/* * Sun Public License * * The contents of this file are subject to the Sun Public License Version * 1.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is available at http://www.sun.com/ * * The Original Code is the SLAMD Distributed Load Generation Engine. * The Initial Developer of the Original Code is Neil A. Wilson. * Portions created by Neil A. Wilson are Copyright (C) 2004-2010. * Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): Neil A. Wilson */ package com.slamd.admin; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.PrintWriter; import java.net.InetAddress; import java.net.URLEncoder; import java.net.UnknownHostException; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.StringTokenizer; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.sun.media.jai.codec.ImageCodec; import com.sun.media.jai.codec.ImageEncoder; import com.sleepycat.je.DatabaseException; import com.slamd.asn1.ASN1Reader; import com.slamd.asn1.ASN1Sequence; import com.slamd.common.Constants; import com.slamd.common.DurationParser; import com.slamd.common.SLAMDException; import com.slamd.db.DecodeException; import com.slamd.db.JobFolder; import com.slamd.job.Job; import com.slamd.job.JobClass; import com.slamd.job.OptimizationAlgorithm; import com.slamd.job.OptimizingJob; import com.slamd.job.SingleStatisticOptimizationAlgorithm; import com.slamd.job.UnknownJobClass; import com.slamd.parameter.BooleanParameter; import com.slamd.parameter.IntegerParameter; import com.slamd.parameter.InvalidValueException; import com.slamd.parameter.LabelParameter; import com.slamd.parameter.MultiChoiceParameter; import com.slamd.parameter.MultiValuedParameter; import com.slamd.parameter.Parameter; import com.slamd.parameter.ParameterList; import com.slamd.parameter.PlaceholderParameter; import com.slamd.resourcemonitor.ResourceMonitor; import com.slamd.server.ClientConnection; import com.slamd.server.RealTimeJobStats; import com.slamd.server.ResourceMonitorClientConnection; import com.slamd.server.SLAMDServerException; import com.slamd.server.UploadedFile; import com.slamd.stat.ResourceMonitorStatTracker; import com.slamd.stat.StatEncoder; import com.slamd.stat.StatGrapher; import com.slamd.stat.StatTracker; import static com.unboundid.util.StaticUtils.secondsToHumanReadableDuration; import static com.slamd.admin.AdminServlet.*; import static com.slamd.admin.AdminUI.*; /** * This class provides a set of methods for providing logic for managing jobs. */ public class AdminJob { /** * Handle all processing related to viewing summary for information for a set * of jobs in a particular category (pending, running, or completed), or for * viewing detailed information about a specific job. * * @param requestInfo The state information for this request. */ static void handleViewJob(RequestInfo requestInfo) { String subsection = requestInfo.subsection; String folderName = null; String jobID = null; String[] jobIDValues = requestInfo.request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if ((jobIDValues != null) && (jobIDValues.length == 1)) { jobID = jobIDValues[0]; } handleViewJob(requestInfo, subsection, folderName, jobID); } /** * Handle all processing related to viewing summary for information for a set * of jobs in the specified category, or for viewing detailed information * about a specific job. * * @param requestInfo The state information for this request. * @param subsection The subsection that specifies which category of jobs * to view. * @param folderName The name of the folder to display. * @param jobID The job ID of the job to display. */ static void handleViewJob(RequestInfo requestInfo, String subsection, String folderName, String jobID) { logMessage(requestInfo, "In handleViewJob()"); // The user must have at least view job permission to access anything in // this section. if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "view job information"); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; if (subsection == null) { subsection = ""; } // Get the current folder name because it may be needed later. if ((folderName == null) || (folderName.length() == 0)) { folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if ((folderName == null) || (folderName.length() == 0)) { folderName = Constants.FOLDER_NAME_UNCLASSIFIED; } } String vFolderName = request.getParameter(Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER); // See if a job ID has been specified. If so, then display that job. if ((jobID != null) && (jobID.length() > 0)) { // The user wants to view a specific job, so retrieve it. Job job = null; try { if (slamdRunning && (! readOnlyMode)) { job = scheduler.getJob(jobID); } else { job = configDB.getJob(jobID); } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">View Job " + jobID + "</SPAN>" + EOL); } catch (Exception e) { infoMessage.append("Error retrieving job " + jobID + ": " + e.getMessage() + "<BR>" + EOL); } if (job == null) { htmlBody.append("<BR><BR>"); htmlBody.append("No information is available for job " + jobID + '.' + EOL); } else { generateViewJobBody(requestInfo, job); } } else { // No specific job was specified, so determine which category to use. String category = null; Job[] jobs = null; if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_VIRTUAL)) { if ((vFolderName == null) || (vFolderName.length() == 0)) { handleViewVirtualFolderList(requestInfo); } else { handleViewVirtualFolder(requestInfo, vFolderName); } return; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_PENDING)) { category = "pending"; htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">View Pending Jobs</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<TABLE BORDER=\"0\" CELLPADDING=\"20\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, subsection) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Refresh\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append("</TABLE>" + EOL); jobs = scheduler.getPendingJobs(); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_RUNNING)) { category = "running"; htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">View Running Jobs</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, subsection) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Refresh\">" + EOL); htmlBody.append("</FORM>" + EOL); jobs = scheduler.getRunningJobs(); } else { category = "completed"; try { jobs = configDB.getCompletedSummaryJobs(folderName); if (jobs == null) { jobs = new Job[0]; infoMessage.append("Unknown folder \"" + folderName + '"'); } if (hideOptimizingIterations) { ArrayList<Job> jobList = new ArrayList<Job>(jobs.length); for (int i=0; i < jobs.length; i++) { if (jobs[i].getOptimizingJobID() == null) { jobList.add(jobs[i]); } } jobs = new Job[jobList.size()]; jobList.toArray(jobs); } } catch (Exception e) { infoMessage.append("Unable to retrieve job information: " + e.getMessage() + "<BR>" + EOL); } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">View Completed Jobs</SPAN>" + EOL); htmlBody.append("<BR>" + EOL); String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING, Constants.SERVLET_PARAM_JOB_FOLDER, folderName, "Switch to optimizing jobs for this folder"); htmlBody.append(link + EOL); htmlBody.append("<BR><BR>" + EOL); if ((folderName == null) || (folderName.length() == 0)) { folderName = Constants.FOLDER_NAME_UNCLASSIFIED; } try { JobFolder folder = null; JobFolder[] folders = configDB.getFolders(); if (folders == null) { folders = new JobFolder[0]; } if ((folders != null) && (folders.length > 0)) { htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, subsection) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" View jobs in folder " + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_FOLDER + "\">" + EOL); for (int i=0; i < folders.length; i++) { String selectedStr = ""; if (folderName.equalsIgnoreCase(folders[i].getFolderName())) { folder = folders[i]; selectedStr = " SELECTED"; } htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + '"' + selectedStr + '>' + folders[i].getFolderName() + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Refresh\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR>" + EOL); if (folder != null) { htmlBody.append("<B>Jobs for Folder " + folder.getFolderName() + "</B>" + EOL); htmlBody.append("<BR>" + EOL); String description = folder.getDescription(); if ((description != null) && (description.length() > 0)) { htmlBody.append("<BLOCKQUOTE>" + description + "</BLOCKQUOTE>" + EOL); } if (requestInfo.mayManageFolders) { htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_FOLDER_DESCRIPTION) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); if (requestInfo.debugHTML) { htmlBody.append( generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"Edit Description\">" + EOL); htmlBody.append("</FORM>" + EOL); } htmlBody.append("<BR>" + EOL); if (requestInfo.mayManageFolders && enableReadOnlyManagement) { if (folder.displayInReadOnlyMode()) { htmlBody.append("This folder is currently visible in " + "restricted read-only mode." + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_FOLDER_PUBLISH) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); if (requestInfo.debugHTML) { htmlBody.append( generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_DEPUBLISH_FOLDER + "\">" + EOL); htmlBody.append("  " + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_DEPUBLISH_FOLDER_JOBS + "\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR>" + EOL); } else { htmlBody.append("This folder is currently not visible in " + "restricted read-only mode." + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_FOLDER_PUBLISH) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); if (requestInfo.debugHTML) { htmlBody.append( generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_PUBLISH_FOLDER + "\">" + EOL); htmlBody.append("  " + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_PUBLISH_FOLDER_JOBS + "\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR>" + EOL); } } } } } catch (DatabaseException de) { infoMessage.append("ERROR: Unable to obtain a list of the job " + "folders defined in the configuration " + "database -- " + de); return; } } if ((jobs == null) || (jobs.length == 0)) { if (category.equals("completed")) { if ((folderName == null) || (folderName.length() == 0)) { folderName = Constants.FOLDER_NAME_UNCLASSIFIED; } htmlBody.append("There are currently no " + category + " jobs in the " + folderName + " folder.<BR><BR>" + EOL); } else { htmlBody.append("There are currently no " + category + " jobs.<BR><BR>" + EOL); } } else { htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIEW_CATEGORY, subsection) + EOL); String jobFolder = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if ((jobFolder != null) && (jobFolder.length() > 0)) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, jobFolder) + EOL); } else { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, Constants.FOLDER_NAME_UNCLASSIFIED) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\" CELLSPACING=\"0\">" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A +"\">" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><B>Job ID</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><B>Description</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><B>Job Type</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); if (category.equals("running") || category.equals("completed")) { htmlBody.append(" <TD><B>Actual Start Time</B></TD>" + EOL); } else { htmlBody.append(" <TD><B>Start Time</B></TD>" + EOL); } if (category.equals("completed")) { htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><B>Actual Duration</B></TD>" + EOL); if (enableReadOnlyManagement && (! readOnlyMode)) { htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><B>Read-Only Status</B></TD>" + EOL); } } htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><B>Current State</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); boolean selectAll = false; boolean deselectAll = false; String submitStr = request.getParameter(Constants.SERVLET_PARAM_SUBMIT); if (submitStr != null) { if (submitStr.equals(Constants.SUBMIT_STRING_SELECT_ALL)) { selectAll = true; } else if (submitStr.equals(Constants.SUBMIT_STRING_DESELECT_ALL)) { deselectAll = true; } } String[] selectedJobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if (selectedJobIDs == null) { selectedJobIDs = new String[0]; } for (int i=0; i < jobs.length; i++) { if (i % 2 == 0) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); } else { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); } String description = (jobs[i].getJobDescription() == null) ? "" : jobs[i].getJobDescription(); String stateStr; switch (jobs[i].getJobState()) { case Constants.JOB_STATE_NOT_YET_STARTED: stateStr = "Pending"; break; case Constants.JOB_STATE_DISABLED: stateStr = "Disabled"; break; case Constants.JOB_STATE_RUNNING: stateStr = "Running"; break; case Constants.JOB_STATE_CANCELLED: case Constants.JOB_STATE_STOPPED_BY_USER: stateStr = "Cancelled"; break; case Constants.JOB_STATE_COMPLETED_SUCCESSFULLY: case Constants.JOB_STATE_COMPLETED_WITH_ERRORS: case Constants.JOB_STATE_STOPPED_DUE_TO_DURATION: case Constants.JOB_STATE_STOPPED_DUE_TO_STOP_TIME: stateStr = "Completed"; break; default: stateStr = "Stopped"; break; } boolean selected = false; if (selectAll) { selected = true; } else if (! deselectAll) { for (int j=0; j < selectedJobIDs.length; j++) { if (selectedJobIDs[j].equals(jobs[i].getJobID())) { selected = true; break; } } } String fParam = null; String fValue = null; if ((vFolderName != null) && (vFolderName.length() > 0)) { fParam = Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER; fValue = vFolderName; } else if ((folderName != null) && (folderName.length() > 0)) { fParam = Constants.SERVLET_PARAM_JOB_FOLDER; fValue = folderName; } String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, jobs[i].getJobID(), fParam, fValue, jobs[i].getJobID()); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_ID + "\" VALUE=\"" + jobs[i].getJobID() + '"' + (selected ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + link + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + description + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + jobs[i].getJobName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); if (category.equals("running") || category.equals("completed")) { Date startTime = jobs[i].getActualStartTime(); if (startTime == null) { startTime = jobs[i].getStartTime(); } htmlBody.append(" <TD>" + displayDateFormat.format(startTime) + "</TD>" + EOL); } else { htmlBody.append(" <TD>" + displayDateFormat.format(jobs[i].getStartTime()) + "</TD>" + EOL); } if (category.equals("completed")) { htmlBody.append(" <TD> </TD>" + EOL); final int actualDuration = jobs[i].getActualDuration(); if (actualDuration < 0) { htmlBody.append(" <TD> </TD>" + EOL); } else { htmlBody.append(" <TD>" + secondsToHumanReadableDuration(actualDuration) + "</TD>" + EOL); } } if (category.equals("completed") && enableReadOnlyManagement && (! readOnlyMode)) { htmlBody.append(" <TD> </TD>" + EOL); if (jobs[i].displayInReadOnlyMode()) { htmlBody.append(" <TD>Published</TD>" + EOL); } else { htmlBody.append(" <TD>Not Published</TD>" + EOL); } } htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + stateStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append(" </TABLE>" + EOL); htmlBody.append(" <BR><BR>" + EOL); ArrayList<String> actions = new ArrayList<String>(); actions.add(Constants.SUBMIT_STRING_SELECT_ALL); actions.add(Constants.SUBMIT_STRING_DESELECT_ALL); if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_PENDING)) { if (requestInfo.mayCancelJob) { actions.add(Constants.SUBMIT_STRING_CANCEL); if (requestInfo.mayDeleteJob) { actions.add(Constants.SUBMIT_STRING_CANCEL_AND_DELETE); } } if (requestInfo.mayScheduleJob) { actions.add(Constants.SUBMIT_STRING_CLONE); actions.add(Constants.SUBMIT_STRING_DISABLE); actions.add(Constants.SUBMIT_STRING_ENABLE); } } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_RUNNING)) { if (requestInfo.mayCancelJob) { actions.add(Constants.SUBMIT_STRING_CANCEL); } if (requestInfo.mayScheduleJob) { actions.add(Constants.SUBMIT_STRING_CLONE); } } else { if (requestInfo.mayScheduleJob) { actions.add(Constants.SUBMIT_STRING_CLONE); } if (requestInfo.mayViewJob && (! disableGraphs)) { actions.add(Constants.SUBMIT_STRING_COMPARE); } if (requestInfo.mayDeleteJob) { actions.add(Constants.SUBMIT_STRING_DELETE); } if (requestInfo.mayExportJobData) { actions.add(Constants.SUBMIT_STRING_EXPORT); } if (requestInfo.mayManageFolders) { actions.add(Constants.SUBMIT_STRING_CREATE_FOLDER); try { JobFolder[] folders = configDB.getFolders(); if ((folders != null) && (folders.length > 0)) { actions.add(Constants.SUBMIT_STRING_DELETE_FOLDER); actions.add(Constants.SUBMIT_STRING_MOVE); } } catch (DatabaseException de) {} } } if (requestInfo.mayManageFolders) { actions.add(Constants.SUBMIT_STRING_ADD_TO_VIRTUAL_FOLDER); } if (requestInfo.mayManageFolders && enableReadOnlyManagement && subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED)) { actions.add(Constants.SUBMIT_STRING_PUBLISH_JOBS); actions.add(Constants.SUBMIT_STRING_DEPUBLISH_JOBS); } if ((reportGenerators != null) && (reportGenerators.length > 0)) { actions.add(Constants.SUBMIT_STRING_GENERATE_REPORT); } htmlBody.append(" <TABLE BORDER=\"0\" WIDTH=\"100%\">" + EOL); htmlBody.append(" <TR>" + EOL); for (int i=0; i < actions.size(); i++) { htmlBody.append(" <TD WIDTH=\"20%\" ALIGN=\"CENTER\"><INPUT " + "TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + actions.get(i) + "\">" + EOL); if (((i % 5) == 4) && ((i+1) < actions.size())) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } if ((actions.size() % 5) != 0) { for (int i=0; i < (5 - (actions.size() % 5)); i++) { htmlBody.append(" <TD> </TD>" + EOL); } } htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } // The remainder of this section deals with file uploads. If the file // upload capability has been disabled, then don't add that content to // the page. Note that it is also only available for completed jobs, so // it should not be displayed for pending or running jobs. if (disableUploads || (! category.equals("completed"))) { return; } htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Uploaded Files</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); UploadedFile[] files = null; try { files = configDB.getUploadedFiles(folderName); } catch (DatabaseException de) { infoMessage.append("Unable to retrieve uploaded file list -- " + de.getMessage() + "<BR>" + EOL); } if ((files == null) || (files.length == 0)) { htmlBody.append("No files have been uploaded into this folder." + EOL); } else { htmlBody.append("The following files have been uploaded:" + EOL); htmlBody.append("<TABLE BORDER=\"1\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><B>File Name</B></TD>" + EOL); htmlBody.append(" <TD><B>File Type</B></TD>" + EOL); htmlBody.append(" <TD><B>File Size (bytes)</B></TD>" + EOL); htmlBody.append(" <TD><B>Description</B></TD>" + EOL); htmlBody.append(" <TD><B>Action</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); for (int i=0; i < files.length; i++) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + files[i].getFileName() + "</TD>" + EOL); htmlBody.append(" <TD>" + files[i].getFileType() + "</TD>" + EOL); htmlBody.append(" <TD>" + files[i].getFileSize() + "</TD>" + EOL); String desc = files[i].getFileDescription(); if ((desc == null) || (desc.length() == 0)) { desc = " "; } htmlBody.append(" <TD>" + desc + "</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\" TARGET=\"_BLANK\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_UPLOAD) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_ACTION, Constants.FILE_ACTION_VIEW) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_NAME, files[i].getFileName()) +EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"View\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_UPLOAD) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_ACTION, Constants.FILE_ACTION_SAVE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_NAME, files[i].getFileName()) +EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"Save\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); if (requestInfo.mayManageFolders) { htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_UPLOAD) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_FILE_ACTION, Constants.FILE_ACTION_EDIT_TYPE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_NAME, files[i].getFileName()) +EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"Edit MIME Type\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_UPLOAD) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_FILE_ACTION, Constants.FILE_ACTION_DELETE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_NAME, files[i].getFileName()) +EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"Delete\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); } htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append("</TABLE>" + EOL); } if (requestInfo.mayManageFolders) { htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_UPLOAD) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_ACTION, Constants.FILE_ACTION_UPLOAD) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Upload File\">" + EOL); htmlBody.append("</FORM>" + EOL); } } } /** * Handles the work of retrieving information about the specified job as a * plain text document. * * @param requestInfo The state information for this request. */ static void handleViewJobAsText(RequestInfo requestInfo) { logMessage(requestInfo, "In handleViewJobAsText()"); // The user must have permission to view job information in order to see // this section. if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "view job information"); return; } // Get the important state information for the request. HttpServletRequest request = requestInfo.request; HttpServletResponse response = requestInfo.response; // Prepare to send the entire response to the client. PrintWriter writer; try { writer = response.getWriter(); response.setContentType("text/plain"); requestInfo.generateHTML = false; } catch (IOException ioe) { // What can we do here? ioe.printStackTrace(); return; } boolean onlyState = false; String stateStr = request.getParameter(Constants.SERVLET_PARAM_ONLY_STATE); if (stateStr != null) { onlyState = (stateStr.equalsIgnoreCase("true") || stateStr.equalsIgnoreCase("yes") || stateStr.equalsIgnoreCase("on") || stateStr.equalsIgnoreCase("1")); } // Get the job ID of the job to retrieve. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { writer.println("ERROR: No job ID specified in the request."); return; } // Get the job for the requested job ID. Job job; try { job = configDB.getJob(jobID); if (job == null) { if (onlyState) { writer.println(Constants.JOB_STATE_NO_SUCH_JOB); } else { writer.println("ERROR: Could not retrieve job \"" + jobID + '"'); } return; } } catch (Exception e) { if (onlyState) { writer.println(Constants.JOB_STATE_NO_SUCH_JOB); } else { writer.println("ERROR: Could not retrieve job \"" + jobID + '"'); } return; } // Determine whether we should only return the job state. if (onlyState) { writer.println(job.getJobState()); return; } // Determine whether the resulting information should include detailed // statistics. boolean viewDetailedStats = false; String detailStr = request.getParameter(Constants.SERVLET_PARAM_JOB_VIEW_DETAILED_STATS); if (detailStr != null) { viewDetailedStats = (detailStr.equalsIgnoreCase("true") || detailStr.equalsIgnoreCase("yes") || detailStr.equalsIgnoreCase("on") || detailStr.equalsIgnoreCase("1")); } writer.println(job.getJobClass().getJobName() + " Job " + job.getJobID()); writer.println("Job ID: " + job.getJobID()); String description = job.getJobDescription(); if ((description != null) && (description.length() > 0)) { writer.println("Job Description: " + description); } String optimizingJobID = job.getOptimizingJobID(); if ((optimizingJobID != null) && (optimizingJobID.length() > 0)) { writer.println("Optimizing Job ID: " + optimizingJobID); } writer.println("Job Type: " + job.getJobClass().getJobName()); writer.println("Job Class: " + job.getJobClassName()); writer.println("Job State: " + job.getJobState() + " (" + Constants.jobStateToString(job.getJobState()) + ')'); writer.println("----- Job Schedule Information -----"); Date scheduledStartTime = job.getStartTime(); String startTimeStr; if (scheduledStartTime == null) { startTimeStr = "(Not Available)"; } else { startTimeStr = dateFormat.format(scheduledStartTime); } writer.println("Scheduled Start Time: " + startTimeStr); Date scheduledStopTime = job.getStopTime(); String stopTimeStr; if (scheduledStopTime == null) { stopTimeStr = "(Not Specified)"; } else { stopTimeStr = dateFormat.format(scheduledStopTime); } writer.println("Scheduled Stop Time: " + stopTimeStr); int scheduledDuration = job.getDuration(); String durationStr; if (scheduledDuration > 0) { durationStr = secondsToHumanReadableDuration(scheduledDuration); } else { durationStr = "(Not Specified)"; } writer.println("Scheduled Duration: " + durationStr); int numClients = job.getNumberOfClients(); writer.println("Number of Clients: " + numClients); String[] requestedClients = job.getRequestedClients(); if ((requestedClients != null) && (requestedClients.length > 0)) { writer.print("Requested Clients: " + requestedClients[0]); for (int i=1; i < requestedClients.length; i++) { writer.println(","); writer.print(" " + requestedClients[i]); } writer.println(); } int numThreads = job.getThreadsPerClient(); writer.println("Number of Threads per Client: " + numThreads); int startupDelay = job.getThreadStartupDelay(); writer.println("Thread Startup Delay: " + startupDelay); int collectionInterval = job.getCollectionInterval(); writer.println("Statistics Collection Interval: " + secondsToHumanReadableDuration(collectionInterval)); // Write information to the buffer about the job-specific configuration. writer.println("----- Job-Specific Configuration -----"); Parameter[] params = job.getParameterList().getParameters(); for (int i=0; i < params.length; i++) { writer.println(params[i].getDisplayName() + ": " + params[i].getDisplayValue()); } // Write information to the buffer about the job statistics. if (job.hasStats()) { writer.println("----- General Statistical Information -----"); Date actualStartTime = job.getActualStartTime(); if (actualStartTime == null) { startTimeStr = "(Not Available)"; } else { startTimeStr = dateFormat.format(actualStartTime); } writer.println("Actual Start Time: " + startTimeStr); Date actualStopTime = job.getActualStopTime(); if (actualStopTime == null) { stopTimeStr = "(Not Available)"; } else { stopTimeStr = dateFormat.format(actualStopTime); } writer.println("Actual Stop Time: " + stopTimeStr); int actualDuration = job.getActualDuration(); if (actualDuration > 0) { durationStr = secondsToHumanReadableDuration(actualDuration); } else { durationStr = "(Not Available)"; } writer.println("Actual Duration: " + durationStr); String[] clients = job.getStatTrackerClientIDs(); if ((clients != null) && (clients.length > 0)) { writer.print("Clients Used: " + clients[0]); for (int i=1; i < clients.length; i++) { writer.println(","); writer.print(" " + clients[i]); } writer.println(); } String[] statNames = job.getStatTrackerNames(); for (int i=0; i < statNames.length; i++) { StatTracker[] trackers = job.getStatTrackers(statNames[i]); if ((trackers == null) || (trackers.length == 0)) { continue; } StatTracker tracker = trackers[0].newInstance(); tracker.aggregate(trackers); writer.println("----- " + statNames[i] + " Statistics -----"); if (viewDetailedStats) { writer.println(tracker.getDetailString()); } else { writer.println(tracker.getSummaryString()); } } } // Write information to the buffer about the resource monitor statistics. if (job.hasResourceStats()) { writer.println("----- Resource Monitor Statistics -----"); String[] statNames = job.getResourceStatTrackerNames(); for (int i=0; i < statNames.length; i++) { StatTracker[] trackers = job.getResourceStatTrackers(statNames[i]); if ((trackers == null) || (trackers.length == 0)) { continue; } StatTracker tracker = trackers[0].newInstance(); tracker.aggregate(trackers); writer.println("----- " + statNames[i] + " Resource Monitor Statistics -----"); if (viewDetailedStats) { writer.println(tracker.getDetailString()); } else { writer.println(tracker.getSummaryString()); } } } } /** * Handles the work of retrieving information about the specified optimizing * job as a plain text document. * * @param requestInfo The state information for this request. */ static void handleViewOptimizingJobAsText(RequestInfo requestInfo) { logMessage(requestInfo, "In handleViewOptimizingJobAsText()"); // The user must have permission to view job information in order to see // this section. if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "view job information"); return; } // Get the important state information for the request. HttpServletRequest request = requestInfo.request; HttpServletResponse response = requestInfo.response; // Prepare to send the entire response to the client. PrintWriter writer; try { writer = response.getWriter(); response.setContentType("text/plain"); requestInfo.generateHTML = false; } catch (IOException ioe) { // What can we do here? ioe.printStackTrace(); return; } boolean onlyState = false; String stateStr = request.getParameter(Constants.SERVLET_PARAM_ONLY_STATE); if (stateStr != null) { onlyState = (stateStr.equalsIgnoreCase("true") || stateStr.equalsIgnoreCase("yes") || stateStr.equalsIgnoreCase("on") || stateStr.equalsIgnoreCase("1")); } // Get the ID of the optimizing job to retrieve. String optimizingJobID = request.getParameter(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID); if ((optimizingJobID == null) || (optimizingJobID.length() == 0)) { writer.println("ERROR: No optimizing job ID specified in the request."); return; } // Get the optimizing job with the requested ID. OptimizingJob optimizingJob; try { optimizingJob = getOptimizingJob(optimizingJobID); if (optimizingJob == null) { if (onlyState) { writer.println(Constants.JOB_STATE_NO_SUCH_JOB); } else { writer.println("ERROR: Could not retrieve optimizing job \"" + optimizingJobID + '"'); } return; } } catch (Exception e) { if (onlyState) { writer.println(Constants.JOB_STATE_NO_SUCH_JOB); } else { writer.println("ERROR: Could not retrieve optimizing job \"" + optimizingJobID + '"'); } return; } // Determine whether we should only return the job state. if (onlyState) { writer.println(optimizingJob.getJobState()); return; } // Write information to the buffer that will always be included. writer.println("Optimizing " + optimizingJob.getJobClass().getJobName() + " Job " + optimizingJob.getOptimizingJobID()); writer.println("Optimizing Job ID: " + optimizingJob.getOptimizingJobID()); String description = optimizingJob.getDescription(); if ((description != null) && (description.length() > 0)) { writer.println("Job Description: " + description); } writer.println("Job Type: " + optimizingJob.getJobClass().getJobName()); writer.println("Job Class: " + optimizingJob.getJobClassName()); writer.println("Job State: " + Constants.jobStateToString(optimizingJob.getJobState())); // Write information to the buffer about the schedule configuration. writer.println("----- Job Schedule Information -----"); Date scheduledStartTime = optimizingJob.getStartTime(); String startTimeStr; if (scheduledStartTime == null) { startTimeStr = "(Not Available)"; } else { startTimeStr = dateFormat.format(scheduledStartTime); } writer.println("Scheduled Start Time: " + startTimeStr); int scheduledDuration = optimizingJob.getDuration(); String durationStr; if (scheduledDuration > 0) { durationStr = secondsToHumanReadableDuration(scheduledDuration); } else { durationStr = "(Not Specified)"; } writer.println("Scheduled Duration: " + durationStr); int numClients = optimizingJob.getNumClients(); writer.println("Number of Clients: " + numClients); String[] requestedClients = optimizingJob.getRequestedClients(); if ((requestedClients != null) && (requestedClients.length > 0)) { writer.print("Requested Clients: " + requestedClients[0]); for (int i=1; i < requestedClients.length; i++) { writer.println(","); writer.print(" " + requestedClients[i]); } writer.println(); } int minThreads = optimizingJob.getMinThreads(); writer.println("Minimum Number of Threads: " + minThreads); int maxThreads = optimizingJob.getMaxThreads(); String maxStr; if (maxThreads > 0) { maxStr = String.valueOf(maxThreads); } else { maxStr = "(Not Specified)"; } writer.println("Maximum Number of Threads: " + maxStr); int threadIncrement = optimizingJob.getThreadIncrement(); writer.println("Thread Increment Between Iterations: " + threadIncrement); int collectionInterval = optimizingJob.getCollectionInterval(); writer.println("Statistics Collection Interval: " + secondsToHumanReadableDuration(collectionInterval)); OptimizationAlgorithm optimizationAlgorithm = optimizingJob.getOptimizationAlgorithm(); Parameter[] params = optimizationAlgorithm.getOptimizationAlgorithmParameters(). getParameters(); for (int i=0; i < params.length; i++) { writer.println(params[i].getDisplayName() + ": " + params[i].getDisplayValue()); } int maxNonImproving = optimizingJob.getMaxNonImproving(); writer.println("Max. Consecutive Non-Improving Iterations: " + maxNonImproving); boolean reRun = optimizingJob.reRunBestIteration(); writer.println("Re-Run Best Iteration: " + String.valueOf(reRun)); int reRunDuration = optimizingJob.getReRunDuration(); if (reRunDuration > 0) { durationStr = secondsToHumanReadableDuration(reRunDuration); } else { durationStr = "(Not Specified)"; } writer.println("Re-Run Duration: " + durationStr); // Write information to the buffer about the job-specific configuration. writer.println("----- Job-Specific Configuration -----"); params = optimizingJob.getParameters().getParameters(); for (int i=0; i < params.length; i++) { writer.println(params[i].getDisplayName() + ": " + params[i].getDisplayValue()); } // Write information to the buffer about the job statistics. if (optimizingJob.hasStats()) { writer.println("----- General Statistical Information -----"); Date actualStartTime = optimizingJob.getActualStartTime(); if (actualStartTime == null) { startTimeStr = "(Not Available)"; } else { startTimeStr = dateFormat.format(actualStartTime); } writer.println("Actual Start Time: " + startTimeStr); Date actualStopTime = optimizingJob.getActualStopTime(); String stopTimeStr; if (actualStopTime == null) { stopTimeStr = "(Not Available)"; } else { stopTimeStr = dateFormat.format(actualStopTime); } writer.println("Actual Stop Time: " + stopTimeStr); Job[] iterations = optimizingJob.getAssociatedJobs(); if ((iterations != null) && (iterations.length > 0)) { writer.println("Job Iterations Completed: " + iterations.length); int optimalThreads = optimizingJob.getOptimalThreadCount(); writer.println("Optimal Thread Count: " + optimalThreads); double optimalValue = optimizingJob.getOptimalValue(); writer.println("Optimal Value: " + decimalFormat.format(optimalValue)); Job reRunIteration = optimizingJob.getReRunIteration(); if (reRunIteration != null) { String valueStr; try { double value = optimizationAlgorithm.getIterationOptimizationValue( reRunIteration); valueStr = decimalFormat.format(value); } catch (Exception e) { valueStr = "N/A"; } writer.println("Re-Run Value: " + valueStr); } writer.println("----- Optimizing Job Iterations -----"); for (int i=0; i < iterations.length; i++) { String valueStr; try { double value = optimizationAlgorithm.getIterationOptimizationValue( iterations[i]); valueStr = decimalFormat.format(value); } catch (Exception e) { valueStr = "N/A"; } writer.println(iterations[i].getJobID() + ": " + valueStr); } } } } /** * Generate the HTML code that can be used to display detailed information * about a particular job. * * @param requestInfo The state information for this request. * @param job The job whose information is to be displayed. */ static void generateViewJobBody(RequestInfo requestInfo, Job job) { logMessage(requestInfo, "In generateViewJobBody(" + job.getJobID() + ')'); HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; int buttonsAdded = 0; boolean isUnknownJob = (job.getJobClass() instanceof UnknownJobClass); htmlBody.append("<TABLE BORDER=\"0\" WIDTH=\"100%\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Refresh\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } if (requestInfo.mayScheduleJob) { if ((job.getJobState() == Constants.JOB_STATE_NOT_YET_STARTED) || (job.getJobState() == Constants.JOB_STATE_DISABLED)) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_EDIT) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Edit\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } if (job.getJobState() == Constants.JOB_STATE_NOT_YET_STARTED) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_DISABLE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Disable\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } else { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_ENABLE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Enable\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } } else { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_EDIT_COMMENTS) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Edit Comments\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } if (! isUnknownJob) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_CLONE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Clone\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } } if (job.doneRunning()) { if (requestInfo.mayScheduleJob) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + '"' + blankTarget + '>' + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_IMPORT_PERSISTENT) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"Import Persistent Stats\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } if ((! disableGraphs) && (job.graphsAvailable())) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + '"' + blankTarget + '>' + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_VIEW_GRAPH) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Graph\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } if (requestInfo.mayDeleteJob) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_DELETE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Delete\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } if (requestInfo.mayManageFolders) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_MOVE + "\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_ADD_TO_VIRTUAL_FOLDER + "\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } StatTracker[] stubs = job.getJobClass().getStatTrackerStubs("", "", 1); if (requestInfo.mayScheduleJob && (! isUnknownJob) && (stubs != null) && (stubs.length > 0)) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_OPTIMIZE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"Optimize Results\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } } else { if ((job.getJobState() == Constants.JOB_STATE_RUNNING) && job.hasRealTimeStats() && (! disableGraphs)) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + '"' + blankTarget + '>' + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_VIEW_GRAPH_REAL_TIME) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"In-Progress Results\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } if (requestInfo.mayCancelJob) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_CANCEL) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Cancel\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } if (requestInfo.mayDeleteJob && scheduler.isJobPending(job.getJobID()) && (job.getOptimizingJobID() == null)) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_CANCEL_AND_DELETE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Cancel and " + "Delete\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } } } if ((reportGenerators != null) && (reportGenerators.length > 0)) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_GENERATE_REPORT) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Generate Report\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; } while ((buttonsAdded % 5) != 0) { htmlBody.append(" <TD> </TD>" + EOL); buttonsAdded++; } htmlBody.append(" </TR>" + EOL); htmlBody.append("</TABLE>" + EOL); // See if a real or virtual folder name has been specified as a parameter. // If so, then provide a link to return to that folder. Start with the // virtual folder first. String folderName = request.getParameter(Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER); if ((folderName != null) && (folderName.length() > 0)) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_VIRTUAL, Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER, folderName, folderName); htmlBody.append("Return to virtual job folder " + link + '.' + EOL); } else { // No virtual folder, so try a real folder. folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if ((folderName == null) || (folderName.length() == 0)) { folderName = job.getFolderName(); } if ((folderName != null) && (folderName.length() > 0)) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, Constants.SERVLET_PARAM_JOB_FOLDER, folderName, folderName); htmlBody.append("Return to job folder " + link + '.' + EOL); } else { // No real folder, so display either the completed, running, or pending // jobs. if (job.doneRunning()) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, "completed jobs"); htmlBody.append("Return to the " + link + " page." + EOL); } else if (job.getJobState() == Constants.JOB_STATE_RUNNING) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_RUNNING, "running jobs"); htmlBody.append("Return to the " + link + " page." + EOL); } else { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_PENDING, "pending jobs"); htmlBody.append("Return to the " + link + " page." + EOL); } } } htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<TABLE BORDER=\"0\" CELLSPACING=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>General " + "Information</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job ID htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Job ID</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + job.getJobID() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The optimizing job ID String optimizingJobID = job.getOptimizingJobID(); if (optimizingJobID == null) { optimizingJobID = "(none specified)"; } else { optimizingJobID = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING, Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID, optimizingJobID); } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Optimizing Job ID</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimizingJobID + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job group name String jobGroupName = job.getJobGroup(); if (jobGroupName == null) { jobGroupName = "(none specified)"; } else { jobGroupName = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GROUP, Constants.SERVLET_PARAM_JOB_GROUP_NAME, jobGroupName, jobGroupName); } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Job Group</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + jobGroupName + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job description String descriptionStr = job.getJobDescription(); if (descriptionStr == null) { descriptionStr = "(not specified)"; } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Job Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + descriptionStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job type htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Job Type</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + job.getJobName() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job class htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Job Class</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); if (requestInfo.mayViewJobClass) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_CLASSES, Constants.SERVLET_PARAM_JOB_CLASS, job.getJobClassName(), job.getJobClassName()); htmlBody.append(" <TD>" + link + "</TD>" + EOL); } else { htmlBody.append(" <TD>" + job.getJobClassName() + "</TD>" + EOL); } htmlBody.append(" </TR>" + EOL); // The current job state htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Current State</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + job.getJobStateString() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // If the job is currently pending, try to figure out why it hasn't started // running. if ((scheduler != null) && scheduler.isJobPending(job.getJobID())) { String pendingReason = scheduler.getPendingReason(job.getJobID()); if (pendingReason != null) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Pending Reason</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + pendingReason + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } // If the job is running, try to figure out what clients it is using and // how long it might have left. if (job.getJobState() == Constants.JOB_STATE_RUNNING) { int styleValue = 0; ArrayList clientList = job.getActiveClients(); if ((clientList != null) && (! clientList.isEmpty())) { String style = ((styleValue++ % 2) == 0) ? Constants.STYLE_JOB_SUMMARY_LINE_A : Constants.STYLE_JOB_SUMMARY_LINE_B; htmlBody.append(" <TR CLASS=\"" + style + "\">" + EOL); htmlBody.append(" <TD>Active Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); for (int i=0; i < clientList.size(); i++) { ClientConnection conn = (ClientConnection) clientList.get(i); htmlBody.append(" " + conn.getClientID() + "<BR>" + EOL); } htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } ArrayList monitorClientList = job.getActiveMonitorClients(); if ((monitorClientList != null) && (! monitorClientList.isEmpty())) { String style = ((styleValue++ % 2) == 0) ? Constants.STYLE_JOB_SUMMARY_LINE_A : Constants.STYLE_JOB_SUMMARY_LINE_B; htmlBody.append(" <TR CLASS=\"" + style + "\">" + EOL); htmlBody.append(" <TD>Active Monitor Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); for (int i=0; i < monitorClientList.size(); i++) { ResourceMonitorClientConnection conn = (ResourceMonitorClientConnection) monitorClientList.get(i); htmlBody.append(" " + conn.getClientID() + "<BR>" + EOL); } htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } Date startDate = job.getActualStartTime(); if (startDate != null) { long startTime = startDate.getTime(); long shouldStopTime = -1; if (job.getDuration() > 0) { shouldStopTime = startTime + (job.getDuration() * 1000); } Date stopDate = job.getStopTime(); if (stopDate != null) { long tmpShouldStopTime = stopDate.getTime(); if ((shouldStopTime > 0) && (tmpShouldStopTime < shouldStopTime)) { shouldStopTime = tmpShouldStopTime; } } if (shouldStopTime > 0) { Date shouldStopDate = new Date(shouldStopTime); String stopTimeStr = displayDateFormat.format(shouldStopDate); String style = ((styleValue++ % 2) == 0) ? Constants.STYLE_JOB_SUMMARY_LINE_A : Constants.STYLE_JOB_SUMMARY_LINE_B; htmlBody.append(" <TR CLASS=\"" + style + "\">" + EOL); htmlBody.append(" <TD>Estimated Completion Time</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + stopTimeStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); long timeLeft = shouldStopTime - System.currentTimeMillis(); if (timeLeft > 0) { timeLeft /= 1000; String remainingStr = ""; long numDays = timeLeft / 86400; if (numDays > 0) { timeLeft %= 86400; remainingStr += numDays + " day(s) "; } long numHours = timeLeft / 3600; if ((remainingStr.length() > 0) || (numHours > 0)) { timeLeft %= 3600; remainingStr += numHours + " hour(s) "; } long numMinutes = timeLeft / 60; if ((remainingStr.length() > 0) || (numMinutes > 0)) { timeLeft %= 60; remainingStr += numMinutes + " minute(s) "; } remainingStr += timeLeft + " second(s)"; style = ((styleValue++ % 2) == 0) ? Constants.STYLE_JOB_SUMMARY_LINE_A : Constants.STYLE_JOB_SUMMARY_LINE_B; htmlBody.append(" <TR CLASS=\"" + style + "\">" + EOL); htmlBody.append(" <TD>Estimated Time Remaining</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + remainingStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } } } // Job execution data if (job.doneRunning()) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>Job Execution " + "Data</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The actual start time Date actualStartTime = job.getActualStartTime(); String actualStartTimeStr = "(not available)"; if (actualStartTime != null) { actualStartTimeStr = displayDateFormat.format(actualStartTime); } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Actual Start Time</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + actualStartTimeStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The actual stop time Date actualStopTime = job.getActualStopTime(); String actualStopTimeStr = "(not available)"; if (actualStopTime != null) { actualStopTimeStr = displayDateFormat.format(actualStopTime); } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Actual Stop Time</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + actualStopTimeStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The actual duration int actualDuration = job.getActualDuration(); String actualDurationStr; if (actualDuration > 0) { actualDurationStr = secondsToHumanReadableDuration(actualDuration); } else { actualDurationStr = "(not available)"; } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Actual Duration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + actualDurationStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); if (job.hasStats()) { // The stat trackers String[] trackerNames = job.getStatTrackerNames(); for (int i=0; i < trackerNames.length; i++) { StatTracker[] statTrackers = job.getStatTrackers(trackerNames[i]); if (statTrackers.length > 0) { String valueStr = "(no data available)"; try { StatTracker tracker = statTrackers[0].newInstance(); tracker.aggregate(statTrackers); valueStr = tracker.getSummaryHTML(); } catch (Exception e) { e.printStackTrace(); infoMessage.append("ERROR creating aggregate tracker " + trackerNames[i] + ": " + e + "<BR>" + EOL); } if (i % 2 == 1) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); } else { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); } htmlBody.append(" <TD>" + trackerNames[i] + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + valueStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } else { if (i % 2 == 1) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); } else { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); } htmlBody.append(" <TD>" + trackerNames[i] + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>(no data available)</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } } if (job.hasResourceStats()) { // The stat trackers String[] trackerNames = job.getResourceStatTrackerNames(); for (int i=0; i < trackerNames.length; i++) { StatTracker[] statTrackers = job.getResourceStatTrackers(trackerNames[i]); if (statTrackers.length > 0) { String valueStr = "(no data available)"; try { StatTracker tracker = statTrackers[0].newInstance(); tracker.aggregate(statTrackers); valueStr = tracker.getSummaryHTML(); } catch (Exception e) { e.printStackTrace(); infoMessage.append("ERROR creating aggregate tracker " + trackerNames[i] + ": " + e + "<BR>" + EOL); } if (i % 2 == 1) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); } else { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); } htmlBody.append(" <TD>" + trackerNames[i] + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + valueStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } else { if (i % 2 == 1) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); } else { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); } htmlBody.append(" <TD>" + trackerNames[i] + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>(no data available)</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } } if (job.hasStats() || job.hasResourceStats()) { ArrayList<String> subsectionList = new ArrayList<String>(); ArrayList<String> nameList = new ArrayList<String>(); ArrayList<String> targetList = new ArrayList<String>(); subsectionList.add(Constants.SERVLET_SECTION_JOB_VIEW_STATS); nameList.add("Detailed Statistics"); targetList.add(" TARGET=\"_BLANK\""); if ((! disableGraphs) && job.graphsAvailable()) { subsectionList.add(Constants.SERVLET_SECTION_JOB_VIEW_GRAPH); nameList.add("Graph Statistics"); targetList.add(blankTarget); subsectionList.add(Constants.SERVLET_SECTION_JOB_VIEW_OVERLAY); nameList.add("Graph Overlaid Statistics"); targetList.add(blankTarget); } if ((! disableGraphs) && (job.resourceGraphsAvailable())) { subsectionList.add( Constants.SERVLET_SECTION_JOB_VIEW_MONITOR_GRAPH); nameList.add("Graph Resource Statistics"); targetList.add(blankTarget); } subsectionList.add(Constants.SERVLET_SECTION_JOB_SAVE_STATS); nameList.add("Save Statistics"); targetList.add(" TARGET=\"_BLANK\""); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\">" + EOL); htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); for (int i=0; i < subsectionList.size(); i++) { String subsec = subsectionList.get(i); String subsecName = nameList.get(i); String target = targetList.get(i); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + '"' + target + '>' + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, subsec) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, job.getJobID()) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"" + subsecName + "\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); } htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>"); } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>Schedule " + "Information</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The scheduled start time Date startTime = job.getStartTime(); String startTimeStr = "(not specified)"; if (startTime != null) { startTimeStr = displayDateFormat.format(startTime); } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Scheduled Start Time</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + startTimeStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The scheduled stop time Date stopTime = job.getStopTime(); String stopTimeStr = "(not specified)"; if (stopTime != null) { stopTimeStr = displayDateFormat.format(stopTime); } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Scheduled Stop Time</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + stopTimeStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The scheduled duration String durationStr = (job.getDuration() > 0) ? secondsToHumanReadableDuration(job.getDuration()) : "(not specified)"; htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Scheduled Duration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + durationStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of clients htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Number of Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + job.getNumberOfClients() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The indication of whether to wait for clients htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Wait for Available Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + (job.waitForClients() ? "true" : "false") + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); if (! (readOnlyMode && hideSensitiveInformation)) { // The set of clients to use String[] requestedClients = job.getRequestedClients(); if ((requestedClients != null) && (requestedClients.length > 0)) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Requested Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); String separator = ""; for (int i=0; i < requestedClients.length; i++) { htmlBody.append(separator); htmlBody.append(requestedClients[i]); separator = "<BR>" + EOL; } htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The set of resource monitor clients to use String[] monitorClients = job.getResourceMonitorClients(); if ((monitorClients != null) && (monitorClients.length > 0)) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Resource Monitor Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); String separator = ""; for (int i=0; i < monitorClients.length; i++) { htmlBody.append(separator); htmlBody.append(monitorClients[i]); separator = "<BR>" + EOL; } htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } // The indication of whether to automatically monitor client systems htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Monitor Clients if Available</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + (job.monitorClientsIfAvailable() ? "true" : "false") + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of threads per client htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Threads per Client</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + job.getThreadsPerClient() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The thread startup delay htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Thread Startup Delay</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + job.getThreadStartupDelay() + " milliseconds</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The collection interval htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Statistics Collection Interval</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + secondsToHumanReadableDuration(job.getCollectionInterval()) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The set of scheduled job dependencies. String[] dependencies = job.getDependencies(); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Job Dependencies</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); if ((dependencies == null) || (dependencies.length == 0)) { htmlBody.append(" (none specified)<BR>" + EOL); } else { for (int i=0; i < dependencies.length; i++) { if ((dependencies[i] == null) || (dependencies[i].length() == 0)) { // If somehow we have an empty dependency, then skip it. continue; } // Try to determine whether this dependency is for a normal or an // optimizing job. Job j = null; String dependencyStr = dependencies[i]; try { j = configDB.getJob(dependencies[i]); if (j != null) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, dependencies[i], dependencies[i]); String description = j.getJobDescription(); if (description == null) { description = ""; } else { description = " -- " + description; } dependencyStr = link + " -- " + j.getJobName() + description; } } catch (Exception e) {} if (j == null) { try { OptimizingJob oj = getOptimizingJob(dependencies[i]); if (oj != null) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING, Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, dependencies[i], dependencies[i]); String description = oj.getDescription(); if (description == null) { description = ""; } else { description = " -- " + description; } dependencyStr = link + " -- Optimizing " + oj.getJobClass().getJobName() + description; } } catch (Exception e) {} } htmlBody.append(" " + dependencyStr + "<BR>" + EOL); } } htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); if (! (readOnlyMode && hideSensitiveInformation)) { // The set of addresses to notify when the job has completed. htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Notify on Completion</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); String[] notifyAddresses = job.getNotifyAddresses(); if ((notifyAddresses == null) || (notifyAddresses.length == 0)) { htmlBody.append(" <TD>(none specified)</TD>" + EOL); } else { htmlBody.append(" <TD><A HREF=\"mailto:" + notifyAddresses[0] + "\">" + notifyAddresses[0] + "</A>"); for (int i=1; i < notifyAddresses.length; i++) { htmlBody.append(", <A HREF=\"mailto:" + notifyAddresses[i] + "\">" + notifyAddresses[i] + "</A>"); } htmlBody.append("</TD>" + EOL); } htmlBody.append(" </TR>" + EOL); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>Parameter " + "Information</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Parameter information Parameter[] params = job.getParameterStubs().clone().getParameters(); if ((params != null) && (params.length > 0)) { for (int i=0, j=0; i < params.length; i++,j++) { Parameter p = job.getParameterList().getParameter(params[i].getName()); if (readOnlyMode && hideSensitiveInformation && p.isSensitive()) { continue; } String valueStr = "(not specified)"; if (p != null) { valueStr = p.getHTMLDisplayValue(); } else if ((params[i] instanceof PlaceholderParameter) || (params[i] instanceof LabelParameter)) { j--; continue; } if (j % 2 == 1) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); } else { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); } htmlBody.append(" <TD>" + params[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + valueStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } else { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\">No parameters defined or " + "parameter information is not available</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // Comments about the job String comments = job.getJobComments(); if ((comments != null) && (comments.length() > 0)) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>Job Comments</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\">" + comments + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } if (job.doneRunning()) { if (! (readOnlyMode && hideSensitiveInformation)) { // The list of clients used. String[] clientIDs = job.getStatTrackerClientIDs(); if ((clientIDs != null) && (clientIDs.length > 0)) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>Clients Used</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\">" + EOL); htmlBody.append(" <TABLE BORDER=\"0\" CELLSPACING=\"0\">" + EOL); for (int i=0; i < clientIDs.length; i++) { if (i % 2 == 1) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); } else { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); } htmlBody.append(" <TD>" + clientIDs[i] + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append(" </TABLE>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } // The log messages String[] logMessages = job.getLogMessages(); if ((logMessages != null) && (logMessages.length > 0)) { String splitReason = null; boolean split = (logMessages.length > 20); if (split) { splitReason = "There were more than 20 messages logged."; } else { for (int i=0; ((! split) && (i < logMessages.length)); i++) { split = logMessages[i].length() > 100; splitReason = "One or messages are too wide to be displayed here."; } } if (split) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>Messages Logged</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\">" + EOL); String link = generateNewWindowLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_LOG_MESSAGES, Constants.SERVLET_PARAM_JOB_ID, job.getJobID(), "here"); htmlBody.append(" " + splitReason + EOL); htmlBody.append(" Click " + link + " to view the full set of " + "log messages for this job in a separate window." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } else { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>Messages Logged</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\">" + EOL); htmlBody.append(" <TABLE BORDER=\"0\" CELLSPACING=\"0\">" + EOL); htmlBody.append(" <PRE>"); for (int i=0; i < logMessages.length; i++) { if (i > 0) { htmlBody.append(EOL); } htmlBody.append(logMessages[i]); } htmlBody.append("</PRE>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } } htmlBody.append("</TABLE>" + EOL); } /** * Handles the work of viewing the full set of log messages associated with a * given job. * * @param requestInfo The state information for this request. */ static void handleViewJobLogMessages(RequestInfo requestInfo) { logMessage(requestInfo, "In handleViewJobLogMessages()"); // The user must have at least view job permission to access anything in // this section. if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "view job information"); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; StringBuilder htmlBody = requestInfo.htmlBody; // Get the job ID of the requested job. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">View Job Log Messages</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("No job ID was provided to indicate the job for which " + "to view the log messages."); return; } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">View Log Messages for Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); } // Get the job from the job cache. Job job; try { job = configDB.getJob(jobID); if (job == null) { htmlBody.append("ERROR: Job " + jobID + " could not be found." + EOL); return; } } catch (Exception e) { htmlBody.append("ERROR: Unable to retrieve job from the job cache: " + e + EOL); return; } // Get the log messages for the specified job. String[] logMessages = job.getLogMessages(); if ((logMessages == null) || (logMessages.length == 0)) { htmlBody.append("Job " + jobID + " does not have any log messages." + EOL); } else { htmlBody.append("The following messages were logged for job " + jobID + ':' + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<PRE>"); for (int i=0; i < logMessages.length; i++) { htmlBody.append(logMessages[i] + EOL); } htmlBody.append("</PRE>" + EOL); } } /** * Handles all processing related to viewing detailed statistical information * about a job. * * @param requestInfo The state information for this request. */ static void handleViewJobStatistics(RequestInfo requestInfo) { logMessage(requestInfo, "In handleViewJobStatistics()"); // Get the important state information for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // The user must be able to view job information to do anything here if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "view job information"); return; } // Get the job ID. If there is no job ID, then just display an error. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">View Job Statistics</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("No job was specified for which to view statistical " + "information." + EOL); String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, "here"); htmlBody.append("Click " + link + " to view the set of completed " + "jobs" + EOL); return; } // Get the job with the specified job ID. Job job = null; try { job = configDB.getJob(jobID); if (job == null) { throw new SLAMDServerException("Could not retrieve information for " + "job from the configuration directory"); } } catch (Exception e) { infoMessage.append("ERROR: " + e.getMessage() + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">View Job Statistics</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Information about job " + jobID + "is not available." + EOL); htmlBody.append("See the error message above for more information." + EOL); return; } // Determine what exactly should be shown. boolean showJobStats = true; boolean showClientStats = false; boolean showThreadStats = false; // Show the header at the top of the page requestInfo.generateSidebar = false; htmlBody.append("<A NAME=\"top\">" + EOL); htmlBody.append("<H1>View Statistics for Job " + jobID + "</H1>" + EOL); htmlBody.append("<BR>" + EOL); // Create all the variables we'll need to show the form. String[] trackerNames = job.getStatTrackerNames(); String[] displayTrackerNames = new String[0]; int defaultStatTypes = 1; for (int i=0; i < trackerNames.length; i++) { defaultStatTypes *= 2; } defaultStatTypes -= 1; String[] monitorTrackerNames = job.getResourceStatTrackerNames(); String[] displayMonitorTrackerNames = new String[0]; int defaultMonitorStatTypes = 1; for (int i=0; i < monitorTrackerNames.length; i++) { defaultMonitorStatTypes *= 2; } defaultMonitorStatTypes -= 1; MultiValuedParameter trackersParameter = new MultiValuedParameter(Constants.SERVLET_PARAM_STAT_TRACKER, "Statistic Types", "The types of statistics that are " + "available for this job", trackerNames, 0, true); MultiValuedParameter monitorTrackersParameter = new MultiValuedParameter(Constants.SERVLET_PARAM_MONITOR_STAT, "Resource Monitor Statistic Types", "The types of resource monitor statistics " + "that are available for this job", monitorTrackerNames, 0, true); MultiValuedParameter detailLevelParameter = new MultiValuedParameter(Constants.SERVLET_PARAM_DETAIL_LEVEL, "Level of Detail", "The amount of detail to display for each " + "statistic type", Constants.STAT_CATEGORY_NAMES, Constants.STAT_CATEGORY_JOB_STATS, true); // Figure out what the user has actually requested (if anything) if (request.getParameter(Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + Constants.SERVLET_PARAM_STAT_TRACKER) != null) { try { trackersParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackersParameter.getName())); displayTrackerNames = intToTrackerNames(trackersParameter.getIntValue(), trackerNames); } catch (Exception e) {} } if (request.getParameter(Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + Constants.SERVLET_PARAM_MONITOR_STAT) != null) { try { monitorTrackersParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + monitorTrackersParameter.getName())); displayMonitorTrackerNames = intToTrackerNames(monitorTrackersParameter.getIntValue(), monitorTrackerNames); } catch (Exception e) {} } if (request.getParameter(Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + Constants.SERVLET_PARAM_DETAIL_LEVEL) != null) { try { detailLevelParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + detailLevelParameter.getName())); int intValue = detailLevelParameter.getIntValue(); showJobStats = (intValue & Constants.STAT_CATEGORY_JOB_STATS) == Constants.STAT_CATEGORY_JOB_STATS; showClientStats = (intValue & Constants.STAT_CATEGORY_CLIENT_STATS) == Constants.STAT_CATEGORY_CLIENT_STATS; showThreadStats = (intValue & Constants.STAT_CATEGORY_THREAD_STATS) == Constants.STAT_CATEGORY_THREAD_STATS; } catch (Exception e) {} } // Generate the form to allow the user choose what they want to see. htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_VIEW_STATS) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><B>" + trackersParameter.getDisplayName() + "</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + trackersParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); if (monitorTrackerNames.length > 0) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><B>" + monitorTrackersParameter.getDisplayName() + "</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + monitorTrackersParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><B>" + detailLevelParameter.getDisplayName() + "</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + detailLevelParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" VALUE=\"Refresh\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); // Since this page can get kind of long, generate anchor links for (int i=0; i < displayTrackerNames.length; i++) { htmlBody.append("<A HREF=\"#stat" + i + "\">Jump to statistics for " + displayTrackerNames[i] + "</A><BR>" + EOL); } for (int i=0; i < displayMonitorTrackerNames.length; i++) { htmlBody.append("<A HREF=\"#stat" + (i+displayTrackerNames.length) + "\">Jump to statistics for " + displayMonitorTrackerNames[i] + "</A><BR>" + EOL); } // Actually generate the detail information. String separator = "<BR><HR><BR>"; for (int i=0; i < displayTrackerNames.length; i++) { htmlBody.append(separator + EOL); htmlBody.append("<A NAME=\"stat" + i + "\">" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">" + displayTrackerNames[i] + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); if (showJobStats) { StatTracker[] statTrackers = job.getStatTrackers(displayTrackerNames[i]); try { StatTracker tracker = statTrackers[0].newInstance(); tracker.aggregate(statTrackers); htmlBody.append("<B>Combined Data for All Threads</B>" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append(tracker.getDetailHTML() + EOL); } catch (Exception e) { e.printStackTrace(); } } if (showClientStats || showThreadStats) { String[] clientIDs = job.getStatTrackerClientIDs(); for (int j=0; j < clientIDs.length; j++) { StatTracker[] statTrackers = job.getStatTrackers(displayTrackerNames[i], clientIDs[j]); if (showClientStats) { try { StatTracker tracker = statTrackers[0].newInstance(); tracker.aggregate(statTrackers); htmlBody.append("<BLOCKQUOTE>" + EOL); htmlBody.append("<B>Summary Data for Client " + clientIDs[j] + "</B>" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append(tracker.getDetailHTML() + EOL); if (showThreadStats) { htmlBody.append("<BLOCKQUOTE>" + EOL); for (int k=0; k < statTrackers.length; k++) { htmlBody.append("<B>Data for Client " + clientIDs[j] + " Thread " + statTrackers[k].getThreadID() + "</B>" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append(statTrackers[k].getDetailHTML() + EOL); htmlBody.append("<BR>" + EOL); } htmlBody.append("</BLOCKQUOTE>" + EOL); } htmlBody.append("</BLOCKQUOTE>" + EOL); } catch (Exception e) { e.printStackTrace(); } } else { htmlBody.append("<BLOCKQUOTE>" + EOL); for (int k=0; k < statTrackers.length; k++) { htmlBody.append("<B>Data for Client " + clientIDs[j] + " Thread " + statTrackers[k].getThreadID() + "</B>" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append(statTrackers[k].getDetailHTML() + EOL); htmlBody.append("<BR>" + EOL); } htmlBody.append("</BLOCKQUOTE>" + EOL); } } } htmlBody.append("<A HREF=\"#top\">Return to Top</A><BR>" + EOL); } for (int i=0; i < displayMonitorTrackerNames.length; i++) { htmlBody.append(separator + EOL); htmlBody.append("<A NAME=\"stat" + (i+displayTrackerNames.length) + "\">" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">" + displayMonitorTrackerNames[i] + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); StatTracker[] statTrackers = job.getResourceStatTrackers(displayMonitorTrackerNames[i]); try { StatTracker tracker = statTrackers[0].newInstance(); tracker.aggregate(statTrackers); htmlBody.append("<B>Combined Data for All Threads</B>" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append(tracker.getDetailHTML() + EOL); } catch (Exception e) { e.printStackTrace(); } htmlBody.append("<A HREF=\"#top\">Return to Top</A><BR>" + EOL); } } /** * Handles all processing related to saving job statistics to an external * file. * * @param requestInfo The state information for this request. */ static void handleSaveJobStatistics(RequestInfo requestInfo) { logMessage(requestInfo, "In handleSaveJobStatistics()"); // The user must be able to export job information to do anything here if (! requestInfo.mayExportJobData) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "save job information"); return; } // Get important state variables for this request. HttpServletRequest request = requestInfo.request; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // Get the job ID. If there is no job ID, then just display an error. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Save Job Statistics</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("No job was specified for which to save statistical " + "information." + EOL); String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, "here"); htmlBody.append("Click " + link + " to view the set of completed " + "jobs" + EOL); return; } // Get the job with the specified job ID. Job job = null; try { job = configDB.getJob(jobID); if (job == null) { throw new SLAMDServerException("Could not retrieve information for " + "job from the configuration directory"); } } catch (Exception e) { infoMessage.append("ERROR: " + e.getMessage() + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Save Job Statistics</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Information about job " + jobID + "is not available." + EOL); htmlBody.append("See the error message above for more information." + EOL); return; } // Determine what exactly should be saved. boolean saveJobStats = true; boolean saveClientStats = true; boolean saveThreadStats = true; boolean saveWithLabels = true; String[] trackerNames = job.getStatTrackerNames(); String[] monitorTrackerNames = job.getResourceStatTrackerNames(); String[] saveTrackerNames = trackerNames; String[] saveMonitorTrackerNames = monitorTrackerNames; int defaultStatTypes = 1; for (int i=0; i < trackerNames.length; i++) { defaultStatTypes *= 2; } defaultStatTypes -= 1; int defaultMonitorStatTypes = 1; for (int i=0; i < monitorTrackerNames.length; i++) { defaultMonitorStatTypes *= 2; } defaultMonitorStatTypes -= 1; int detailLevel = Constants.STAT_CATEGORY_JOB_STATS | Constants.STAT_CATEGORY_CLIENT_STATS | Constants.STAT_CATEGORY_THREAD_STATS; BooleanParameter includeLabelsParameter = new BooleanParameter(Constants.SERVLET_PARAM_INCLUDE_LABELS, "Include Row/Column Labels", "Indicates whether to include row and column " + "labels in the data to be saved", true); MultiValuedParameter trackersParameter = new MultiValuedParameter(Constants.SERVLET_PARAM_STAT_TRACKER, "Statistic Types", "The types of statistics that are " + "available for this job", trackerNames, defaultStatTypes, true); MultiValuedParameter monitorTrackersParameter = new MultiValuedParameter(Constants.SERVLET_PARAM_MONITOR_STAT, "Resource Monitor Statistic Types", "The types of resource monitor statistics " + "that are available for this job", monitorTrackerNames, defaultMonitorStatTypes, true); MultiValuedParameter detailLevelParameter = new MultiValuedParameter(Constants.SERVLET_PARAM_DETAIL_LEVEL, "Level of Detail", "The amount of detail to include for each " + "statistic type", Constants.STAT_CATEGORY_NAMES, detailLevel, true); // See whether we need to actually save the data or if we should display the // form that allows the user to choose what they want to save. This is done // by looking for the presence of the confirmed parameter. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr == null) || (confirmStr.length() == 0)) { // The user hasn't gotten to choose what he/she wants to see yet, so // show them the form. htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Save Data for Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("This function allows you to save the statistical " + "information gathered while processing this job to a " + "tab-delimited text file that may be imported into " + "a spreadsheet or other application." + EOL); htmlBody.append("Choose the kinds of data and the level of detail that " + "you would like to include in the output." + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + requestInfo.servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_SAVE_STATS) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><B>" + trackersParameter.getDisplayName() + "</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + trackersParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); if (monitorTrackerNames.length > 0) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><B>" + monitorTrackersParameter.getDisplayName() + "</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + monitorTrackersParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><B>" + detailLevelParameter.getDisplayName() + "</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + detailLevelParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><B>" + includeLabelsParameter.getDisplayName() + "</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + includeLabelsParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Save the Data\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR><BR>" + EOL); String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, Constants.SERVLET_PARAM_JOB_ID, jobID, "Return to Job Information Page"); htmlBody.append(link + EOL); } else { // The form has been submitted, so we're going to write out the // information that they have requested. First, get all the request // parameters. try { trackersParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackersParameter.getName())); saveTrackerNames = intToTrackerNames(trackersParameter.getIntValue(), trackerNames); } catch (Exception e) {} try { monitorTrackersParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + monitorTrackersParameter.getName())); saveMonitorTrackerNames = intToTrackerNames(monitorTrackersParameter.getIntValue(), monitorTrackerNames); } catch (Exception e) {} try { detailLevelParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + detailLevelParameter.getName())); int intValue = detailLevelParameter.getIntValue(); saveJobStats = (intValue & Constants.STAT_CATEGORY_JOB_STATS) == Constants.STAT_CATEGORY_JOB_STATS; saveClientStats = (intValue & Constants.STAT_CATEGORY_CLIENT_STATS) == Constants.STAT_CATEGORY_CLIENT_STATS; saveThreadStats = (intValue & Constants.STAT_CATEGORY_THREAD_STATS) == Constants.STAT_CATEGORY_THREAD_STATS; } catch (Exception e) {} try { includeLabelsParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + includeLabelsParameter.getName())); saveWithLabels = includeLabelsParameter.getBooleanValue(); } catch (Exception e) {} // Get the print writer for this servlet. This is the only thing that // should throw an exception, so it is the only way we can bail out // prematurely. Of course, if this fails, then it's very likely that // the attempt to display the page back to the client will fail too. PrintWriter writer; try { writer = requestInfo.response.getWriter(); } catch (IOException ioe) { infoMessage.append("ERROR: Unable to write the data -- " + ioe + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Error Saving Data</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("The attempt to save the data failed." + EOL); htmlBody.append("See the error message above for additional " + "information"); return; } // OK. We're ready to go. We want this information to get saved to a // file rather than displayed by the browser. To do this, we need to // set a content type that the browser doesn't recognize. Also, we want // to make sure that doPost doesn't try to generate any additional HTML // because otherwise that would get saved in the file too. requestInfo.response.setContentType("application/x-slamd-statistics"); requestInfo.response.addHeader("Content-Disposition", "filename=\"slamd_job_data_" + jobID + ".txt\""); requestInfo.generateHTML = false; // Now iterate through each type of statistic and save the appropriate // set of values. for (int i=0; i < saveTrackerNames.length; i++) { if (saveJobStats) { StatTracker[] statTrackers = job.getStatTrackers(saveTrackerNames[i]); try { StatTracker tracker = statTrackers[0].newInstance(); tracker.aggregate(statTrackers); if (saveWithLabels) { writer.println("Combined " + saveTrackerNames[i] + " Data for All Threads"); } String[][] values = tracker.getDataForExport(saveWithLabels); for (int j=0; j < values.length; j++) { String tab = ""; for (int k=0; k < values[j].length; k++) { writer.print(tab + values[j][k]); tab = "\t"; } writer.println(); } writer.println(); writer.println(); } catch (Exception e) { e.printStackTrace(); } } if (saveClientStats || saveThreadStats) { String[] clientIDs = job.getStatTrackerClientIDs(); for (int j=0; j < clientIDs.length; j++) { StatTracker[] statTrackers = job.getStatTrackers(saveTrackerNames[i], clientIDs[j]); if (saveClientStats) { try { StatTracker tracker = statTrackers[0].newInstance(); tracker.aggregate(statTrackers); if (saveWithLabels) { writer.println("Combined " + saveTrackerNames[i] + " Data for Client " + clientIDs[j]); } String[][] values = tracker.getDataForExport(saveWithLabels); for (int k=0; k < values.length; k++) { String tab = ""; for (int l=0; l < values[k].length; l++) { writer.print(tab + values[k][l]); tab = "\t"; } writer.println(); } writer.println(); writer.println(); } catch (Exception e) { e.printStackTrace(); } } if (saveThreadStats) { for (int k=0; k < statTrackers.length; k++) { if (saveWithLabels) { writer.println(saveTrackerNames[i] + " Data for Client " + clientIDs[j] + " Thread " + statTrackers[k].getThreadID()); } String[][] values = statTrackers[k].getDataForExport(saveWithLabels); for (int l=0; l < values.length; l++) { String tab = ""; for (int m=0; m < values[l].length; m++) { writer.print(tab + values[l][m]); tab = "\t"; } writer.println(); } writer.println(); writer.println(); } } } } } // Now iterate through each type of resource monitor statistic and save // the appropriate set of values. for (int i=0; i < saveMonitorTrackerNames.length; i++) { StatTracker[] statTrackers = job.getResourceStatTrackers(saveMonitorTrackerNames[i]); try { StatTracker tracker = statTrackers[0].newInstance(); tracker.aggregate(statTrackers); if (saveWithLabels) { writer.println(saveMonitorTrackerNames[i]); } String[][] values = tracker.getDataForExport(saveWithLabels); for (int j=0; j < values.length; j++) { String tab = ""; for (int k=0; k < values[j].length; k++) { writer.print(tab + values[j][k]); tab = "\t"; } writer.println(); } writer.println(); writer.println(); } catch (Exception e) { e.printStackTrace(); } } } } /** * Converts the provided int value into a list of the stat tracker names to * which that number should correspond. This is used to convert the value * of the multivalued parameter for statistic types into a list of the stat * trackers for which data is to be provided. * * @param intValue The int value to be converted into a set of tracker * names. * @param trackerNames The set of all stat tracker names available for the * job to be displayed. * * @return The set of stat tracker names that the user has chosen. */ static String[] intToTrackerNames(int intValue, String[] trackerNames) { ArrayList<String> nameList = new ArrayList<String>(); for (int i=0; i < trackerNames.length; i++) { // Calculate 2^i int val = 1; for (int j=0; j < i; j++) { val *= 2; } if ((intValue & val) == val) { nameList.add(trackerNames[i]); } } String[] nameArray = new String[nameList.size()]; nameList.toArray(nameArray); return nameArray; } /** * Handles the processing required to display graphs of statistical * information gathered during job processing. * * @param requestInfo The state information for this request. */ static void handleViewGraph(RequestInfo requestInfo) { logMessage(requestInfo, "In handleViewGraph()"); // The user must be able to view job information in order to see this if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "view job information"); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.htmlBody; // See if information has been posted for this graph. boolean posted = false; String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && (confirmStr.length() > 0)) { posted = true; } // Get the job ID and the job that goes along with it String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Job Results</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("No job ID was specified." + EOL); htmlBody.append("A job ID is required to indicate which job " + "contains the data to be graphed." + EOL); return; } Job job; try { job = configDB.getJob(jobID); if (job == null) { throw new SLAMDServerException("No information is know about job " + jobID); } } catch (Exception e) { infoMessage.append("ERROR: " + e.getMessage() + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Results for Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Unable to retrieve job " + jobID + " from the configuration directory." + EOL); htmlBody.append("See the error message above for additional " + "information." + EOL); return; } // Get information about the kinds of statistics available for this job. // If there is no statistical data available, then abort. String[] trackerNames = job.getStatTrackerNames(); String[] clientIDs = job.getStatTrackerClientIDs(); if ((trackerNames == null) || (trackerNames.length == 0) || (clientIDs == null) || (clientIDs.length == 0)) { trackerNames = job.getResourceStatTrackerNames(); clientIDs = job.getResourceStatTrackerClientIDs(); if ((trackerNames == null) || (trackerNames.length == 0) || (clientIDs == null) || (clientIDs.length == 0)) { String link = generateGetJobLink(requestInfo, jobID, jobID); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Results for Job " + link + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("The specified job does not contain any statistical " + "data from which to generate a graph."); return; } else { // This job does not have any job statistics, but it does have // monitor statistics, so show the user the page to display them. handleViewMonitorGraph(requestInfo); return; } } // Generate the common parameters that will be used for user input. IntegerParameter widthParameter = new IntegerParameter(Constants.SERVLET_PARAM_GRAPH_WIDTH, "Graph Width", "The width in pixels of the graph to create", true, defaultGraphWidth, true, 0, false, 0); IntegerParameter heightParameter = new IntegerParameter(Constants.SERVLET_PARAM_GRAPH_HEIGHT, "Graph Height", "The height in pixels of the graph to create", true, defaultGraphHeight, true, 0, false, 0); MultiChoiceParameter trackersParameter = new MultiChoiceParameter(Constants.SERVLET_PARAM_STAT_TRACKER, "Statistic Types", "The types of statistics that are " + "maintained for this job.", trackerNames, trackerNames[0]); IntegerParameter monitorHeightParameter = new IntegerParameter(Constants.SERVLET_PARAM_MONITOR_GRAPH_HEIGHT, "Resource Monitor Graph Height", "The height in pixels for the resource monitor " + "graphs", true, defaultMonitorGraphHeight, true, 0, false, 0); BooleanParameter graphAllMonitorsParameter = new BooleanParameter(Constants.SERVLET_PARAM_MONITOR_GRAPH_ALL, "Graph All Resource Monitors", "Indicates whether all resource monitor " + "statistics should be graphed.", false); // Obtain the values that should be used for the common parameters. if (posted) { try { widthParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + widthParameter.getName())); } catch (Exception e) {} try { heightParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + heightParameter.getName())); } catch (Exception e) {} try { trackersParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackersParameter.getName())); } catch (Exception e) {} } // Get the tracker-specific parameters. Parameter[] trackerParameters = new Parameter[0]; StatTracker[] selectedTrackers = job.getStatTrackers(trackersParameter.getStringValue()); if ((selectedTrackers != null) && (selectedTrackers.length > 0)) { trackerParameters = selectedTrackers[0].getGraphParameterStubs(job). clone().getParameters(); for (int i=0; i < trackerParameters.length; i++) { if (posted) { try { trackerParameters[i].htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackerParameters[i].getName())); } catch (Exception e) {} } } } // Get the height for the monitor tracker graphs. try { monitorHeightParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + monitorHeightParameter.getName())); } catch (Exception e) {} // Get the set of all resource monitor statistics collected for the job. ResourceMonitorStatTracker[] monitorTrackers = job.getResourceMonitorStatTrackers(); // Determine whether to graph all monitor trackers. try { graphAllMonitorsParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + graphAllMonitorsParameter.getName())); } catch (Exception e) {} boolean graphAllMonitors = graphAllMonitorsParameter.getBooleanValue(); // Determine whether to graph monitor trackers by client. String[] monitorClientIDs = job.getResourceStatTrackerClientIDs(); BooleanParameter[] monitorClientParameters = new BooleanParameter[monitorClientIDs.length]; HashSet<String> monitorClientSet = new HashSet<String>(monitorClientIDs.length); for (int i=0; i < monitorClientIDs.length; i++) { String clientID = monitorClientIDs[i]; String safeName = Constants.SERVLET_PARAM_MONITOR_CLIENT + '_' + clientID; String displayName = "Graph All " + clientID + " Resource Monitors"; String description = "Indicates whether all resource statistics " + "collected by the " + clientID + " resource monitor client should be graphed."; monitorClientParameters[i] = new BooleanParameter(safeName, displayName, description, false); try { if (posted) { if (graphAllMonitors) { monitorClientParameters[i].setValue(true); } else { monitorClientParameters[i].htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + safeName)); } } } catch (Exception e) {} if (monitorClientParameters[i].getBooleanValue()) { monitorClientSet.add(clientID); } } // Determine whether to graph monitor trackers by monitor class. ResourceMonitor[] monitorClasses = job.getResourceMonitorClasses(); BooleanParameter[] monitorClassParameters = new BooleanParameter[monitorClasses.length]; HashSet<String> monitorClassSet = new HashSet<String>(monitorClasses.length); for (int i=0; i < monitorClassParameters.length; i++) { String className = monitorClasses[i].getClass().getName(); String safeName = Constants.SERVLET_PARAM_MONITOR_CLASS + '_' + className; String displayName = "Graph All " + monitorClasses[i].getMonitorName() + " Resource Monitors"; String description = "Indicates whether all resource statistics " + "collected by instances of the " + className + " resource monitor should be graphed."; monitorClassParameters[i] = new BooleanParameter(safeName, displayName, description, false); try { if (posted) { if (graphAllMonitors) { monitorClassParameters[i].setValue(true); } else { monitorClassParameters[i].htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + safeName)); } } } catch (Exception e) {} if (monitorClassParameters[i].getBooleanValue()) { monitorClassSet.add(className); } } // Generate the page header. String link = generateGetJobLink(requestInfo, jobID, jobID); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Results for Job " + link + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Choose the type of information and level of detail to " + "display." + EOL); htmlBody.append("<BR>" + EOL); // Generate the form that allows the user to specify the information htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_VIEW_GRAPH) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_CONFIRMED, "1") + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + widthParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + widthParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + heightParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + heightParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + trackersParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + trackersParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Generate the tracker-specific parameter input form for (int i=0; i < trackerParameters.length; i++) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + trackerParameters[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + trackerParameters[i].getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // Generate the element to allow the user to specify the height for system // resource graphs. if (monitorTrackers.length > 0) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + monitorHeightParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + monitorHeightParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + graphAllMonitorsParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + graphAllMonitorsParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); for (int i=0; i < monitorClientParameters.length; i++) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + monitorClientParameters[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + monitorClientParameters[i].getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } for (int i=0; i < monitorClassParameters.length; i++) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + monitorClassParameters[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + monitorClassParameters[i].getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" " + "VALUE=\"View Graph\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>"); // Generate the image tag. Replace any spaces with the '+' sign. String imageURI; try { htmlBody.append("<BR><BR>" + EOL); imageURI = servletBaseURI + '?' + Constants.SERVLET_PARAM_SECTION + '=' + Constants.SERVLET_SECTION_JOB + '&' + Constants.SERVLET_PARAM_SUBSECTION + '=' + Constants.SERVLET_SECTION_JOB_GRAPH + '&' + Constants.SERVLET_PARAM_JOB_ID + '=' + jobID + '&' + Constants.SERVLET_PARAM_GRAPH_WIDTH +'=' + widthParameter.getIntValue() + '&' + Constants.SERVLET_PARAM_GRAPH_HEIGHT + '=' + heightParameter.getIntValue() + '&' + Constants.SERVLET_PARAM_STAT_TRACKER + '=' + URLEncoder.encode(trackersParameter.getStringValue(), "UTF-8"); for (int i=0; i < trackerParameters.length; i++) { imageURI += '&' + Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackerParameters[i].getName() + '=' + trackerParameters[i].getValueString(); } htmlBody.append("<IMG SRC=\"" + imageURI.replace(' ', '+') + "\" WIDTH=\"" + widthParameter.getIntValue() + "\" HEIGHT=\"" + heightParameter.getIntValue() + "\" ALT=\"Graph of Results for Job " + jobID + "\">" + EOL); } catch (Exception e) { slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(e)); } // Graph any appropriate resource monitor statistics. for (int i=0; i < monitorTrackers.length; i++) { try { String monitorClass = monitorTrackers[i].getResourceMonitor().getClass().getName(); String monitorClientID = monitorTrackers[i].getStatTracker().getClientID(); if ((! monitorClassSet.contains(monitorClass)) && (! monitorClientSet.contains(monitorClientID))) { continue; } String displayName = monitorTrackers[i].getStatTracker().getDisplayName(); htmlBody.append("<BR><BR>" + EOL); imageURI = servletBaseURI + '?' + Constants.SERVLET_PARAM_SECTION + '=' + Constants.SERVLET_SECTION_JOB + '&' + Constants.SERVLET_PARAM_SUBSECTION + '=' + Constants.SERVLET_SECTION_JOB_GRAPH_MONITOR + '&' + Constants.SERVLET_PARAM_JOB_ID + '=' + jobID + '&' + Constants.SERVLET_PARAM_GRAPH_WIDTH + '=' + widthParameter.getIntValue() + '&' + Constants.SERVLET_PARAM_MONITOR_GRAPH_HEIGHT + '=' + monitorHeightParameter.getIntValue() + '&' + Constants.SERVLET_PARAM_STAT_TRACKER + '=' + URLEncoder.encode(displayName, "UTF-8"); htmlBody.append("<IMG SRC=\"" + imageURI.replace(' ', '+') + "\" WIDTH=\"" + widthParameter.getIntValue() + "\" HEIGHT=\"" + monitorHeightParameter.getIntValue() + "\" ALT=\"" + displayName + "\">" + EOL); } catch (Exception e) { slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(e)); } } } /** * Handles the processing required to display graphs of resource monitor * information gathered during job processing. * * @param requestInfo The state information for this request. */ static void handleViewMonitorGraph(RequestInfo requestInfo) { logMessage(requestInfo, "In handleViewGraph()"); // The user must be able to view job information in order to see this if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "view job information"); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.htmlBody; // See if information has been posted for this graph. boolean posted = false; String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && (confirmStr.length() > 0)) { posted = true; } // Get the job ID and the job that goes along with it String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Job Resource Monitors</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("No job ID was specified." + EOL); htmlBody.append("A job ID is required to indicate which job " + "contains the data to be graphed." + EOL); return; } Job job; try { job = configDB.getJob(jobID); if (job == null) { throw new SLAMDServerException("No information is know about job " + jobID); } } catch (Exception e) { infoMessage.append("ERROR: " + e.getMessage() + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Resource Monitors for Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Unable to retrieve job " + jobID + " from the configuration directory." + EOL); htmlBody.append("See the error message above for additional " + "information." + EOL); return; } // Get information about the kinds of statistics available for this job. // If there is no statistical data available, then abort. String[] trackerNames = job.getResourceStatTrackerNames(); String[] clientIDs = job.getResourceStatTrackerClientIDs(); if ((trackerNames == null) || (trackerNames.length == 0) || (clientIDs == null) || (clientIDs.length == 0)) { String link = generateGetJobLink(requestInfo, jobID, jobID); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Resource Monitors for Job " + link + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("The specified job does not contain any resource " + "monitor data from which to generate a graph."); return; } // Generate the common parameters that will be used for user input. IntegerParameter widthParameter = new IntegerParameter(Constants.SERVLET_PARAM_GRAPH_WIDTH, "Graph Width", "The width in pixels of the graph to create", true, defaultGraphWidth, true, 0, false, 0); IntegerParameter heightParameter = new IntegerParameter(Constants.SERVLET_PARAM_GRAPH_HEIGHT, "Graph Height", "The height in pixels of the graph to create", true, defaultGraphHeight, true, 0, false, 0); MultiChoiceParameter trackersParameter = new MultiChoiceParameter(Constants.SERVLET_PARAM_STAT_TRACKER, "Resource Monitor Types", "The types of statistics that are " + "maintained for this job.", trackerNames, trackerNames[0]); IntegerParameter monitorHeightParameter = new IntegerParameter(Constants.SERVLET_PARAM_MONITOR_GRAPH_HEIGHT, "Resource Monitor Graph Height", "The height in pixels for the resource monitor " + "graphs", true, defaultMonitorGraphHeight, true, 0, false, 0); BooleanParameter graphAllMonitorsParameter = new BooleanParameter(Constants.SERVLET_PARAM_MONITOR_GRAPH_ALL, "Graph All Resource Monitors", "Indicates whether all resource monitor " + "statistics should be graphed.", false); // Obtain the values that should be used for the common parameters. if (posted) { try { widthParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + widthParameter.getName())); } catch (Exception e) {} try { heightParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + heightParameter.getName())); } catch (Exception e) {} try { trackersParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackersParameter.getName())); } catch (Exception e) {} try { monitorHeightParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + monitorHeightParameter.getName())); } catch (Exception e) {} try { graphAllMonitorsParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + graphAllMonitorsParameter.getName())); } catch (Exception e) {} } // Get the tracker-specific parameters. Parameter[] trackerParameters = new Parameter[0]; StatTracker[] selectedTrackers = job.getResourceStatTrackers(trackersParameter.getStringValue()); if ((selectedTrackers != null) && (selectedTrackers.length > 0)) { trackerParameters = selectedTrackers[0].getMonitorGraphParameterStubs(job). clone().getParameters(); for (int i=0; i < trackerParameters.length; i++) { if (posted) { try { trackerParameters[i].htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackerParameters[i].getName())); } catch (Exception e) {} } } } // Generate the page header. String link = generateGetJobLink(requestInfo, jobID, jobID); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Resource Monitors for Job " + link + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Choose the resource monitor to graph." + EOL); htmlBody.append("<BR>" + EOL); // Generate the form that allows the user to specify the information htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_VIEW_MONITOR_GRAPH) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_CONFIRMED, "1") + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + widthParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + widthParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + heightParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + heightParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + trackersParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + trackersParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Generate the tracker-specific parameter input form for (int i=0; i < trackerParameters.length; i++) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + trackerParameters[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + trackerParameters[i].getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + monitorHeightParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + monitorHeightParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + graphAllMonitorsParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + graphAllMonitorsParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" " + "VALUE=\"View Graph\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>"); try { // Generate the image tag. Replace any spaces with the '+' sign. htmlBody.append("<BR><BR>" + EOL); String imageURI = servletBaseURI + '?' + Constants.SERVLET_PARAM_SECTION + '=' + Constants.SERVLET_SECTION_JOB + '&' + Constants.SERVLET_PARAM_SUBSECTION + '=' + Constants.SERVLET_SECTION_JOB_GRAPH_MONITOR + '&' + Constants.SERVLET_PARAM_JOB_ID + '=' + jobID + '&' + Constants.SERVLET_PARAM_GRAPH_WIDTH + '=' + widthParameter.getIntValue() + '&' + Constants.SERVLET_PARAM_MONITOR_GRAPH_HEIGHT + '=' + heightParameter.getIntValue() + '&' + Constants.SERVLET_PARAM_STAT_TRACKER + '=' + URLEncoder.encode(trackersParameter.getStringValue(), "UTF-8"); for (int i=0; i < trackerParameters.length; i++) { imageURI += '&' + Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackerParameters[i].getName() + '=' + trackerParameters[i].getValueString(); } htmlBody.append("<IMG SRC=\"" + imageURI.replace(' ', '+') + "\" WIDTH=\"" + widthParameter.getIntValue() + "\" HEIGHT=\"" + heightParameter.getIntValue() + "\" ALT=\"Graph of Results for Job " + jobID + "\">" + EOL); } catch (Exception e) { slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(e)); } // If we should graph all monitor stats, then do so. if (graphAllMonitorsParameter.getBooleanValue()) { String[] monitorTrackerNames = job.getResourceStatTrackerNames(); for (int i=0; i < monitorTrackerNames.length; i++) { try { htmlBody.append("<BR><BR>" + EOL); String imageURI = servletBaseURI + '?' + Constants.SERVLET_PARAM_SECTION + '=' + Constants.SERVLET_SECTION_JOB + '&' + Constants.SERVLET_PARAM_SUBSECTION + '=' + Constants.SERVLET_SECTION_JOB_GRAPH_MONITOR + '&' + Constants.SERVLET_PARAM_JOB_ID + '=' + jobID + '&' + Constants.SERVLET_PARAM_GRAPH_WIDTH + '=' + widthParameter.getIntValue() + '&' + Constants.SERVLET_PARAM_MONITOR_GRAPH_HEIGHT + '=' + monitorHeightParameter.getIntValue() + '&' + Constants.SERVLET_PARAM_STAT_TRACKER + '=' + URLEncoder.encode(monitorTrackerNames[i], "UTF-8"); htmlBody.append("<IMG SRC=\"" + imageURI.replace(' ', '+') + "\" WIDTH=\"" + widthParameter.getIntValue() + "\" HEIGHT=\"" + monitorHeightParameter.getIntValue() + "\" ALT=\"" + monitorTrackerNames[i] + "\">" + EOL); } catch (Exception e) { slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(e)); } } } } /** * Handles the processing required to actually serve up the dynamically * generated images depicting information gathered during job processing. * * @param requestInfo The state information for this request. */ static void handleGraph(RequestInfo requestInfo) { logMessage(requestInfo, "In handleGraph()"); // The user must be able to view job information in order to see this if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); try { requestInfo.response.sendError(HttpServletResponse.SC_UNAUTHORIZED); } catch (Exception e) { e.printStackTrace(); } return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; HttpServletResponse response = requestInfo.response; // Get the job IDs. If none were specified, then send back an error // response. If one was provided, then generate a regular graph. If // multiple job IDs were provided, then generate a graph comparing the // results of those jobs. String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if ((jobIDs == null) || (jobIDs.length == 0)) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (Exception e) {} return; } else if (jobIDs.length == 1) { String jobID = jobIDs[0]; Job job = null; try { job = configDB.getJob(jobID); } catch (Exception e) { e.printStackTrace(); } if (job == null) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (Exception e) { e.printStackTrace(); } return; } // Get the graph parameters. int width = defaultGraphWidth; try { width = Integer.parseInt(request.getParameter( Constants.SERVLET_PARAM_GRAPH_WIDTH)); } catch (Exception e) { e.printStackTrace(); } int height = defaultGraphHeight; try { height = Integer.parseInt(request.getParameter( Constants.SERVLET_PARAM_GRAPH_HEIGHT)); } catch (Exception e) { e.printStackTrace(); } // Get the type of statistic that is to be graphed. String trackerName = request.getParameter(Constants.SERVLET_PARAM_STAT_TRACKER); StatTracker[] selectedTrackers = job.getStatTrackers(trackerName); if ((selectedTrackers == null) || (selectedTrackers.length == 0)) { return; } // Get the tracker-specific parameters. Parameter[] trackerParams = new Parameter[0]; if ((selectedTrackers != null) && (selectedTrackers.length > 0)) { trackerParams = selectedTrackers[0].getGraphParameterStubs(job). clone().getParameters(); for (int i=0; i < trackerParams.length; i++) { if (request.getParameter(Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackerParams[i].getName()) != null) { try { trackerParams[i].htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackerParams[i].getName())); } catch (Exception e) {} } } } // Generate the graph. try { BufferedImage image = selectedTrackers[0].createGraph(job, width, height, new ParameterList(trackerParams)); response.setContentType("image/png"); response.addHeader("Content-Disposition", "filename=\"" + generateGraphFilename(job, selectedTrackers[0]) + '"'); ImageEncoder encoder = ImageCodec.createImageEncoder("png", response.getOutputStream(), null); encoder.encode(image); } catch (Exception e) { e.printStackTrace(); } } else { Job[] jobs = new Job[jobIDs.length]; for (int i=0; i < jobs.length; i++) { try { jobs[i] = configDB.getJob(jobIDs[i]); } catch (Exception e) { e.printStackTrace(); } if (jobs[i] == null) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (Exception e) { e.printStackTrace(); } return; } } // Get the graph parameters. int width = Constants.DEFAULT_GRAPH_WIDTH; try { width = Integer.parseInt(request.getParameter( Constants.SERVLET_PARAM_GRAPH_WIDTH)); } catch (Exception e) { e.printStackTrace(); } int height = Constants.DEFAULT_GRAPH_HEIGHT; try { height = Integer.parseInt(request.getParameter( Constants.SERVLET_PARAM_GRAPH_HEIGHT)); } catch (Exception e) { e.printStackTrace(); } // Get the type of statistic that is to be graphed. String trackerName = request.getParameter(Constants.SERVLET_PARAM_STAT_TRACKER); StatTracker[] selectedTrackers = jobs[0].getStatTrackers(trackerName); if ((selectedTrackers == null) || (selectedTrackers.length == 0)) { return; } // Get the tracker-specific parameters. Parameter[] trackerParams = new Parameter[0]; if ((selectedTrackers != null) && (selectedTrackers.length > 0)) { trackerParams = selectedTrackers[0].getGraphParameterStubs(jobs). clone().getParameters(); for (int i=0; i < trackerParams.length; i++) { if (request.getParameter(Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackerParams[i].getName()) != null) { try { trackerParams[i].htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackerParams[i].getName())); } catch (Exception e) {} } } } // Generate the graph. try { BufferedImage image = selectedTrackers[0].createGraph(jobs, width, height, new ParameterList(trackerParams)); response.setContentType("image/png"); response.addHeader("Content-Disposition", "filename=\"" + generateGraphFilename(jobs, selectedTrackers[0]) + '"'); ImageEncoder encoder = ImageCodec.createImageEncoder("png", response.getOutputStream(), null); encoder.encode(image); } catch (Exception e) { e.printStackTrace(); } } } /** * Handles the processing required to generate graphs from resource monitor * statistics. * * @param requestInfo The state information for this request. */ static void handleMonitorGraph(RequestInfo requestInfo) { logMessage(requestInfo, "In handleMonitorGraph()"); // The user must be able to view job information in order to see this if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); try { requestInfo.response.sendError(HttpServletResponse.SC_UNAUTHORIZED); } catch (Exception e) { e.printStackTrace(); } return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; HttpServletResponse response = requestInfo.response; // Get the job ID. If none was specified, then send back an error // response. If one was provided, then generate a regular graph. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (Exception e) {} return; } Job job = null; try { job = configDB.getJob(jobID); } catch (Exception e) { e.printStackTrace(); } if (job == null) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (Exception e) { e.printStackTrace(); } return; } // Get the graph parameters. int width = defaultGraphWidth; try { width = Integer.parseInt(request.getParameter( Constants.SERVLET_PARAM_GRAPH_WIDTH)); } catch (Exception e) { e.printStackTrace(); } int height = defaultMonitorGraphHeight; try { height = Integer.parseInt(request.getParameter( Constants.SERVLET_PARAM_MONITOR_GRAPH_HEIGHT)); } catch (Exception e) { e.printStackTrace(); } // Get the type of statistic that is to be graphed. String trackerName = request.getParameter(Constants.SERVLET_PARAM_STAT_TRACKER); StatTracker[] selectedTrackers = job.getResourceStatTrackers(trackerName); if ((selectedTrackers == null) || (selectedTrackers.length == 0)) { return; } // Get the tracker-specific parameters. Parameter[] trackerParams = new Parameter[0]; if ((selectedTrackers != null) && (selectedTrackers.length > 0)) { trackerParams = selectedTrackers[0].getMonitorGraphParameterStubs(job). clone().getParameters(); for (int i=0; i < trackerParams.length; i++) { if (request.getParameter(Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackerParams[i].getName()) != null) { try { trackerParams[i].htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + trackerParams[i].getName())); } catch (Exception e) {} } } } // Generate the graph. try { BufferedImage image = selectedTrackers[0].createMonitorGraph(job, width, height, new ParameterList(trackerParams)); response.setContentType("image/png"); response.addHeader("Content-Disposition", "filename=\"" + generateGraphFilename(job, selectedTrackers[0]) + '"'); ImageEncoder encoder = ImageCodec.createImageEncoder("png", response.getOutputStream(), null); encoder.encode(image); } catch (Exception e) { e.printStackTrace(); } } /** * Handles the processing required to display graphs of statistical * information gathered in real time. * * @param requestInfo The state information for this request. */ static void handleViewRealTimeGraph(RequestInfo requestInfo) { logMessage(requestInfo, "In handleViewRealTimeGraph()"); // The user must be able to view job information in order to see this if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "view job information"); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // See if information has been posted for this graph. boolean posted = false; String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && (confirmStr.length() > 0)) { posted = true; } // Get the job ID and the job that goes along with it String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph In-Progress Results</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("No job ID was specified." + EOL); htmlBody.append("A job ID is required to indicate which job " + "contains the data to be graphed." + EOL); return; } Job job = null; RealTimeJobStats jobStats = null; try { job = scheduler.getJob(jobID); if (job != null) { jobStats = job.getRealTimeStats(); } } catch (SLAMDServerException sse) { infoMessage.append("ERROR: " + sse.getMessage() + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph In-Progress Results for Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Unable to retrieve job " + jobID + "from the configuration directory." + EOL); htmlBody.append("See the error message above for additional " + "information." + EOL); return; } if (jobStats == null) { if (job.doneRunning()) { String link = generateGetJobLink(requestInfo, jobID, jobID); infoMessage.append("Job Completed.<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph In-Progress Results for Job " + link + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Job " + jobID + " is no longer running." + EOL); htmlBody.append("The in-progress statistics associated with it are " + "no longer available." + EOL); link = generateGetJobLink(requestInfo, jobID, "completed job page"); htmlBody.append("See the " + link + " for complete details about the " + "job."); return; } else { String link = generateGetJobLink(requestInfo, jobID, jobID); infoMessage.append("ERROR: No data available<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph In-Progress Results for Job " + link + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Job " + jobID + " does not have any in-progress data available." + EOL); return; } } // Get information about the kinds of statistics available for this job. // If there is no statistical data available, then abort. String[] statNames = jobStats.getStatNames(); if ((statNames == null) || (statNames.length == 0)) { String link = generateGetJobLink(requestInfo, jobID, jobID); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph In-Progress Results for Job " + link + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("The specified job does not contain any statistical " + "data from which to generate a graph."); return; } // Generate the common parameters that will be used for user input. IntegerParameter widthParameter = new IntegerParameter(Constants.SERVLET_PARAM_GRAPH_WIDTH, "Graph Width", "The width in pixels of the graph to create", true, defaultGraphWidth, true, 0, false, 0); IntegerParameter heightParameter = new IntegerParameter(Constants.SERVLET_PARAM_GRAPH_HEIGHT, "Graph Height", "The height in pixels of the graph to create", true, defaultGraphHeight, true, 0, false, 0); MultiChoiceParameter statsParameter = new MultiChoiceParameter(Constants.SERVLET_PARAM_STAT_TRACKER, "Statistic Types", "The types of statistics that are " + "maintained for this job.", statNames, statNames[0]); // Obtain the values that should be used for the common parameters. if (posted) { try { widthParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + widthParameter.getName())); } catch (Exception e) {} try { heightParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + heightParameter.getName())); } catch (Exception e) {} try { statsParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + statsParameter.getName())); } catch (Exception e) {} } // Get the data for the requested statistic. String statName = statsParameter.getStringValue(); double[] statValues = jobStats.getStatValues(statName); long updateTime = jobStats.getLastUpdateTime(); // Generate the page header. String link = generateGetJobLink(requestInfo, jobID, jobID); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph In-Progress Results for Job " + link + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Choose the statistic to graph." + EOL); htmlBody.append("<BR>" + EOL); // Generate the form that allows the user to specify the information htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_VIEW_GRAPH_REAL_TIME) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_CONFIRMED, "1") + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + widthParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + widthParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + heightParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + heightParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + statsParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + statsParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" " + "VALUE=\"View Graph\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>"); htmlBody.append("<BR><BR>" + EOL); if ((statValues == null) || (statValues.length == 0)) { htmlBody.append("Job " + jobID + " does not have any in-progress data available for " + statName + EOL); } else if (statValues.length < 2) { htmlBody.append("Job " + jobID + " does not yet have enough data " + "available for " + statName + " to generate a graph" + EOL); } else { try { // Generate the image tag. Replace any spaces with the '+' sign. String imageURI = servletBaseURI + '?' + Constants.SERVLET_PARAM_SECTION + '=' + Constants.SERVLET_SECTION_JOB + '&' + Constants.SERVLET_PARAM_SUBSECTION + '=' + Constants.SERVLET_SECTION_JOB_GRAPH_REAL_TIME + '&' + Constants.SERVLET_PARAM_JOB_ID + '=' + jobID + '&' + Constants.SERVLET_PARAM_GRAPH_WIDTH + '=' + widthParameter.getIntValue() + '&' + Constants.SERVLET_PARAM_GRAPH_HEIGHT + '=' + heightParameter.getIntValue() + '&' + Constants.SERVLET_PARAM_STAT_TRACKER + '=' + URLEncoder.encode(statsParameter.getStringValue(), "UTF-8"); htmlBody.append("<IMG SRC=\"" + imageURI.replace(' ', '+') + "\" WIDTH=\"" + widthParameter.getIntValue() + "\" HEIGHT=\"" + heightParameter.getIntValue() + "\" ALT=\"Graph of In-Progress Results for Job " + jobID + "\">" + EOL); } catch (Exception e) { slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(e)); } } htmlBody.append("<BR><BR>" + EOL); htmlBody.append("In-progress statistical data for this job was last " + "updated at " + displayDateFormat.format(new Date(updateTime)) + EOL); } /** * Handles the processing required to actually serve up the dynamically * generated images depicting information gathered in real-time. * * @param requestInfo The state information for this request. */ static void handleRealTimeGraph(RequestInfo requestInfo) { logMessage(requestInfo, "In handleRealTimeGraph()"); // The user must be able to view job information in order to see this if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); try { requestInfo.response.sendError(HttpServletResponse.SC_UNAUTHORIZED); } catch (Exception e) { e.printStackTrace(); } return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; HttpServletResponse response = requestInfo.response; // Get the job ID. If none was specified, then send back an error response. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (Exception e) {} return; } // Get the name of the stat for which to retrieve the data. String statName = request.getParameter(Constants.SERVLET_PARAM_STAT_TRACKER); if ((statName == null) || (statName.length() == 0)) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (Exception e) {} return; } // Get the data for the requested statistic. If an problem occurs, then // send back an error response. Job job; double[] statData; int startSeconds; try { job = scheduler.getJob(jobID); RealTimeJobStats stats = job.getRealTimeStats(); statData = stats.getStatValues(statName); startSeconds = stats.getFirstInterval(statName) * job.getCollectionInterval(); if ((statData == null) || (statData.length < 2)) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } } catch (Exception e) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (Exception e2) { e2.printStackTrace(); } return; } // Get the graph dimensions. int width = defaultGraphWidth; try { width = Integer.parseInt(request.getParameter( Constants.SERVLET_PARAM_GRAPH_WIDTH)); } catch (Exception e) { e.printStackTrace(); } int height = defaultGraphHeight; try { height = Integer.parseInt(request.getParameter( Constants.SERVLET_PARAM_GRAPH_HEIGHT)); } catch (Exception e) { e.printStackTrace(); } // Create the graph. StatGrapher grapher = new StatGrapher(width, height, "In-Progress Results for " + statName); grapher.addDataSet(statData, job.getCollectionInterval(), jobID); grapher.setBaseAtZero(true); grapher.setIncludeAverage(false); grapher.setIncludeRegression(false); grapher.setIncludeHorizontalGrid(true); grapher.setIncludeVerticalGrid(true); grapher.setVerticalAxisTitle(""); grapher.setStartSeconds(startSeconds); try { BufferedImage image = grapher.generateLineGraph(); response.setContentType("image/png"); response.addHeader("Content-Disposition", "filename=\"" + generateGraphFilename(job, statName) + '"'); ImageEncoder encoder = ImageCodec.createImageEncoder("png", response.getOutputStream(), null); encoder.encode(image); } catch (Exception e) { e.printStackTrace(); } } /** * Handles the processing required to display graphs that overlay two * different stat trackers. * * @param requestInfo The state information for this request. */ static void handleViewOverlay(RequestInfo requestInfo) { logMessage(requestInfo, "In handleViewOverlay()"); // The user must be able to view job information in order to see this if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "view job information"); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.htmlBody; // See if information has been posted for this graph. boolean posted = false; String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && (confirmStr.length() > 0)) { posted = true; } // Get the set of job IDs. There could be multiple, but we don't care // about that yet. If there are multiple, then just deal with the first // one. String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if ((jobIDs == null) || (jobIDs.length == 0)) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Job Results</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("No job ID was specified." + EOL); htmlBody.append("A job ID is required to indicate which job " + "contains the data to be graphed." + EOL); return; } String jobID; String link; if (jobIDs.length == 1) { jobID = "Job " + jobIDs[0]; link = "Job " + generateGetJobLink(requestInfo, jobIDs[0], jobIDs[0]); } else { jobID = "Multiple Jobs"; link = "Multiple Jobs"; } Job job; try { job = configDB.getJob(jobIDs[0]); if (job == null) { throw new SLAMDServerException("No information is known about job " + jobIDs[0]); } } catch (Exception e) { infoMessage.append("ERROR: " + e.getMessage() + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Results for " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Unable to retrieve job " + jobIDs[0] + "from the configuration directory." + EOL); htmlBody.append("See the error message above for additional " + "information." + EOL); return; } // Get the set of searchable statistics available for this job. Only // searchable statistics may be used in an overlay graph. ArrayList<String> nameList = new ArrayList<String>(); String[] trackerNames = job.getStatTrackerNames(); if ((trackerNames == null) || (trackerNames.length < 2)) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Results for " + link + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("The specified job does not contain enough statistical " + "data from which to generate a graph."); return; } for (int i=0; i < trackerNames.length; i++) { StatTracker[] trackers = job.getStatTrackers(trackerNames[i]); if ((trackers != null) && (trackers.length > 0) && trackers[0].isSearchable()) { nameList.add(trackerNames[i]); } } if (nameList.size() < 2) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Results for " + link + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("The specified job does not contain enough statistical " + "data from which to generate a graph."); return; } String[] graphableNames = new String[nameList.size()]; nameList.toArray(graphableNames); // Generate the common parameters that will be used for user input. BooleanParameter baseAtZeroParameter = new BooleanParameter(Constants.SERVLET_PARAM_BASE_AT_ZERO, "Base at Zero", "Indicates whether the lower bound for the " + "graph should be based at zero rather than " + "dynamically calculated from the information " + "contained in the data provided.", true); BooleanParameter includeLegendParameter = new BooleanParameter(Constants.SERVLET_PARAM_INCLUDE_LABELS, "Include Legend", "Indicates whether the graph generated should " + "include a legend.", false); BooleanParameter sameAxisParameter = new BooleanParameter(Constants.SERVLET_PARAM_GRAPH_USE_SAME_AXIS, "Graph on Same Axis", "Indicates whether the two statistics should " + "graphed on the same axis rather than separate " + "axes.", false); IntegerParameter widthParameter = new IntegerParameter(Constants.SERVLET_PARAM_GRAPH_WIDTH, "Graph Width", "The width in pixels of the graph to create", true, defaultGraphWidth, true, 0, false, 0); IntegerParameter heightParameter = new IntegerParameter(Constants.SERVLET_PARAM_GRAPH_HEIGHT, "Graph Height", "The height in pixels of the graph to create", true, defaultGraphHeight, true, 0, false, 0); MultiChoiceParameter leftParameter = new MultiChoiceParameter(Constants.SERVLET_PARAM_LEFT_TRACKER, "Left Axis Statistic", "The name of the stat tracker to graph " + "along the left axis.", graphableNames, graphableNames[0]); MultiChoiceParameter rightParameter = new MultiChoiceParameter(Constants.SERVLET_PARAM_RIGHT_TRACKER, "Right Axis Statistic", "The name of the stat tracker to graph " + "along the right axis.", graphableNames, graphableNames[1]); // Obtain the values that should be used for the common parameters. if (posted) { try { baseAtZeroParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + baseAtZeroParameter.getName())); } catch (Exception e) {} try { includeLegendParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + includeLegendParameter.getName())); } catch (Exception e) {} try { sameAxisParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + sameAxisParameter.getName())); } catch (Exception e) {} try { widthParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + widthParameter.getName())); } catch (Exception e) {} try { heightParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + heightParameter.getName())); } catch (Exception e) {} try { leftParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + leftParameter.getName())); } catch (Exception e) {} try { rightParameter.htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + rightParameter.getName())); } catch (Exception e) {} } // Generate the page header. htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Graph Results for " + link + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Choose the type of information to display." + EOL); htmlBody.append("<BR>" + EOL); // Generate the form that allows the user to specify the information htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_VIEW_OVERLAY) + EOL); for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + EOL); } htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_CONFIRMED, "1") + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + widthParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + widthParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + heightParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + heightParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + leftParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + leftParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + rightParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + rightParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + sameAxisParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + sameAxisParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + includeLegendParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + includeLegendParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + baseAtZeroParameter.getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + baseAtZeroParameter.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" " + "VALUE=\"View Graph\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>"); // Generate the image tag. Replace any spaces with the '+' sign. try { htmlBody.append("<BR><BR>" + EOL); String imageURI = servletBaseURI + '?' + Constants.SERVLET_PARAM_SECTION + '=' + Constants.SERVLET_SECTION_JOB + '&' + Constants.SERVLET_PARAM_SUBSECTION + '=' + Constants.SERVLET_SECTION_JOB_OVERLAY + '&'; for (int i=0; i < jobIDs.length; i++) { imageURI += Constants.SERVLET_PARAM_JOB_ID + '=' + jobIDs[i] + '&'; } imageURI += Constants.SERVLET_PARAM_GRAPH_WIDTH + '=' + widthParameter.getIntValue() + '&' + Constants.SERVLET_PARAM_GRAPH_HEIGHT + '=' + heightParameter.getIntValue() + '&' + Constants.SERVLET_PARAM_LEFT_TRACKER + '=' + URLEncoder.encode(leftParameter.getStringValue(), "UTF-8") + '&' + Constants.SERVLET_PARAM_RIGHT_TRACKER + '=' + URLEncoder.encode(rightParameter.getStringValue(), "UTF-8") + '&' + Constants.SERVLET_PARAM_GRAPH_USE_SAME_AXIS + '=' + sameAxisParameter.getValueString() + '&' + Constants.SERVLET_PARAM_INCLUDE_LABELS + '=' + includeLegendParameter.getValueString() + '&' + Constants.SERVLET_PARAM_BASE_AT_ZERO + '=' + baseAtZeroParameter.getValueString(); htmlBody.append("<IMG SRC=\"" + imageURI.replace(' ', '+') + "\" WIDTH=\"" + widthParameter.getIntValue() + "\" HEIGHT=\"" + heightParameter.getIntValue() + "\" ALT=\"Graph of Results for " + jobID + "\">" + EOL); } catch (Exception e) { slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(e)); } } /** * Handles the processing required to actually serve up the dynamically * generated overlay graphs depicting information gathered during job * processing. * * @param requestInfo The state information for this request. */ static void handleOverlay(RequestInfo requestInfo) { logMessage(requestInfo, "In handleOverlay()"); // The user must be able to view job information in order to see this if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); try { requestInfo.response.sendError(HttpServletResponse.SC_UNAUTHORIZED); } catch (Exception e) { e.printStackTrace(); } return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; HttpServletResponse response = requestInfo.response; // Get the graph parameters. int width = Constants.DEFAULT_GRAPH_WIDTH; try { width = Integer.parseInt(request.getParameter( Constants.SERVLET_PARAM_GRAPH_WIDTH)); } catch (Exception e) { e.printStackTrace(); } int height = Constants.DEFAULT_GRAPH_HEIGHT; try { height = Integer.parseInt(request.getParameter( Constants.SERVLET_PARAM_GRAPH_HEIGHT)); } catch (Exception e) { e.printStackTrace(); } boolean useSameAxis = false; try { String sameAxisStr = request.getParameter(Constants.SERVLET_PARAM_GRAPH_USE_SAME_AXIS); sameAxisStr = sameAxisStr.toLowerCase(); useSameAxis = (sameAxisStr.equals("true") || sameAxisStr.equals("yes") || sameAxisStr.equals("on") || sameAxisStr.equals("1")); } catch (Exception e) { e.printStackTrace(); } boolean includeLegend = false; try { String legendStr = request.getParameter(Constants.SERVLET_PARAM_INCLUDE_LABELS); legendStr = legendStr.toLowerCase(); includeLegend = (legendStr.equals("true") || legendStr.equals("yes") || legendStr.equals("on") || legendStr.equals("1")); } catch (Exception e) { e.printStackTrace(); } boolean baseAtZero = true; try { String baseAtZeroStr = request.getParameter(Constants.SERVLET_PARAM_BASE_AT_ZERO); baseAtZeroStr = baseAtZeroStr.toLowerCase(); baseAtZero = (! (baseAtZeroStr.equals("false") || baseAtZeroStr.equals("no") || baseAtZeroStr.equals("off") || baseAtZeroStr.equals("0"))); } catch (Exception e) { e.printStackTrace(); } String leftTrackerName = request.getParameter(Constants.SERVLET_PARAM_LEFT_TRACKER); String rightTrackerName = request.getParameter(Constants.SERVLET_PARAM_RIGHT_TRACKER); // Get the job IDs. If none were specified, then send back an error // response. If one was provided, then generate a regular graph. If // multiple job IDs were provided, then generate a graph comparing the // results of those jobs. String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if ((jobIDs == null) || (jobIDs.length == 0)) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (Exception e) {} return; } else if (jobIDs.length == 1) { String jobID = jobIDs[0]; Job job = null; try { job = configDB.getJob(jobID); } catch (Exception e) { e.printStackTrace(); } if (job == null) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (Exception e) { e.printStackTrace(); } return; } // Get the statistics to include on the left and right axes. StatTracker[] leftTrackers = job.getStatTrackers(leftTrackerName); StatTracker[] rightTrackers = job.getStatTrackers(rightTrackerName); if ((leftTrackers == null) || (leftTrackers.length == 0) || (rightTrackers == null) || (rightTrackers.length == 0)) { return; } // Aggregate the tracker data for the left and right trackers. StatTracker leftTracker = leftTrackers[0].newInstance(); leftTracker.aggregate(leftTrackers); StatTracker rightTracker = rightTrackers[0].newInstance(); rightTracker.aggregate(rightTrackers); // Get the values to include in the graph for the left and right // trackers. double[] leftData = leftTracker.getGraphData(); double[] rightData = rightTracker.getGraphData(); // Create and initialize the stat tracker. String caption = leftTracker.getDisplayName() + " and " + rightTracker.getDisplayName() + " for Job " + job.getJobID(); StatGrapher grapher = new StatGrapher(width, height, caption); grapher.setBaseAtZero(baseAtZero); grapher.setIncludeLegend(includeLegend, "Statistic"); // Generate the graph. try { BufferedImage image = grapher.generateDualLineGraph( leftTracker.getDisplayName(), leftTracker.getAxisLabel(), leftData, leftTracker.getCollectionInterval(), rightTracker.getDisplayName(), rightTracker.getAxisLabel(), rightData, rightTracker.getCollectionInterval(), useSameAxis, "Elapsed Time (seconds)", null); response.setContentType("image/png"); response.addHeader("Content-Disposition", "filename=\"" + generateGraphFilename(job, leftTracker, rightTracker) + '"'); ImageEncoder encoder = ImageCodec.createImageEncoder("png", response.getOutputStream(), null); encoder.encode(image); } catch (Exception e) { e.printStackTrace(); } } else { Job[] jobs = new Job[jobIDs.length]; for (int i=0; i < jobs.length; i++) { try { jobs[i] = configDB.getJob(jobIDs[i]); } catch (Exception e) { e.printStackTrace(); } if (jobs[i] == null) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (Exception e) { e.printStackTrace(); } return; } } // Get the data to be graphed for each job. double[] leftData = new double[jobs.length]; double[] rightData = new double[jobs.length]; String leftAxisTitle = ""; String rightAxisTitle = ""; for (int i=0; i < jobs.length; i++) { StatTracker[] trackers = jobs[i].getStatTrackers(leftTrackerName); if ((trackers == null) || (trackers.length == 0)) { leftData[i] = Double.NaN; } else { StatTracker tracker = trackers[0].newInstance(); tracker.aggregate(trackers); leftData[i] = tracker.getSummaryValue(); leftAxisTitle = tracker.getAxisLabel(); } trackers = jobs[i].getStatTrackers(rightTrackerName); if ((trackers == null) || (trackers.length == 0)) { rightData[i] = Double.NaN; } else { StatTracker tracker = trackers[0].newInstance(); tracker.aggregate(trackers); rightData[i] = tracker.getSummaryValue(); rightAxisTitle = tracker.getAxisLabel(); } } // Create and initialize the stat tracker. String caption = leftTrackerName + " and " + rightTrackerName; StatGrapher grapher = new StatGrapher(width, height, caption); grapher.setBaseAtZero(baseAtZero); grapher.setIncludeLegend(includeLegend, "Statistic"); grapher.setIgnoreZeroValues(true); // Generate the graph. try { BufferedImage image = grapher.generateDualLineGraph( leftTrackerName, leftAxisTitle, leftData, 1, rightTrackerName, rightAxisTitle, rightData, 1, useSameAxis, "Job Number", jobIDs); response.setContentType("image/png"); response.addHeader("Content-Disposition", "filename=\"" + generateGraphFilename(jobs, leftTrackerName, rightTrackerName) + '"'); ImageEncoder encoder = ImageCodec.createImageEncoder("png", response.getOutputStream(), null); encoder.encode(image); } catch (Exception e) { e.printStackTrace(); } } } /** * Constructs a filename that can be used for the name of a graph generated * from the provided job and stat tracker. * * @param job The job from which the graph is being generated. * @param tracker A stat tracker that provides information about the * statistic being graphed. * * @return The filename that can be used for the generated graph. */ static String generateGraphFilename(Job job, StatTracker tracker) { String nameStr = job.getJobName() + '_' + tracker.getDisplayName() + '_' + job.getJobID() + ".png"; nameStr = nameStr.replace(' ', '_').replace('/', '_').replace(',', '_'); return nameStr; } /** * Constructs a filename that can be used for the name of a graph generated * from the provided set of jobs and stat tracker. * * @param jobs The jobs from which the graph is being generated. * @param tracker A stat tracker that provides information about the * statistic being graphed. * * @return The filename that can be used for the generated graph. */ static String generateGraphFilename(Job[] jobs, StatTracker tracker) { String nameStr = jobs[0].getJobName() + "_comparison_of_" + tracker.getDisplayName() + ".png"; nameStr = nameStr.replace(' ', '_').replace('/', '_').replace(',', '_'); return nameStr; } /** * Constructs a filename that can be used for the name of a graph generated * from the provided job and stat trackers. * * @param job The job from which the graph is being generated. * @param tracker1 The first stat tracker included in the overlay graph. * @param tracker2 The second stat tracker included in the overlay graph. * * @return The filename that can be used for the generated graph. */ static String generateGraphFilename(Job job, StatTracker tracker1, StatTracker tracker2) { String nameStr = job.getJobName() + "_comparison_of_" + tracker1.getDisplayName() + "_and_" + tracker2.getDisplayName() + '_' + job.getJobID() + ".png"; nameStr = nameStr.replace(' ', '_').replace('/', '_').replace(',', '_'); return nameStr; } /** * Constructs a filename that can be used for the name of a graph generated * from the provided job and stat tracker names. * * @param jobs The jobs from which the graph is being generated. * @param trackerName1 The name of the first stat tracker included in the * overlay graph. * @param trackerName2 The name of the second stat tracker included in the * overlay graph. * * @return The filename that can be used for the generated graph. */ static String generateGraphFilename(Job[] jobs, String trackerName1, String trackerName2) { String nameStr = "multiple_" + jobs[0].getJobName() + "_jobs_comparison_of_" + trackerName1 + "_and_" + trackerName2 + ".png"; nameStr = nameStr.replace(' ', '_').replace('/', '_').replace(',', '_'); return nameStr; } /** * Constructs a filename that can be used for the name of a graph generated * from the provided job and stat name. * * @param job The job from which the graph is being generated. * @param statName The name of the statistic being graphed. * * @return The filename that can be used for the generated graph. */ static String generateGraphFilename(Job job, String statName) { String nameStr = job.getJobName() + '_' + statName + '_' + job.getJobID() + ".png"; nameStr = nameStr.replace(' ', '_').replace('/', '_').replace(',', '_'); return nameStr; } /** * Handles all processing related to scheduling a new job for execution. * * @param requestInfo The state information for this request. */ static void handleScheduleJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handleScheduleJob()"); // The user must be able to schedule new jobs to do anything here if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "schedule jobs for execution"); return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; StringBuilder htmlBody = requestInfo.htmlBody; // See if a job class name has been provided. If so, then generate a form // to schedule that job. If not, then allow the user to choose the job // class. String jobClassName = request.getParameter(Constants.SERVLET_PARAM_JOB_CLASS); if ((jobClassName == null) || (jobClassName.length() == 0)) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Schedule a New Job</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); JobClass[][] categorizedClasses = slamdServer.getCategorizedJobClasses(); if ((categorizedClasses != null) && (categorizedClasses.length > 0)) { htmlBody.append("Choose the type of job to schedule:" + EOL); htmlBody.append("<BR><BR>" + EOL); for (int i=0; i < categorizedClasses.length; i++) { String categoryName = categorizedClasses[i][0].getJobCategoryName(); if (categoryName == null) { categoryName = "Unclassified"; } htmlBody.append("<B>" + categoryName + " Job Classes</B><BR>" + EOL); htmlBody.append("<UL>" + EOL); for (int j=0; j < categorizedClasses[i].length; j++) { String[] names = { Constants.SERVLET_PARAM_JOB_CLASS }; String[] values = { categorizedClasses[i][j].getClass().getName() }; String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_SCHEDULE, names, values, categorizedClasses[i][j].getShortDescription(), categorizedClasses[i][j].getJobName()); htmlBody.append(" <LI>" + link + " (" + categorizedClasses[i][j].getClass().getName() + ")</LI>" + EOL); } htmlBody.append("</UL>" + EOL); htmlBody.append("<BR>" + EOL); } } else { htmlBody.append("No job classes have been defined in the SLAMD " + "server." + EOL); } } else { JobClass jobClass = slamdServer.getJobClass(jobClassName); if (jobClass == null) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Schedule a New Job</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Job class " + jobClassName + " is not defined in the SLAMD server." + EOL); } else { boolean showAdvanced = alwaysShowAdvancedOptions; boolean advancedClicked = false; String advStr = request.getParameter(Constants.SERVLET_PARAM_SHOW_ADVANCED); if ((advStr != null) && (advStr.length() > 0)) { advancedClicked = true; showAdvanced = true; } else if (alwaysShowAdvancedOptions) { advStr = "1"; } String validateStr = request.getParameter( Constants.SERVLET_PARAM_JOB_VALIDATE_SCHEDULE); if ((validateStr == null) || (validateStr.length() == 0) || ((advStr != null) && (! advStr.equals("1")))) { int numCopies = 1; String copyStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NUM_COPIES); if (copyStr != null) { try { numCopies = Integer.parseInt(copyStr); } catch (Exception e) {} } boolean makeInterDependent = false; String interDependStr = request.getParameter( Constants.SERVLET_PARAM_JOB_MAKE_INTERDEPENDENT); if (interDependStr != null) { makeInterDependent = (interDependStr.equalsIgnoreCase("true") || interDependStr.equalsIgnoreCase("yes") || interDependStr.equalsIgnoreCase("on") || interDependStr.equalsIgnoreCase("1")); } int delay = 0; String delayStr = request.getParameter( Constants.SERVLET_PARAM_TIME_BETWEEN_STARTUPS); if (delayStr != null) { try { delay = Integer.parseInt(delayStr); } catch (Exception e) {} } String descStr = request.getParameter( Constants.SERVLET_PARAM_JOB_DESCRIPTION); Date startTime = null; String startTimeStr = request.getParameter( Constants.SERVLET_PARAM_JOB_START_TIME); if (startTimeStr != null) { try { startTime = dateFormat.parse(startTimeStr); } catch (Exception e) {} } Date stopTime = null; String stopTimeStr = request.getParameter( Constants.SERVLET_PARAM_JOB_STOP_TIME); if (stopTimeStr != null) { try { stopTime = dateFormat.parse(stopTimeStr); } catch (Exception e) {} } int duration = -1; String durationStr = request.getParameter( Constants.SERVLET_PARAM_JOB_DURATION); if (durationStr != null) { try { duration = DurationParser.parse(durationStr); } catch (Exception e) {} } int numClients = -1; String numClientsStr = request.getParameter( Constants.SERVLET_PARAM_JOB_NUM_CLIENTS); if (numClientsStr != null) { try { numClients = Integer.parseInt(numClientsStr); } catch (Exception e) {} } int numThreads = -1; String threadStr = request.getParameter( Constants.SERVLET_PARAM_JOB_THREADS_PER_CLIENT); if (threadStr != null) { try { numThreads = Integer.parseInt(threadStr); } catch (Exception e) {} } int threadStartupDelay = 0; threadStr = request.getParameter( Constants.SERVLET_PARAM_JOB_THREAD_STARTUP_DELAY); if (threadStr != null) { try { threadStartupDelay = Integer.parseInt(threadStr); } catch (Exception e) {} } String clientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_CLIENTS); String[] clients; if ((clientsStr == null) || (clientsStr.length() == 0)) { clients = new String[0]; } else { ArrayList<String> clientList = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(clientsStr); while (tokenizer.hasMoreTokens()) { clientList.add(tokenizer.nextToken()); } clients = new String[clientList.size()]; clientList.toArray(clients); } clientsStr = request.getParameter( Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS); String[] monitorClients; if ((clientsStr == null) || (clientsStr.length() == 0)) { monitorClients = new String[0]; } else { ArrayList<String> clientList = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(clientsStr); while (tokenizer.hasMoreTokens()) { clientList.add(tokenizer.nextToken()); } monitorClients = new String[clientList.size()]; clientList.toArray(monitorClients); } boolean monitorClientsIfAvailable = false; String monitorStr = request.getParameter( Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS_IF_AVAILABLE); if (monitorStr != null) { monitorClientsIfAvailable = (monitorStr.equals("1") || monitorStr.equalsIgnoreCase("true") || monitorStr.equalsIgnoreCase("yes") || monitorStr.equalsIgnoreCase("on")); } boolean waitForClients; if (validateStr == null) { waitForClients = true; String waitStr = request.getParameter( Constants.SERVLET_PARAM_JOB_WAIT_FOR_CLIENTS); if (waitStr != null) { waitForClients = (! (waitStr.equals("0") || waitStr.equalsIgnoreCase("false") || waitStr.equalsIgnoreCase("off") || waitStr.equalsIgnoreCase("no"))); } else { waitForClients = true; } } else { waitForClients = false; String waitStr = request.getParameter( Constants.SERVLET_PARAM_JOB_WAIT_FOR_CLIENTS); if (waitStr != null) { waitForClients = (waitStr.equals("1") || waitStr.equalsIgnoreCase("true") || waitStr.equalsIgnoreCase("on") || waitStr.equalsIgnoreCase("yes")); } else { waitForClients = false; } } String[] dependencyIDs = request.getParameterValues( Constants.SERVLET_PARAM_JOB_DEPENDENCY); String[] notifyAddresses; String notifyAddressStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NOTIFY_ADDRESS); if ((notifyAddressStr == null) || (notifyAddressStr.length() == 0)) { notifyAddresses = new String[0]; } else { ArrayList<String> addressList = new ArrayList<String>(); StringTokenizer st = new StringTokenizer(notifyAddressStr, ", "); while (st.hasMoreTokens()) { addressList.add(st.nextToken()); } notifyAddresses = new String[addressList.size()]; addressList.toArray(notifyAddresses); } int collectionInterval = -1; String intervalStr = request.getParameter( Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL); if (intervalStr != null) { try { collectionInterval = DurationParser.parse(intervalStr); } catch (Exception e) {} } String disabledStr = request.getParameter(Constants.SERVLET_PARAM_JOB_DISABLED); boolean jobDisabled = ((disabledStr != null) && (disabledStr.equalsIgnoreCase("true") || disabledStr.equalsIgnoreCase("on") || disabledStr.equalsIgnoreCase("yes") || disabledStr.equalsIgnoreCase("1"))); String displayStr = request.getParameter( Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY); boolean displayInReadOnlyMode = false; if (displayStr != null) { displayInReadOnlyMode = displayStr.equalsIgnoreCase("true") || displayStr.equalsIgnoreCase("yes") || displayStr.equalsIgnoreCase("on") || displayStr.equalsIgnoreCase("1"); } String comments = request.getParameter(Constants.SERVLET_PARAM_JOB_COMMENTS); Parameter[] jobParams = jobClass.getParameterStubs().clone().getParameters(); for (int i=0; i < jobParams.length; i++) { try { String[] values = request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + jobParams[i].getName()); if (values != null) { jobParams[i].htmlInputFormToValue(values); } else if (advancedClicked && (jobParams[i] instanceof BooleanParameter)) { // This means that the form was posted and the box was not // checked, so make sure the parameter has a value of "false". ((BooleanParameter) jobParams[i]).setValue(false); } } catch (Exception e) {} } generateScheduleJobForm(requestInfo, jobClass, numCopies, makeInterDependent, delay, null, descStr, startTime, stopTime, duration, numClients, numThreads, threadStartupDelay, clients, monitorClients, monitorClientsIfAvailable, waitForClients, dependencyIDs, notifyAddresses, collectionInterval, comments, jobDisabled, displayInReadOnlyMode, new ParameterList(jobParams)); } else { validateJobInfo(requestInfo); } } } } /** * Handles all processing required to be able to clone a job (i.e., schedule * a new job using the settings taken from an existing job). * * @param requestInfo The state information for this request. */ static void handleCloneJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handleCloneJob()"); // The user must be able to schedule new jobs to do anything here if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "schedule jobs for execution"); return; } // Get the important state variables. HttpServletRequest request = requestInfo.request; StringBuilder infoMessage = requestInfo.infoMessage; // See if a job ID has been specified. If not, then just treat it like // scheduling a new job. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { handleScheduleJob(requestInfo); } else { // See if the specified job exists. If so, then use information from // it. If not, then set an info message and schedule a new job. try { Job job = scheduler.getJob(jobID); if (job == null) { infoMessage.append("Unable to retrieve information about job " + jobID + "<BR>" + EOL); handleScheduleJob(requestInfo); } else { generateScheduleJobForm(requestInfo, job.getJobClass(), 1, false, 0, job.getFolderName(), job.getJobDescription(), null, null, job.getDuration(), job.getNumberOfClients(), job.getThreadsPerClient(), job.getThreadStartupDelay(), job.getRequestedClients(), job.getResourceMonitorClients(), job.monitorClientsIfAvailable(), job.waitForClients(), null, job.getNotifyAddresses(), job.getCollectionInterval(), job.getJobComments(), false, job.displayInReadOnlyMode(), job.getParameterList()); } } catch (SLAMDServerException sse) { infoMessage.append("Unable to retrieve information about job " + jobID + ": " + sse.getMessage() + "<BR>" + EOL); handleScheduleJob(requestInfo); } } } /** * Generates the HTML form that may be used to specify all of the necessary * information required to schedule a new job for execution. If any * information is provided through the arguments to this method, then the * form fields will be populated with the relevant information. * * @param requestInfo The state information for this request. * @param jobClass The Java class that is to be used to run * the job. * @param numCopies The number of copies to make of the * scheduled job. * @param makeInterDependent Indicates whether to make multiple * copies of the job interdependent. * @param delayBetweenStarts The delay in seconds between the start * of one job from the start of the next * copy. * @param folderName The name of the folder in which this job * should be placed by default. * @param jobDescription A freeform text description that can * provide additional information about the * purpose of this job. * @param startTime The time at which the job should start * running. * @param stopTime The time at which the job should stop * running. * @param duration The maximum length of time in seconds * that the job should be allowed to run. * @param numClients The number of clients on which the job * should be run. * @param threadsPerClient The number of threads to create on each * client to process the job. * @param threadStartupDelay The delay in milliseconds that should be * used between starting the individual * threads on the client. * @param clients The set of clients that have been * requested for the job. * @param monitorClients The set of resource monitor clients that * have been requested for the job. * @param monitorClientsIfAvailable Indicates whether to automatically * monitor systems used to run job clients * if resource monitor clients are * available. * @param waitForClients Indicates whether the scheduler should * wait for a sufficient set of clients to * become available before trying to start * the job. * @param dependencyIDs The job IDs of any jobs that must be * completed before this job may be * started. * @param notifyAddresses The e-mail addresses of the users to * notify when the job has been completed. * @param collectionInterval The length of time in seconds that will * be used as the statistics collection * interval. * @param comments A set of comments to use for the job. * @param jobDisabled Indicates whether the job should be * disabled when it is scheduled. * @param displayInReadOnlyMode Indicates whether the job should be made * visible if the server is operating in * restricted read-only mode. * @param parameters The set of parameters with information * that is to be used during job * processing. */ static void generateScheduleJobForm(RequestInfo requestInfo, JobClass jobClass, int numCopies, boolean makeInterDependent, int delayBetweenStarts, String folderName, String jobDescription, Date startTime, Date stopTime, int duration, int numClients, int threadsPerClient, int threadStartupDelay, String[] clients, String[] monitorClients, boolean monitorClientsIfAvailable, boolean waitForClients, String[] dependencyIDs, String[] notifyAddresses, int collectionInterval, String comments, boolean jobDisabled, boolean displayInReadOnlyMode, ParameterList parameters) { logMessage(requestInfo, "In generateScheduleJobForm(" + jobClass.getJobName() + ')'); // Get the important state information for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; // See if the job class is deprecated. If so, then add a warning message at // the top of the page. StringBuilder deprecatedMessage = new StringBuilder(); if (jobClass.isDeprecated(deprecatedMessage)) { StringBuilder infoMessage = requestInfo.infoMessage; infoMessage.append("WARNING: This job class has been deprecated."); if (deprecatedMessage.length() > 0) { infoMessage.append(" "); infoMessage.append(deprecatedMessage); } infoMessage.append("<BR><BR>" + EOL); } String star = "<SPAN CLASS=\"" + Constants.STYLE_WARNING_TEXT + "\">*</SPAN>"; htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Schedule a New \"" + jobClass.getJobName() + "\" Job</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); for (String s : jobClass.getLongDescription()) { htmlBody.append(s + EOL); htmlBody.append("<BR><BR>" + EOL); } htmlBody.append("Enter the following information about the " + jobClass.getJobName() + " job." + EOL); htmlBody.append("Note that parameters marked with an asterisk (" + star + ") are required to have a value." + EOL); String link = generateNewWindowLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_SCHEDULE_HELP, Constants.SERVLET_PARAM_JOB_CLASS, jobClass.getClass().getName(), "Click here for help regarding these parameters"); htmlBody.append(link + '.' + EOL); htmlBody.append("<BR><BR>" + EOL); // See if we should show the advanced scheduling info. boolean showAdvanced = alwaysShowAdvancedOptions; String advancedStr = request.getParameter(Constants.SERVLET_PARAM_SHOW_ADVANCED); if ((advancedStr != null) && (advancedStr.length() > 0)) { showAdvanced = true; } int jobNumClients = jobClass.overrideNumClients(); int jobNumThreads = jobClass.overrideThreadsPerClient(); int jobInterval = jobClass.overrideCollectionInterval(); htmlBody.append("<FORM CLASS=\"" + Constants.STYLE_MAIN_FORM + "\" METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_SCHEDULE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_CLASS, jobClass.getClass().getName()) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_VALIDATE_SCHEDULE, "1") + EOL); if (jobNumClients > 0) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_NUM_CLIENTS, String.valueOf(jobNumClients)) + EOL); } if (jobNumThreads > 0) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_THREADS_PER_CLIENT, String.valueOf(jobNumThreads)) + EOL); } if (jobInterval > 0) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL, secondsToHumanReadableDuration(jobInterval)) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } if (showAdvanced) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SHOW_ADVANCED, "1") + EOL); } else { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_NUM_COPIES, String.valueOf(numCopies)) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_MAKE_INTERDEPENDENT, String.valueOf(makeInterDependent)) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_TIME_BETWEEN_STARTUPS, String.valueOf(delayBetweenStarts)) + EOL); StringBuilder clientBuffer = new StringBuilder(); String separator = ""; for (int i=0; ((clients != null) && (i < clients.length)); i++) { clientBuffer.append(separator); clientBuffer.append(clients[i]); separator = " "; } htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_CLIENTS, clientBuffer.toString()) + EOL); StringBuilder monitorClientBuffer = new StringBuilder(); separator = ""; for (int i=0; ((monitorClients != null) && (i < monitorClients.length)); i++) { monitorClientBuffer.append(separator); monitorClientBuffer.append(monitorClients[i]); separator = " "; } htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS, monitorClientBuffer.toString()) + EOL); if ((notifyAddresses != null) && (notifyAddresses.length > 0)) { String notifyStr = notifyAddresses[0]; for (int i=1; i < notifyAddresses.length; i++) { notifyStr += ", " + notifyAddresses[i]; } htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_NOTIFY_ADDRESS, notifyStr) + EOL); } htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_THREAD_STARTUP_DELAY, String.valueOf(threadStartupDelay)) + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SHOW_ADVANCED + "\" VALUE=\"Show Advanced Scheduling Options\">" + "<BR>" + EOL); } htmlBody.append("<TABLE BORDER=\"0\">" + EOL); if (showAdvanced) { // Indicate whether the job should be disabled. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Is Disabled</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DISABLED + '"' + (jobDisabled ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Indicate whether the job should be displayed in restricted read-only // mode. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Display In Read-Only Mode</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY + '"' + (displayInReadOnlyMode ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of copies. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Number of Copies</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_NUM_COPIES + "\" VALUE=\"" + numCopies + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to make copies interdependent. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Make Copies Interdependent</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_MAKE_INTERDEPENDENT + '"' + (makeInterDependent ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The delay between the start of each copy. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Time Between Copy Startups</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_TIME_BETWEEN_STARTUPS + "\" VALUE=\"" + delayBetweenStarts + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The name of the folder in which the job should be placed. JobFolder[] folders = null; try { folders = configDB.getFolders(); } catch (DatabaseException de) {} if ((folders != null) && (folders.length > 0)) { if (folderName == null) { folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Place in Folder</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_FOLDER + "\">" + EOL); for (int i=0; i < folders.length; i++) { if ((folderName != null) && folderName.equalsIgnoreCase(folders[i].getFolderName())) { htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + "\" SELECTED>" + folders[i].getFolderName() + EOL); } else { htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + "\">" + folders[i].getFolderName() + EOL); } } htmlBody.append(" </SELECT>"); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The job description String value = jobDescription; if (value == null) { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DESCRIPTION + "\" VALUE=\"" + value + "\" SIZE=\"80\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The start time if (startTime != null) { value = dateFormat.format(startTime); } else { if (populateStartTime) { value = dateFormat.format(new Date()); } else { value = ""; } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Start Time <FONT SIZE=\"-1\">(YYYYMMDDhhmmss)" + "</FONT></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_START_TIME + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The stop time if (stopTime != null) { value = dateFormat.format(stopTime); } else { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Stop Time <FONT SIZE=\"-1\">(YYYYMMDDhhmmss)" + "</FONT></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_STOP_TIME + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The duration if (duration > 0) { value = secondsToHumanReadableDuration(duration); } else { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Duration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DURATION + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of clients if (jobNumClients <= 0) { if (numClients > 0) { value = String.valueOf(numClients); } else { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Number of Clients " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_NUM_CLIENTS + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // Specific clients to use. if (showAdvanced) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Use Specific Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_CLIENTS + "\" ROWS=\"5\"" + " COLS=\"40\">"); String separator = ""; for (int i=0; ((clients != null) && (i < clients.length)); i++) { htmlBody.append(separator); htmlBody.append(clients[i]); separator = EOL; } htmlBody.append("</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Resource monitor clients to use. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Resource Monitor Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS + "\" ROWS=\"5\"" + " COLS=\"40\">"); separator = ""; for (int i=0; ((monitorClients != null) && (i < monitorClients.length)); i++) { htmlBody.append(separator); htmlBody.append(monitorClients[i]); separator = EOL; } htmlBody.append("</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // Whether to automatically monitor client systems if available. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Monitor Clients if Available</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS_IF_AVAILABLE + '"' + (monitorClientsIfAvailable ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to wait for clients to be available. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Wait for Available Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_WAIT_FOR_CLIENTS + '"' + (waitForClients ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of threads per client if (jobNumThreads <= 0) { if (threadsPerClient > 0) { value = String.valueOf(threadsPerClient); } else { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Threads per Client " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREADS_PER_CLIENT + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } if (showAdvanced) { // The thread startup delay htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Thread Startup Delay (ms)</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREAD_STARTUP_DELAY + "\" VALUE=\"" + threadStartupDelay + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job dependencies Job[] pendingJobs = scheduler.getPendingJobs(); Job[] runningJobs = scheduler.getRunningJobs(); OptimizingJob[] optimizingJobs = new OptimizingJob[0]; try { optimizingJobs = scheduler.getUncompletedOptimizingJobs(); } catch (SLAMDServerException sse) { requestInfo.infoMessage.append("ERROR: Unable to retrieve the list " + "of uncompleted optimizing jobs -- " + sse + "<BR>" + EOL); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Dependencies</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); for (int i=0; ((dependencyIDs != null) && (i < dependencyIDs.length)); i++) { if ((dependencyIDs[i] == null) || (dependencyIDs[i].length() == 0)) { continue; } htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_DEPENDENCY + "\">" + EOL); Job dependentJob = null; try { dependentJob = configDB.getJob(dependencyIDs[i]); } catch (Exception e) {} if (dependentJob == null) { htmlBody.append(" <OPTION VALUE=\"" + dependencyIDs[i] + "\">" + dependencyIDs[i] + " -- Unknown Job" + EOL); } else { String description = dependentJob.getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + dependencyIDs[i] + "\">" + dependencyIDs[i] + " -- " + dependentJob.getJobName() + description + EOL); } htmlBody.append(" <OPTION VALUE=\"\">No Dependency" + EOL); for (int j=0; j < pendingJobs.length; j++) { String description = pendingJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + pendingJobs[j].getJobID() + "\">" + pendingJobs[j].getJobID() + " -- Pending " + pendingJobs[j].getJobName() + description + EOL); } for (int j=0; j < runningJobs.length; j++) { String description = runningJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + runningJobs[j].getJobID() + "\">" + runningJobs[j].getJobID() + " -- Running " + runningJobs[j].getJobName() + description + EOL); } for (int j=0; j < optimizingJobs.length; j++) { String description = optimizingJobs[j].getDescription(); if (description == null) { description = ""; } else { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + optimizingJobs[j].getOptimizingJobID() + "\">" + optimizingJobs[j].getOptimizingJobID() + " -- Optimizing " + optimizingJobs[j].getJobClass().getJobName() + description + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" <BR>" + EOL); } htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_DEPENDENCY + "\">" + EOL); htmlBody.append(" <OPTION VALUE=\"\">No Dependency" + EOL); for (int j=0; j < pendingJobs.length; j++) { String description = pendingJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + pendingJobs[j].getJobID() + "\">" + pendingJobs[j].getJobID() + " -- Pending " + pendingJobs[j].getJobName() + description + EOL); } for (int j=0; j < runningJobs.length; j++) { String description = runningJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + runningJobs[j].getJobID() + "\">" + runningJobs[j].getJobID() + " -- Running " + runningJobs[j].getJobName() + description + EOL); } for (int j=0; j < optimizingJobs.length; j++) { String description = optimizingJobs[j].getDescription(); if (description == null) { description = ""; } else { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + optimizingJobs[j].getOptimizingJobID() + "\">" + optimizingJobs[j].getOptimizingJobID() + " -- Optimizing " + optimizingJobs[j].getJobClass().getJobName() + description + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); if (slamdServer.getMailer().isEnabled()) { // The e-mail addresses of the users to notify upon completion. if ((notifyAddresses == null) || (notifyAddresses.length == 0)) { value = ""; } else { value = notifyAddresses[0]; for (int i=1; i < notifyAddresses.length; i++) { value += ", " + notifyAddresses[i]; } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Notify on Completion</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_NOTIFY_ADDRESS + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } // The collection interval if (jobInterval <= 0) { if (collectionInterval > 0) { value = secondsToHumanReadableDuration(collectionInterval); } else { value = secondsToHumanReadableDuration( Constants.DEFAULT_COLLECTION_INTERVAL); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Statistics Collection Interval</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // Get the job-specific parameters. Note that the provided set of // parameters may not be the entire set that can be used, so use the // parameter stubs as the base Parameter[] stubs = jobClass.getParameterStubs().clone().getParameters(); for (int i=0; i < stubs.length; i++) { if (parameters != null) { Parameter p = parameters.getParameter(stubs[i].getName()); if (p != null) { stubs[i].setValueFrom(p); } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><A CLASS=\"" + Constants.STYLE_FORM_CAPTION + "\" TITLE=\"" + stubs[i].getDescription() + "\">" + stubs[i].getDisplayName() + (stubs[i].isRequired() ? ' ' + star : "") + "</A></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + stubs[i].getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The job comments if (comments == null) { comments = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Comments</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_COMMENTS + "\" ROWS=\"5\" " + "COLS=\"80\">" + comments + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The "Test Job Parameters" and "Schedule Job" buttons htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); if (jobClass.providesParameterTest()) { htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_TEST_PARAMS + "\">" + EOL); htmlBody.append("    " + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_SCHEDULE_JOB + "\">" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append("</TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } /** * Parses the request parameters provided from submitting the "schedule a new * job" form and verifies that all the necessary information has been provided * and that it is valid. If there are any problems, then it will provide * information on what those problems are and will display the form again to * allow the user to correct these problems. If everything is OK, then the * job will be scheduled for execution. * * @param requestInfo The state information for this request. */ static void validateJobInfo(RequestInfo requestInfo) { logMessage(requestInfo, "In validateJobInfo()"); // If the user doesn't have schedule permission, then they can't see this if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "schedule jobs for execution."); return; } HttpServletRequest request = requestInfo.request; StringBuilder infoMessage = requestInfo.infoMessage; boolean displayInReadOnlyMode = false; boolean jobDisabled = false; boolean jobIsValid = true; boolean makeInterDependent = false; boolean monitorClientsIfAvailable = false; boolean waitForClients = false; Date startTime = null; Date stopTime = null; int delayBetweenStarts = 0; int duration = -1; int numCopies = 1; int numClients = -1; int threadsPerClient = -1; int threadStartupDelay = 0; int collectionInterval = Constants.DEFAULT_COLLECTION_INTERVAL; String folderName = null; String jobComments = null; String[] dependencyIDs = null; String[] notifyAddresses = null; String[] requestedClients = null; String[] monitorClients = null; JobClass jobClass = null; // Handle the job class String jobClassName = request.getParameter(Constants.SERVLET_PARAM_JOB_CLASS); if ((jobClassName == null) || (jobClassName.length() == 0)) { infoMessage.append("ERROR: No job class specified.<BR>" + EOL); handleScheduleJob(requestInfo); return; } jobClass = slamdServer.getJobClass(jobClassName); if (jobClass == null) { infoMessage.append("ERROR: Could not find job class " + jobClassName + ".<BR>" + EOL); handleScheduleJob(requestInfo); return; } // See if the job is disabled. String disabledStr = request.getParameter(Constants.SERVLET_PARAM_JOB_DISABLED); jobDisabled = ((disabledStr != null) && (disabledStr.equalsIgnoreCase("true") || disabledStr.equalsIgnoreCase("on") || disabledStr.equalsIgnoreCase("yes") || disabledStr.equalsIgnoreCase("1"))); // See if the job should be displayed in restricted read-only mode. String displayStr = request.getParameter(Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY); if (displayStr != null) { displayInReadOnlyMode = (displayStr.equalsIgnoreCase("true") || displayStr.equalsIgnoreCase("yes") || displayStr.equalsIgnoreCase("on") || displayStr.equalsIgnoreCase("1")); } // Handle the number of copies of the job to create. String numCopiesStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NUM_COPIES); if (numCopiesStr != null) { try { numCopies = Integer.parseInt(numCopiesStr); } catch (NumberFormatException nfe) { infoMessage.append("ERROR: Number of copies must be an integer<BR>" + EOL); jobIsValid = false; } } // Determine whether to make the copies interdependent. String interDependStr = request.getParameter( Constants.SERVLET_PARAM_JOB_MAKE_INTERDEPENDENT); if (interDependStr != null) { makeInterDependent = (interDependStr.equalsIgnoreCase("true") || interDependStr.equalsIgnoreCase("yes") || interDependStr.equalsIgnoreCase("on") || interDependStr.equalsIgnoreCase("1")); } // Handle the time between job starts. String timeStr = request.getParameter(Constants.SERVLET_PARAM_TIME_BETWEEN_STARTUPS); if (timeStr != null) { try { delayBetweenStarts = Integer.parseInt(timeStr); } catch (NumberFormatException nfe) { infoMessage.append("ERROR: Time between job startups must be an " + "integer<BR>" + EOL); jobIsValid = false; } } // Handle the job folder name. No need to validate here -- if it doesn't // exist, then it will fail later. folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); // Handle the job description. No validation is required for this one. String jobDescription = request.getParameter(Constants.SERVLET_PARAM_JOB_DESCRIPTION); // Handle the start time String startTimeStr = request.getParameter(Constants.SERVLET_PARAM_JOB_START_TIME); if ((startTimeStr == null) || (startTimeStr.length() == 0)) { startTime = new Date(); } else { if (startTimeStr.length() != Constants.ATTRIBUTE_DATE_FORMAT.length()) { infoMessage.append("ERROR: Start time string must be " + Constants.ATTRIBUTE_DATE_FORMAT.length() + " digits in length (YYYYMMDDhhmmss).<BR>" + EOL); jobIsValid = false; } else { try { startTime = dateFormat.parse(startTimeStr); } catch (Exception e) { infoMessage.append("ERROR: Start time string could not be " + "interpreted as a timestamp. It must be in the " + "form YYYYMMDDhhmmss.<BR>" + EOL); jobIsValid = false; } } } // Handle the stop time String stopTimeStr = request.getParameter(Constants.SERVLET_PARAM_JOB_STOP_TIME); if ((stopTimeStr != null) && (stopTimeStr.length() > 0)) { if (stopTimeStr.length() != Constants.ATTRIBUTE_DATE_FORMAT.length()) { infoMessage.append("ERROR: Stop time string must be " + Constants.ATTRIBUTE_DATE_FORMAT.length() + " digits in length (YYYYMMDDhhmmss).<BR>" + EOL); jobIsValid = false; } else { try { stopTime = dateFormat.parse(stopTimeStr); } catch (Exception e) { infoMessage.append("ERROR: Stop time string could not be " + "interpreted as a timestamp. It must be in the " + "form YYYYMMDDhhmmss.<BR>" + EOL); jobIsValid = false; } } } // Handle the duration String durationStr = request.getParameter(Constants.SERVLET_PARAM_JOB_DURATION); if ((durationStr != null) && (durationStr.length() > 0)) { try { duration = DurationParser.parse(durationStr); } catch (SLAMDException se) { infoMessage.append("ERROR: " + se.getMessage() + "<BR>" + EOL); jobIsValid = false; } } // Handle the number of clients. String numClientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NUM_CLIENTS); if ((numClientsStr != null) && (numClientsStr.length() > 0)) { try { numClients = Integer.parseInt(numClientsStr); } catch (NumberFormatException nfe) { infoMessage.append("ERROR: Number of clients string could not be " + "interpreted as an integer.<BR>" + EOL); jobIsValid = false; } } else { infoMessage.append("ERROR: Number of clients not specified.<BR>" + EOL); jobIsValid = false; } // Handle the set of requested clients. String requestedClientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_CLIENTS); if ((requestedClientsStr != null) && (requestedClientsStr.length() > 0)) { ArrayList<String> clientList = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(requestedClientsStr); while (tokenizer.hasMoreTokens()) { // Convert each client address to an IP address. This makes it possible // to allow for multiple names to refer to a single client. If a client // address can't be resolved, then report an error back to the client. String token = tokenizer.nextToken(); try { InetAddress clientAddress = InetAddress.getByName(token); clientList.add(clientAddress.getHostAddress()); } catch (UnknownHostException uhe) { infoMessage.append("ERROR: Could not resolve \"" + token + "\" as a valid address.<BR>" + EOL); jobIsValid = false; } } if (! clientList.isEmpty()) { requestedClients = new String[clientList.size()]; clientList.toArray(requestedClients); if (requestedClients.length > numClients) { infoMessage.append("ERROR: Requested set of clients contains more " + "than the specified number of clients.<BR>" + EOL); jobIsValid = false; } } } // Handle the set of resource monitor clients. String monitorClientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS); if ((monitorClientsStr != null) && (monitorClientsStr.length() > 0)) { ArrayList<String> clientList = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(monitorClientsStr); while (tokenizer.hasMoreTokens()) { // Convert each client address to an IP address. This makes it possible // to allow for multiple names to refer to a single client. If a client // address can't be resolved, then report an error back to the client. String token = tokenizer.nextToken(); try { InetAddress clientAddress = InetAddress.getByName(token); // See if the address is already present in the list. if so, then // don't add it a second time and display a warning to the user. String ipAddress = clientAddress.getHostAddress(); if (clientList.contains(ipAddress)) { infoMessage.append("WARNING: Ignoring duplicate reference to " + "resource monitor client " + token + "<BR>." + EOL); continue; } clientList.add(ipAddress); } catch (UnknownHostException uhe) { infoMessage.append("ERROR: Could not resolve \"" + token + "\" as a valid address<BR>." + EOL); jobIsValid = false; } } if (! clientList.isEmpty()) { monitorClients = new String[clientList.size()]; clientList.toArray(monitorClients); } } // Handle the number of threads per client String threadsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_THREADS_PER_CLIENT); if ((threadsStr != null) && (threadsStr.length() > 0)) { try { threadsPerClient = Integer.parseInt(threadsStr); } catch (NumberFormatException nfe) { infoMessage.append("ERROR: Number of threads per client could not " + "be interpreted as an integer.<BR>" + EOL); jobIsValid = false; } } else { infoMessage.append("ERROR: Number of threads per client not " + "specified.<BR>" + EOL); jobIsValid = false; } // Handle the thread startup delay String delayStr = request.getParameter(Constants.SERVLET_PARAM_JOB_THREAD_STARTUP_DELAY); if ((delayStr != null) && (delayStr.length() > 0)) { try { threadStartupDelay = Integer.parseInt(delayStr); } catch (NumberFormatException nfe) { infoMessage.append("ERROR: Thread startup delay must be an " + "integer.<BR>" + EOL); jobIsValid = false; } } // Handle the determination to wait for available clients. String waitStr = request.getParameter(Constants.SERVLET_PARAM_JOB_WAIT_FOR_CLIENTS); if ((waitStr != null) && (waitStr.length() > 0)) { waitForClients = (waitStr.equalsIgnoreCase("true") || waitStr.equalsIgnoreCase("on") || waitStr.equalsIgnoreCase("yes") || waitStr.equals("1")); } // Handle the determination to automatically monitor available clients. String monitorStr = request.getParameter( Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS_IF_AVAILABLE); if ((monitorStr != null) && (monitorStr.length() > 0)) { monitorClientsIfAvailable = (monitorStr.equalsIgnoreCase("true") || monitorStr.equalsIgnoreCase("on") || monitorStr.equalsIgnoreCase("yes") || monitorStr.equals("1")); } // Handle the list of dependency IDs. dependencyIDs = request.getParameterValues( Constants.SERVLET_PARAM_JOB_DEPENDENCY); // Handle the notify addresses. String notifyAddressStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NOTIFY_ADDRESS); if ((notifyAddressStr == null) || (notifyAddressStr.length() == 0)) { notifyAddresses = new String[0]; } else { ArrayList<String> addressList = new ArrayList<String>(); StringTokenizer st = new StringTokenizer(notifyAddressStr, ", "); while (st.hasMoreTokens()) { addressList.add(st.nextToken()); } notifyAddresses = new String[addressList.size()]; addressList.toArray(notifyAddresses); } // Handle the collection interval. String intervalStr = request.getParameter(Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL); if ((intervalStr != null) && (intervalStr.length() > 0)) { try { collectionInterval = DurationParser.parse(intervalStr); if (collectionInterval <= 0) { infoMessage.append("ERROR: Statistics collection interval must be " + "greater than zero.<BR>" + EOL); jobIsValid = false; } } catch (SLAMDException se) { infoMessage.append("ERROR: " + se.getMessage() + "<BR>" + EOL); jobIsValid = false; } } // Figure out how long the job is scheduled to run. If it is less than // or equal to the collection interval, then complain about it. if ((duration > 0) && (duration <= collectionInterval)) { infoMessage.append("ERROR: Statistics collection interval must be " + "less than the scheduled job duration.<BR>" + EOL); jobIsValid = false; } else if (stopTime != null) { long startTimeMillis = startTime.getTime(); long stopTimeMillis = stopTime.getTime(); long durationMillis = (stopTimeMillis - startTimeMillis); long durationSecs = durationMillis / 1000; if (durationSecs <= collectionInterval) { infoMessage.append("ERROR: The difference between the scheduled " + "start and stop times may not be less than the " + "statistics collection interval.<BR>" + EOL); jobIsValid = false; } } // Handle the job comments jobComments = request.getParameter(Constants.SERVLET_PARAM_JOB_COMMENTS); // Handle the job-specific parameters Parameter[] params = jobClass.getParameterStubs().clone().getParameters(); for (int i=0; i < params.length; i++) { try { params[i].htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + params[i].getName())); } catch (InvalidValueException ive) { infoMessage.append("ERROR: The value for " + params[i].getDisplayName() + " is invalid -- " + ive.getMessage() + "<BR>" + EOL); jobIsValid = false; } } ParameterList parameters = new ParameterList(params); // Execute the validation routine of the job class itself. try { jobClass.validateJobInfo(numClients, threadsPerClient, threadStartupDelay, startTime, stopTime, duration, collectionInterval, parameters); } catch (InvalidValueException ive) { infoMessage.append("ERROR: " + ive.getMessage() + "<BR>" + EOL); jobIsValid = false; } // At this point, all the parameters have been read in and verified. If the // job is valid, then see if we need to test the parameters. If so, then do // that. Otherwise, schedule the job for execution. if (jobIsValid) { String submitStr = request.getParameter(Constants.SERVLET_PARAM_SUBMIT); if (submitStr.equals(Constants.SUBMIT_STRING_TEST_PARAMS)) { ArrayList<String> messageList = new ArrayList<String>(); boolean testSuccessful = false; try { testSuccessful = jobClass.testJobParameters(parameters, messageList); } catch (Exception e) { testSuccessful = false; messageList.add("ERROR: Exception caught while testing job " + "parameters: " + JobClass.stackTraceToString(e)); } infoMessage.append("Results of testing job parameters:<BR><BR>" + EOL); for (int i=0; i < messageList.size(); i++) { Object o = messageList.get(i); if (o != null) { infoMessage.append(o.toString() + "<BR>" + EOL); } } } else { try { long thisStartTime = System.currentTimeMillis(); if (startTime != null) { thisStartTime = startTime.getTime(); } long thisDuration = duration; if (stopTime != null) { long stopTimeDuration = stopTime.getTime() - thisStartTime; thisDuration = Math.max(thisDuration, stopTimeDuration); } Job job = null; String jobID = null; for (int i=0; i < numCopies; i++) { Date jobStartTime = new Date(thisStartTime); Date jobStopTime = null; if (stopTime != null) { jobStopTime = new Date(thisStartTime + thisDuration); } job = new Job(slamdServer, jobClass.getClass().getName(), numClients, threadsPerClient, threadStartupDelay, jobStartTime, jobStopTime, duration, collectionInterval, parameters, displayInReadOnlyMode); job.setFolderName(folderName); job.setJobDescription(jobDescription); job.setWaitForClients(waitForClients); job.setRequestedClients(requestedClients); job.setResourceMonitorClients(monitorClients); job.setMonitorClientsIfAvailable(monitorClientsIfAvailable); job.setDependencies(dependencyIDs); job.setNotifyAddresses(notifyAddresses); job.setJobComments(jobComments); if (jobDisabled) { job.setJobState(Constants.JOB_STATE_DISABLED); } try { jobID = scheduler.scheduleJob(job, folderName); logMessage(requestInfo, "Successfully scheduled job " + jobID); infoMessage.append("Successfully scheduled job " + jobID + " for execution.<BR>" + EOL); // Update the HTTP header of the response to include the job ID. HttpServletResponse response = requestInfo.response; response.addHeader(Constants.SERVLET_PARAM_JOB_ID, jobID); // Perform a simple calculation to see how much data this job will // send back to client. If (numIntervals*numClients*numThreads) // is greater than 1 million, then display a warning message. int numIntervals = 0; if (duration > 0) { numIntervals = duration / collectionInterval; } else if (jobStopTime != null) { long stopTimeVal = jobStopTime.getTime(); long startTimeVal; if (jobStartTime == null) { startTimeVal = System.currentTimeMillis(); } else { startTimeVal = jobStartTime.getTime(); } numIntervals = (int) ((stopTimeVal - startTimeVal) / collectionInterval); } if ((numIntervals * numClients * threadsPerClient) > 1000000) { infoMessage.append("WARNING: This job has the potential to " + "return a large amount of data to the " + "SLAMD server. If you do not think that " + "the SLAMD server has adequate memory to " + "handle the result set returned, then you " + "may wish to cancel or edit this job and " + "re-schedule it with a larger collection " + "interval.<BR>" + EOL); } if (makeInterDependent) { dependencyIDs = new String[] { jobID }; } } catch (SLAMDServerException sse) { sse.printStackTrace(); infoMessage.append("ERROR: Unable to schedule job for " + "execution -- " + sse.getMessage() + "<BR>" + EOL); } thisStartTime += (delayBetweenStarts * 1000); } if (numCopies == 1) { generateViewJobBody(requestInfo, job); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_PENDING, null, null); } return; } catch (Exception e) { e.printStackTrace(); infoMessage.append("ERROR: Unable to create the job -- " + e.getMessage() + "<BR>" + EOL); } } } generateScheduleJobForm(requestInfo, jobClass, numCopies, makeInterDependent, delayBetweenStarts, folderName, jobDescription, startTime, stopTime, duration, numClients, threadsPerClient, threadStartupDelay, requestedClients, monitorClients, monitorClientsIfAvailable, waitForClients, dependencyIDs, notifyAddresses, collectionInterval, jobComments, jobDisabled, displayInReadOnlyMode, parameters); } /** * Generates an HTML page that may be used to display information that can * help a user understand the kinds of information that should be provided * when scheduling a new job for execution. * * @param requestInfo The state information for this request. */ static void generateScheduleHelpPage(RequestInfo requestInfo) { logMessage(requestInfo, "In generateScheduleHelpPage()"); // If the user doesn't have schedule permission, then they can't see this if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "schedule jobs for execution."); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; StringBuilder htmlBody = requestInfo.htmlBody; String jobClassName = request.getParameter(Constants.SERVLET_PARAM_JOB_CLASS); if ((jobClassName == null) || (jobClassName.length() == 0)) { htmlBody.append("ERROR: No job class name specified." + EOL); return; } JobClass jobClass = slamdServer.getJobClass(jobClassName); if (jobClass == null) { htmlBody.append("ERROR: No information is known about job class " + jobClass + '.' + EOL); return; } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Help for Scheduling a \"" + jobClass.getJobName() + "\" Job</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("The following parameters may be specified when " + "scheduling a " + jobClass.getJobName() + " job class:" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<TABLE BORDER=\"1\">" + EOL); // The disable checkbox. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Is Disabled</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" Indicates whether the job should be designated as " + "disabled when it is initially scheduled." + EOL); htmlBody.append(" This will prevent the job from starting until it " + "is manually re-enabled." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of copies htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Number of Copies</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The number of copies to make for this job." + EOL); htmlBody.append(" When scheduling the job for execution, this " + "parameter specifies how many copies to schedule, which " + "allows you to create multiple jobs using the same " + "base configuration and then edit each one to customize " + "its settings." + EOL); htmlBody.append(" If no value is specified, then only one copy will " + "be created." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The delay between startups htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Time between Copy Startups</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The length of time in seconds that should be left " + "between the start times for each copy of this job." + EOL); htmlBody.append(" Note that this delay is between start times, not " + "between the time that one job completes and the next " + "begins." + EOL); htmlBody.append(" If no value is specified, then all jobs will be " + "eligible for immediate execution." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job folder htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Place in Folder</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The name of the job folder in which the job " + "be placed when it is created." + EOL); htmlBody.append(" Note that this will only appear if one or more " + "job folders have been created." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job description htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Description</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" A string that can contain any kind of " + "information about this job." + EOL); htmlBody.append(" It is only used for display in the " + "administrative interface to help users more quickly " + "determine the purpose of a particular job." + EOL); htmlBody.append(" This parameter is optional." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The start time htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Start Time</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The time at which the job should start running." + EOL); htmlBody.append(" The value should be in the form " + "\"YYYYMMDDhhmmss\"." + EOL); htmlBody.append(" If you specify time that has already passed, then " + "the job will be immediately eligible for execution." + EOL); htmlBody.append(" If you leave the value unspecified, then the " + "current time will be used." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The stop time htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Stop Time</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The time at which the job should stop running if " + "it has not already stopped running." + EOL); htmlBody.append(" The value should be in the form " + "\"YYYYMMDDhhmmss\"." + EOL); htmlBody.append(" If you leave the value unspecified, then the " + "job will continue running for the maximum allowed " + "duration, until it has completed, or until it is " + "stopped by an administrator." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The duration htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Duration</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The maximum length of time in seconds that the " + "job should be allowed to run before it is stopped." + EOL); htmlBody.append(" If you leave the value unspecified, then the " + "job will continue running until the stop time has been " + "reached, until it has completed, or until it is stopped " + "by an administrator." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of clients htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Number of Clients</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The number of clients that should be used to run " + "this job." + EOL); htmlBody.append(" Note that the specified number of clients must be " + "available when the start time is reached or the job " + "will not be able to run." + EOL); htmlBody.append(" This is a required parameter." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The requested clients htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Use Specific Clients</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The addresses of specific client systems that " + "should be used to run the job." + EOL); htmlBody.append(" The addresses may be either DNS-resolvable host " + "names or IP addresses." + EOL); htmlBody.append(" A separate address should be used per line." + EOL); htmlBody.append(" If no set of clients is specified, then any " + "available clients will be used, up to the specified " + "number of clients." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The resource monitor clients htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Resource Monitor Clients</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The addresses of the resource monitor client " + "systems that should be used for the job." + EOL); htmlBody.append(" The addresses may be either DNS-resolvable host " + "names or IP addresses." + EOL); htmlBody.append(" A separate address should be used per line." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to automatically monitor client systems htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Monitor Clients if Available</TD>" + EOL); htmlBody.append(" <TD>"); htmlBody.append(" Indicates whether the job should automatically " + "attempt to use any resource monitor clients that are " + "running on client system(s) when the job is running." + EOL); htmlBody.append(" If so, then any clients used that also have " + "resource monitors running will report resource monitor " + "statistics for the job." + EOL); htmlBody.append(" If no resource monitor client is available on one " + "or more client systems, then the job will still be " + "processed by those clients but no monitor information " + "will be collected for those systems." + EOL); htmlBody.append(" </TD>"); htmlBody.append(" </TR>" + EOL); // Whether to wait until clients are available htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Wait for Available Clients</TD>" + EOL); htmlBody.append(" <TD>"); htmlBody.append(" Indicates whether the job should wait for the " + "appropriate number and/or specified clients to become " + "available before it will be eligible to start running." + EOL); htmlBody.append(" If the time arrives for the job to start, this " + "parameter indicates whether the job will be cancelled, " + "or if the start will be delayed until the appropriate " + "clients are available." + EOL); htmlBody.append(" </TD>"); htmlBody.append(" </TR>" + EOL); // The number of threads per client htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Threads per Client</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The number of threads that should be created on " + "each client to run the job." + EOL); htmlBody.append(" This is a required parameter." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The thread startup delay htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Thread Startup Delay</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The delay in milliseconds that will be used when " + "starting the individual threads on the client." + EOL); htmlBody.append(" If no value is specified, then there will not be " + "any delay between client thread startup." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job dependencies htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Dependencies</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The set of jobs that must complete running before " + "this job will be considered eligible to run." + EOL); htmlBody.append(" If dependencies are specified and at least one " + "on which this job is dependent has not yet completed " + "running when the start time for this job arrives, then " + "the execution of this job will be delayed until all " + "dependencies have been fulfilled." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The e-mail address(es) to notify on completion of this job. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Notify on Completion</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The e-mail address(es) of the user(s) that should " + "be sent an e-mail message when the job has completed " + "execution." + EOL); htmlBody.append(" This message will contain a summary of the " + "job execution results and may optionally include a " + "link to view more information about the job through the " + "SLAMD administrative interface." + EOL); htmlBody.append(" If multiple addresses should be notified, then " + "they should be separated with spaces and/or commas." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The collection interval htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Statistics Collection Interval</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The length of time in seconds for a statistics " + "collection interval." + EOL); htmlBody.append(" In addition to the summary statistics gathered " + "during job processing, the time that a job is running " + "will be broken up into intervals of this length and " + "statistics will be made available for each of those " + "intervals." + EOL); htmlBody.append(" If no value is specified, a default of " + Constants.DEFAULT_COLLECTION_INTERVAL + " seconds will be used." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job-specific parameters Parameter[] stubs = jobClass.getParameterStubs().clone().getParameters(); for (int i=0; i < stubs.length; i++) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + stubs[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD>" + EOL); String description = replaceText(stubs[i].getDescription(), "\r\n", "<BR>"); description = replaceText(description, "\n", "<BR>"); description = replaceText(description, "\t", "        "); htmlBody.append(" " + description + EOL); if (stubs[i].isRequired()) { htmlBody.append(" <BR>" + EOL); htmlBody.append(" This is a required parameter." + EOL); } htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The job comments htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Comments</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" Free-form comments about this job that may be " + "used to provide more descriptive information than can " + "be seen through the other parameters." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append("</TABLE>" + EOL); } /** * Handles the work necessary to edit a job that has been scheduled but not * yet started. * * @param requestInfo The state information for this request. */ static void handleEditJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handleEditJob()"); // If the user doesn't have schedule permission, then they can't see this if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "edit job information."); return; } // Get the important state variables. HttpServletRequest request = requestInfo.request; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // Make sure that a job ID has been specified. If not, then just show the // default HTML. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { htmlBody.append(getDefaultHTML(requestInfo)); return; } // Make sure that we can retrieve the specified job from the pending queue. Job job = scheduler.getPendingJob(jobID); if (job == null) { infoMessage.append("Unable to retrieve job " + jobID + " for editing." + EOL); infoMessage.append("It may no longer be in the pending jobs queue.<BR>" + EOL); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_PENDING, null, null); return; } // See if the user has performed the edit. If so, make sure everything is // valid and perform the update. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && (confirmStr.length() > 0)) { boolean updateValid = true; // Get the disabled flag. String disabledStr = request.getParameter(Constants.SERVLET_PARAM_JOB_DISABLED); boolean jobDisabled = ((disabledStr != null) && (disabledStr.equalsIgnoreCase("true") || disabledStr.equalsIgnoreCase("on") || disabledStr.equalsIgnoreCase("yes") || disabledStr.equalsIgnoreCase("1"))); boolean displayInReadOnlyMode = false; String displayStr = request.getParameter(Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY); if ((displayStr == null) || (displayStr.length() == 0)) { displayInReadOnlyMode = false; } else { displayInReadOnlyMode = (displayStr.equalsIgnoreCase("true") || displayStr.equalsIgnoreCase("yes") || displayStr.equalsIgnoreCase("on") || displayStr.equalsIgnoreCase("1")); } // Get the description -- no verification required. String description = request.getParameter(Constants.SERVLET_PARAM_JOB_DESCRIPTION); // Get the start time. If it's specified, then it must be a valid date. Date startTime = null; String startTimeStr = request.getParameter(Constants.SERVLET_PARAM_JOB_START_TIME); if ((startTimeStr != null) && (startTimeStr.length() > 0)) { if (startTimeStr.length() == 14) { try { startTime = dateFormat.parse(startTimeStr); } catch (Exception e) { infoMessage.append("ERROR: Start time is not a valid date.<BR>" + EOL); updateValid = false; } } else { infoMessage.append("ERROR: Start time is not a valid date.<BR>" + EOL); updateValid = false; } } // Get the stop time. If it's specified, then it must be a valid date. Date stopTime = null; String stopTimeStr = request.getParameter(Constants.SERVLET_PARAM_JOB_STOP_TIME); if ((stopTimeStr != null) && (stopTimeStr.length() > 0)) { if (stopTimeStr.length() == 14) { try { stopTime = dateFormat.parse(stopTimeStr); } catch (Exception e) { infoMessage.append("ERROR: Stop time is not a valid date.<BR>" + EOL); updateValid = false; } } else { infoMessage.append("ERROR: Stop time is not a valid date.<BR>" + EOL); updateValid = false; } } // Get the duration. If it's specified, then it must be an integer; int duration = -1; String durationStr = request.getParameter(Constants.SERVLET_PARAM_JOB_DURATION); if ((durationStr != null) && (durationStr.length() > 0)) { try { duration = DurationParser.parse(durationStr); } catch (SLAMDException se) { infoMessage.append("ERROR: " + se.getMessage() + "<BR>" + EOL); updateValid = false; } } // Get the number of clients. It must be an integer. int numClients = -1; String numClientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NUM_CLIENTS); if ((numClientsStr == null) || (numClientsStr.length() == 0)) { infoMessage.append("ERROR: The number of clients to use must be " + "specified.<BR>" + EOL); updateValid = false; } else { try { numClients = Integer.parseInt(numClientsStr); if (numClients <= 0) { infoMessage.append("ERROR: The number of clients must be " + "greater than zero.<BR>" + EOL); updateValid = false; } } catch (Exception e) { infoMessage.append("ERROR: The number of clients must be an " + "integer.<BR>" + EOL); updateValid = false; } } // Get the specific clients to use. If specified, they must all be // resolvable to IP addresses. String[] clients = null; String clientStr = request.getParameter(Constants.SERVLET_PARAM_JOB_CLIENTS); if ((clientStr != null) && (clientStr.length() > 0)) { ArrayList<String> clientAddressList = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(clientStr, " \t\r\n"); while (tokenizer.hasMoreTokens()) { String address = tokenizer.nextToken(); try { InetAddress clientAddress = InetAddress.getByName(address); clientAddressList.add(clientAddress.getHostAddress()); } catch (Exception e) { infoMessage.append("ERROR: The client address " + address + " could not be resolved.<BR>" + EOL); updateValid = false; } } clients = new String[clientAddressList.size()]; clientAddressList.toArray(clients); } // Get the resource monitor clients to use. If specified, they must all // be resolvable to IP addresses. String[] monitorClients = null; clientStr = request.getParameter(Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS); if ((clientStr != null) && (clientStr.length() > 0)) { ArrayList<String> clientAddressList = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(clientStr, " \t\r\n"); while (tokenizer.hasMoreTokens()) { String address = tokenizer.nextToken(); try { InetAddress clientAddress = InetAddress.getByName(address); // See if the address is already present in the list. if so, then // don't add it a second time and display a warning to the user. String ipAddress = clientAddress.getHostAddress(); if (clientAddressList.contains(ipAddress)) { infoMessage.append("WARNING: Ignoring duplicate reference to " + "resource monitor client " + address + "<BR>." + EOL); continue; } clientAddressList.add(ipAddress); } catch (Exception e) { infoMessage.append("ERROR: The resource monitor client address " + address + " could not be resolved.<BR>" + EOL); updateValid = false; } } monitorClients = new String[clientAddressList.size()]; clientAddressList.toArray(monitorClients); } // Get the indicator that specifies whether to automatically monitor // client systems if they are available. String monitorStr = request.getParameter( Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS_IF_AVAILABLE); boolean monitorClientsIfAvailable = ((monitorStr != null) && (monitorStr.equalsIgnoreCase("true") || monitorStr.equalsIgnoreCase("yes") || monitorStr.equalsIgnoreCase("on") || monitorStr.equalsIgnoreCase("1"))); // Get the indicator that specifies whether to wait for clients to be // available. String waitStr = request.getParameter(Constants.SERVLET_PARAM_JOB_WAIT_FOR_CLIENTS); boolean waitForClients = ((waitStr != null) && (waitStr.equalsIgnoreCase("true") || waitStr.equalsIgnoreCase("yes") || waitStr.equalsIgnoreCase("on") || waitStr.equalsIgnoreCase("1"))); // Get the number of threads per client. It must be a positive integer. int threadsPerClient = -1; String threadsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_THREADS_PER_CLIENT); if ((threadsStr == null) || (threadsStr.length() == 0)) { infoMessage.append("ERROR: The number of threads per client must be " + "specified.<BR>" + EOL); updateValid = false; } else { try { threadsPerClient = Integer.parseInt(threadsStr); if (threadsPerClient <= 0) { infoMessage.append("ERROR: The number of threads per client " + "must be greater than zero.<BR>" + EOL); updateValid = false; } } catch (Exception e) { infoMessage.append("ERROR: The number of threads per client must " + "be an integer.<BR>" + EOL); updateValid = false; } } // Get the thread startup delay. If it is specified, then it must be // an integer. int threadStartupDelay = 0; String threadDelayStr = request.getParameter( Constants.SERVLET_PARAM_JOB_THREAD_STARTUP_DELAY); if ((threadDelayStr != null) && (threadDelayStr.length() > 0)) { try { threadStartupDelay = Integer.parseInt(threadDelayStr); } catch (Exception e) { infoMessage.append("ERROR: The thread startup delay must be an " + "integer.<BR>" + EOL); updateValid = false; } } // Get the job dependencies. String[] dependencyIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_DEPENDENCY); // Get the statistics collection interval. If it is specified, then it // must be an integer. int collectionInterval = Constants.DEFAULT_COLLECTION_INTERVAL; String intervalStr = request.getParameter( Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL); if ((intervalStr != null) && (intervalStr.length() > 0)) { try { collectionInterval = DurationParser.parse(intervalStr); } catch (SLAMDException se) { infoMessage.append("ERROR: " + se.getMessage() + "<BR>" + EOL); updateValid = false; } } // Get the notify addresses. String[] notifyAddresses = new String[0]; String addressStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NOTIFY_ADDRESS); if ((addressStr != null) && (addressStr.length() > 0)) { ArrayList<String> addressList = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(addressStr, ", "); while (tokenizer.hasMoreTokens()) { addressList.add(tokenizer.nextToken()); } notifyAddresses = new String[addressList.size()]; addressList.toArray(notifyAddresses); } // Get the job comments. String comments = request.getParameter(Constants.SERVLET_PARAM_JOB_COMMENTS); // Get all of the job-specific parameters. Parameter[] params = job.getParameterStubs().clone().getParameters(); for (int i=0; i < params.length; i++) { String[] values = request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + params[i].getName()); try { params[i].htmlInputFormToValue(values); } catch (InvalidValueException ive) { infoMessage.append("ERROR: Invalid value specified for " + params[i].getDisplayName() + ": " + ive.getMessage() + "<BR>" + EOL); updateValid = false; } } // If all the new values are acceptable, then write the changes into the // config directory. if (updateValid) { try { job.setJobState(jobDisabled ? Constants.JOB_STATE_DISABLED : Constants.JOB_STATE_NOT_YET_STARTED); job.setJobDescription(description); job.setStartTime(startTime); job.setStopTime(stopTime); job.setDuration(duration); job.setNumberOfClients(numClients); job.setRequestedClients(clients); job.setResourceMonitorClients(monitorClients); job.setMonitorClientsIfAvailable(monitorClientsIfAvailable); job.setWaitForClients(waitForClients); job.setThreadsPerClient(threadsPerClient); job.setThreadStartupDelay(threadStartupDelay); job.setCollectionInterval(collectionInterval); job.setDependencies(dependencyIDs); job.setNotifyAddresses(notifyAddresses); job.setJobComments(comments); job.setDisplayInReadOnlyMode(displayInReadOnlyMode); job.setParameterList(new ParameterList(params)); configDB.writeJob(job); infoMessage.append("Successfully updated job " + job.getJobID() + ".<BR>" + EOL); } catch (Exception e) { infoMessage.append("ERROR: Unable to update job information: " + e + "<BR>" + EOL); } generateViewJobBody(requestInfo, job); return; } } int jobNumClients = job.getJobClass().overrideNumClients(); int jobNumThreads = job.getJobClass().overrideThreadsPerClient(); int jobInterval = job.getJobClass().overrideCollectionInterval(); String star = "<SPAN CLASS=\"" + Constants.STYLE_WARNING_TEXT + "\">*</SPAN>"; htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Edit Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); String link = generateNewWindowLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_SCHEDULE_HELP, Constants.SERVLET_PARAM_JOB_CLASS, job.getJobClass().getClass().getName(), "Click here for help regarding these parameters"); htmlBody.append(link + '.' + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM CLASS=\"" + Constants.STYLE_MAIN_FORM + "\" METHOD=\"POST\" ACTION=\"" + requestInfo.servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_EDIT) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_CONFIRMED, "1") + EOL); if (jobNumClients > 0) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_NUM_CLIENTS, String.valueOf(jobNumClients)) + EOL); } if (jobNumThreads > 0) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_THREADS_PER_CLIENT, String.valueOf(jobNumThreads)) + EOL); } if (jobInterval > 0) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL, secondsToHumanReadableDuration(jobInterval)) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append("<TABLE BORDER=\"0\">" + EOL); // Whether the job is disabled boolean jobDisabled = (job.getJobState() == Constants.JOB_STATE_DISABLED); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Disabled</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DISABLED + '"' + (jobDisabled ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether the job should be displayed in read-only mode boolean displayInReadOnlyMode = job.displayInReadOnlyMode(); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Display in Read-Only Mode</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY + '"' + (displayInReadOnlyMode ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job description String value = job.getJobDescription(); if (value == null) { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DESCRIPTION + "\" VALUE=\"" + value + "\" SIZE=\"80\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The start time Date startTime = job.getStartTime(); if (startTime != null) { value = dateFormat.format(startTime); } else { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Start Time <FONT SIZE=\"-1\">(YYYYMMDDhhmmss)" + "</FONT></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_START_TIME + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The stop time Date stopTime = job.getStopTime(); if (stopTime != null) { value = dateFormat.format(stopTime); } else { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Stop Time <FONT SIZE=\"-1\">(YYYYMMDDhhmmss)" + "</FONT></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_STOP_TIME + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The duration int duration = job.getDuration(); if (duration > 0) { value = secondsToHumanReadableDuration(duration); } else { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Duration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DURATION + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of clients if (jobNumClients <= 0) { int numClients = job.getNumberOfClients(); if (numClients > 0) { value = String.valueOf(numClients); } else { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Number of Clients " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_NUM_CLIENTS + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // Specific clients to use. String[] clients = job.getRequestedClients(); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Use Specific Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_CLIENTS + "\" ROWS=\"5\"" + " COLS=\"40\">"); String separator = ""; for (int i=0; ((clients != null) && (i < clients.length)); i++) { htmlBody.append(separator); htmlBody.append(clients[i]); separator = EOL; } htmlBody.append("</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Resource monitor clients to use. String[] monitorClients = job.getResourceMonitorClients(); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Resource Monitor Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS + "\" ROWS=\"5\"" + " COLS=\"40\">"); separator = ""; for (int i=0; ((monitorClients != null) && (i < monitorClients.length)); i++) { htmlBody.append(separator); htmlBody.append(monitorClients[i]); separator = EOL; } htmlBody.append("</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to automatically monitor client systems. boolean monitorClientsIfAvailable = job.monitorClientsIfAvailable(); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Monitor Clients if Available</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS_IF_AVAILABLE + '"' + (monitorClientsIfAvailable ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to wait for clients to be available. boolean waitForClients = job.waitForClients(); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Wait for Available Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_WAIT_FOR_CLIENTS + '"' + (waitForClients ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of threads per client if (jobNumThreads <= 0) { int threadsPerClient = job.getThreadsPerClient(); if (threadsPerClient > 0) { value = String.valueOf(threadsPerClient); } else { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Threads per Client " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREADS_PER_CLIENT + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The thread startup delay int threadStartupDelay = job.getThreadStartupDelay(); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Thread Startup Delay (ms)</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREAD_STARTUP_DELAY + "\" VALUE=\"" + threadStartupDelay + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job dependencies String[] dependencyIDs = job.getDependencies(); Job[] pendingJobs = scheduler.getPendingJobs(); Job[] runningJobs = scheduler.getRunningJobs(); OptimizingJob[] optimizingJobs = new OptimizingJob[0]; try { optimizingJobs = scheduler.getUncompletedOptimizingJobs(); } catch (SLAMDServerException sse) { requestInfo.infoMessage.append("ERROR: Unable to retrieve the list " + "of uncompleted optimizing jobs -- " + sse + "<BR>" + EOL); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Dependencies</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); for (int i=0; ((dependencyIDs != null) && (i < dependencyIDs.length)); i++) { if ((dependencyIDs[i] == null) || (dependencyIDs[i].length() == 0)) { continue; } htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_DEPENDENCY + "\">" + EOL); Job dependentJob = null; try { dependentJob = configDB.getJob(dependencyIDs[i]); } catch (Exception e) {} if (dependentJob == null) { htmlBody.append(" <OPTION VALUE=\"" + dependencyIDs[i] + "\">" + dependencyIDs[i] + " -- Unknown Job" + EOL); } else { String description = dependentJob.getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + dependencyIDs[i] + "\">" + dependencyIDs[i] + " -- " + dependentJob.getJobName() + description + EOL); } htmlBody.append(" <OPTION VALUE=\"\">No Dependency" + EOL); for (int j=0; j < pendingJobs.length; j++) { if (pendingJobs[j].getJobID().equals(jobID)) { // Don't allow the user to specify this job as its own dependency. // That would prevent the job from starting at all. continue; } String description = pendingJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + pendingJobs[j].getJobID() + "\">" + pendingJobs[j].getJobID() + " -- " + pendingJobs[j].getJobName() + description + EOL); } for (int j=0; j < runningJobs.length; j++) { String description = runningJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + runningJobs[j].getJobID() + "\">" + runningJobs[j].getJobID() + " -- " + runningJobs[j].getJobName() + description + EOL); } for (int j=0; j < optimizingJobs.length; j++) { String description = optimizingJobs[j].getDescription(); if (description == null) { description = ""; } else { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + optimizingJobs[j].getOptimizingJobID() + "\">" + optimizingJobs[j].getOptimizingJobID() + " -- Optimizing " + optimizingJobs[j].getJobClass().getJobName() + description + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" <BR>" + EOL); } htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_DEPENDENCY + "\">" + EOL); htmlBody.append(" <OPTION VALUE=\"\">No Dependency" + EOL); for (int j=0; j < pendingJobs.length; j++) { if (pendingJobs[j].getJobID().equals(jobID)) { // Don't allow the user to specify this job as its own dependency. // That would prevent the job from starting at all. continue; } String description = pendingJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + pendingJobs[j].getJobID() + "\">" + pendingJobs[j].getJobID() + " -- " + pendingJobs[j].getJobName() + description + EOL); } for (int j=0; j < runningJobs.length; j++) { String description = runningJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + runningJobs[j].getJobID() + "\">" + runningJobs[j].getJobID() + " -- " + runningJobs[j].getJobName() + description + EOL); } for (int j=0; j < optimizingJobs.length; j++) { String description = optimizingJobs[j].getDescription(); if (description == null) { description = ""; } else { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + optimizingJobs[j].getOptimizingJobID() + "\">" + optimizingJobs[j].getOptimizingJobID() + " -- Optimizing " + optimizingJobs[j].getJobClass().getJobName() + description + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The notify addresses String[] notifyAddresses = job.getNotifyAddresses(); if ((notifyAddresses != null) && (notifyAddresses.length > 0)) { value = notifyAddresses[0]; for (int i=1; i < notifyAddresses.length; i++) { value += ", " + notifyAddresses[i]; } } else { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Notify on Completion</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_NOTIFY_ADDRESS + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The collection interval if (jobInterval <= 0) { int collectionInterval = job.getCollectionInterval(); if (collectionInterval > 0) { value = secondsToHumanReadableDuration(collectionInterval); } else { value = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Statistics Collection Interval</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL + "\" VALUE=\"" + value + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // Get the job-specific parameters. Note that the provided set of // parameters may not be the entire set that can be used, so use the // parameter stubs as the base Parameter[] stubs = job.getParameterStubs().clone().getParameters(); ParameterList parameters = job.getParameterList(); for (int i=0; i < stubs.length; i++) { if (parameters != null) { Parameter p = parameters.getParameter(stubs[i].getName()); if (p != null) { stubs[i].setValueFrom(p); } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + stubs[i].getDisplayName() + (stubs[i].isRequired() ? ' ' + star : "") + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + stubs[i].getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The job comments String comments = job.getJobComments(); if (comments == null) { comments = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Comments</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_COMMENTS + "\" ROWS=\"5\" " + "COLS=\"80\">" + comments + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The "Schedule Job" button htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" VALUE=\"Update " + "Job\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append("</TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } /** * Handles the work necessary to edit the set of comments and/or description * for a job. * * @param requestInfo The state information for this request. */ static void handleEditJobComments(RequestInfo requestInfo) { logMessage(requestInfo, "In handleEditJobComments()"); // If the user doesn't have schedule permission, then they can't see this if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "edit job information."); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // Make sure that a job ID has been specified. If not, then just show the // default HTML. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { htmlBody.append(getDefaultHTML(requestInfo)); return; } // Make sure that we can retrieve the specified job. Job job = null; try { job = configDB.getJob(jobID); } catch (Exception e) { infoMessage.append("Error retrieving job " + jobID + ": " + e.getMessage() + "<BR>" + EOL); } if (job == null) { infoMessage.append("Unable to retrieve job " + jobID + " for editing.<BR>" + EOL); return; } boolean displayInReadOnlyMode = false; String displayStr = request.getParameter(Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY); if ((displayStr == null) || (displayStr.length() == 0)) { displayInReadOnlyMode = false; } else { displayInReadOnlyMode = (displayStr.equalsIgnoreCase("true") || displayStr.equalsIgnoreCase("yes") || displayStr.equalsIgnoreCase("on") || displayStr.equalsIgnoreCase("1")); } // See if we need to actually process the update or if we need to show the // form to the user. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && (confirmStr.length() > 0)) { String comments = request.getParameter(Constants.SERVLET_PARAM_JOB_COMMENTS); String description = request.getParameter(Constants.SERVLET_PARAM_JOB_DESCRIPTION); try { job.setJobDescription(description); job.setJobComments(comments); job.setDisplayInReadOnlyMode(displayInReadOnlyMode); configDB.writeJob(job); infoMessage.append("Successfully updated job comments.<BR>" + EOL); } catch (DatabaseException de) { infoMessage.append("Unable to update job comments: " + de + "<BR>" + EOL); } generateViewJobBody(requestInfo, job); } else { String comments = job.getJobComments(); String description = job.getJobDescription(); if (comments == null) { comments = ""; } if (description == null) { description = ""; } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Edit Comments for Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Edit the set of comments for the job and click the " + "update button when finished." + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_EDIT_COMMENTS) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DESCRIPTION + "\" VALUE=\"" + description + "\" SIZE=\"80\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Comments</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_COMMENTS + "\" ROWS=\"10\" " + "COLS=\"80\">" + comments + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Display in Restricted Read-Only Mode</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY + '"' + (displayInReadOnlyMode ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" " + "VALUE=\"Update\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Cancel\">" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles all processing necessary to import persistent statistical data for * a job into the SLAMD server. * * @param requestInfo The state information for this request. */ static void handleImportPersistentStats(RequestInfo requestInfo) { logMessage(requestInfo, "In handleImportPersistentStats()"); // If the user doesn't have schedule permission, then they can't see this. if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "import persistent job statistics."); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // There should have been a job ID specified. If not, then report an error. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { String message = "Unable to determine the job ID of the job for which " + "to import persistent statistics."; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); return; } // Make sure that we can retrieve the specified job. Job job = null; String message = null; try { job = configDB.getJob(jobID); } catch (Exception e) { message = "Unable to retrieve information about job " + jobID + ": " + e; } if (job == null) { if (message == null) { message = "Unable to retrieve information about job " + jobID; } infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); return; } // Make sure that the job is done running. if (! job.doneRunning()) { message = "Unable to import persistent statistics for job " + jobID + " -- the job is not yet done running."; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); return; } // See if information was provided about the file to import. If so, then // try to import that data. Otherwise, provide a form to get that file. String importFile = request.getParameter(Constants.SERVLET_PARAM_DATA_IMPORT_FILE); if ((importFile != null) && (importFile.length() > 0)) { try { File f = new File(importFile); if (! (f.exists() || f.isFile())) { message = "The specified input file " + importFile + " does not exist or is not a file"; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader( Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); } else { FileInputStream inputStream = new FileInputStream(f); ASN1Reader reader = new ASN1Reader(inputStream); ASN1Sequence trackerSequence = null; try { trackerSequence = reader.readElement().decodeAsSequence(); } catch (Exception e) { inputStream.close(); throw e; } StatTracker[] importTrackers = StatEncoder.sequenceToTrackers(trackerSequence); if (importTrackers.length == 0) { message = "No statistical information was found in the import " + "file"; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader( Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); } else { String clientID = importTrackers[0].getClientID(); ArrayList<StatTracker> trackerList = new ArrayList<StatTracker>(); StatTracker[] jobTrackers = job.getStatTrackers(); for (int i=0; i < jobTrackers.length; i++) { if (! jobTrackers[i].getClientID().equalsIgnoreCase(clientID)) { trackerList.add(jobTrackers[i]); } } for (int i=0; i < importTrackers.length; i++) { trackerList.add(importTrackers[i]); } StatTracker[] newTrackers = new StatTracker[trackerList.size()]; trackerList.toArray(newTrackers); job.setStatTrackers(newTrackers); configDB.writeJob(job); infoMessage.append("The job was successfully updated with the " + "information from the provided persistent " + "stat data file.<BR>"); generateViewJobBody(requestInfo, job); return; } } } catch (Exception e) { message = "An error occurred while attempting to import the " + "persistent statistical data: " + JobClass.stackTraceToString(e); infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); return; } } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Import Persistent Statistics for Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Specify the path on the SLAMD server system to the " + "file containing the persistent statistical data." + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_IMPORT_PERSISTENT) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <BR>" + EOL); htmlBody.append(" Data File Path: " + EOL); htmlBody.append(" <INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_DATA_IMPORT_FILE + "\" SIZE=\"80\">" + EOL); htmlBody.append(" <BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Submit\">" + EOL); htmlBody.append("</FORM>" + EOL); } /** * Handles all processing necessary to cancel a pending or running job, * including first obtaining confirmation from the user so that a job is not * inadvertently cancelled. * * @param requestInfo The state information for this request. */ static void handleCancelJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handleCancelJob()"); // If the user doesn't have cancel permission, then they can't see this if (! requestInfo.mayCancelJob) { logMessage(requestInfo, "No mayCancelJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "cancel jobs."); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // There should have been a job ID specified. If not, then there's not // really much that can be done, so just print an info message and leave // the rest of the page blank. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { String message = "Unable to determine the job ID of the job to cancel."; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); } else { // Cancelling a job requires confirmation. If confirmation has not // yet been obtained, then display a form that allows the user to // provide this confirmation. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr == null) || ((! confirmStr.equalsIgnoreCase("yes")) && (! confirmStr.equalsIgnoreCase("no")))) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Cancel Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to cancel this job?" + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_CANCEL) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\" CELLPADDING=\"20\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Yes\"></TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"No\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } else if (confirmStr.equalsIgnoreCase("yes")) { scheduler.cancelJob(jobID, false); infoMessage.append("A request has been sent to cancel job " + jobID + ". It may take a short amount of time for the " + "job to actually be stopped.<BR>" + EOL); try { generateViewJobBody(requestInfo, scheduler.getJob(jobID)); } catch (SLAMDServerException sse) {} } else { infoMessage.append("Job " + jobID + " was not cancelled.<BR>" + EOL); try { generateViewJobBody(requestInfo, scheduler.getJob(jobID)); } catch (SLAMDServerException sse) {} } } } /** * Handles all processing necessary to cancel a pending job and remove it from * SLAMD entirely, rather than cancelling it and moving it to the completed * jobs page. * * @param requestInfo The state information for this request. */ static void handleCancelAndDelete(RequestInfo requestInfo) { logMessage(requestInfo, "In handleCancelAndDelete()"); // If the user doesn't have cancel or delete permission, then they can't // see this if (! requestInfo.mayCancelJob) { logMessage(requestInfo, "No mayCancelJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "cancel jobs."); return; } if (! requestInfo.mayDeleteJob) { logMessage(requestInfo, "No mayDeleteJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "delete jobs."); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // There should have been a job ID specified. If not, then there's not // really much that can be done, so just print an info message and leave // the rest of the page blank. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { infoMessage.append("ERROR: Unable to determine the job ID of the " + "job to cancel.<BR>" + EOL); } else { // Retrieve the job from the scheduler to see if it is actually in the // pending jobs queue, and that it has not yet started running. Job job = scheduler.getPendingJob(jobID); if (job == null) { infoMessage.append("ERROR: Job " + jobID + " is not contained in " + "the pending jobs queue.<BR>" + EOL); handleViewJob(requestInfo, null, null, jobID); return; } else if (job.getOptimizingJobID() != null) { infoMessage.append("ERROR: Job " + jobID + " is associated with an " + "optimizing job and may not be deleted<BR>." + EOL); handleViewJob(requestInfo, null, null, jobID); return; } // Cancelling a job requires confirmation. If confirmation has not // yet been obtained, then display a form that allows the user to // provide this confirmation. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr == null) || ((! confirmStr.equalsIgnoreCase("yes")) && (! confirmStr.equalsIgnoreCase("no")))) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Cancel Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to cancel this job?" + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_CANCEL_AND_DELETE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\" CELLPADDING=\"20\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Yes\"></TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"No\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } else if (confirmStr.equalsIgnoreCase("yes")) { scheduler.cancelAndDeleteJob(jobID); infoMessage.append("Job " + jobID + " has been cancelled and removed " + "from SLAMD.<BR>" + EOL); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_PENDING, null, null); return; } else { infoMessage.append("Job " + jobID + " was not cancelled.<BR>" + EOL); try { generateViewJobBody(requestInfo, scheduler.getJob(jobID)); } catch (SLAMDServerException sse) {} } } } /** * Handles all processing necessary to delete information from the * configuration directory about a job that has been completed. It can be * used to delete information about a single job, or about a range of jobs * completed before a specified time. * * @param requestInfo The state information for this request. */ static void handleDeleteJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handleDeleteJob()"); // If the user doesn't have delete permission, then they can't see this if (! requestInfo.mayDeleteJob) { logMessage(requestInfo, "No mayDeleteJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "delete job information."); return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID != null) && (jobID.length() > 0)) { // Deleting a job requires confirmation. If it hasn't been provided, then // request it. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr == null) || ((! confirmStr.equalsIgnoreCase("yes")) && (! confirmStr.equalsIgnoreCase("no")))) { // First, retrieve the job and make sure that it is not associated with // an optimizing job. Job job; try { job = configDB.getJob(jobID); } catch (Exception e) { infoMessage.append("Unable to retrieve job " + jobID + " from the configuration directory: " + e + "<BR>" + EOL); return; } String optimizingJobID = job.getOptimizingJobID(); if ((optimizingJobID != null) && (optimizingJobID.length() > 0)) { OptimizingJob optimizingJob = null; try { optimizingJob = getOptimizingJob(optimizingJobID); } catch (Exception e) {} if (optimizingJob != null) { infoMessage.append("ERROR: You cannot remove a job iteration " + "that is part of an optimizing job without " + "first removing the optimizing job definition." + "<BR>" + EOL); generateViewJobBody(requestInfo, job); return; } } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Delete Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to delete this job?" + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_DELETE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\" CELLPADDING=\"20\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Yes\"></TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"No\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } else if (confirmStr.equalsIgnoreCase("yes")) { try { configDB.removeJob(jobID); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Delete Successful</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Information about job " + jobID + " has been removed from the configuration " + "directory." + EOL); htmlBody.append("<BR><BR>" + EOL); String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, "here"); htmlBody.append("Click " + link + " to go to the completed jobs " + "page." + EOL); } catch (DatabaseException de) { infoMessage.append("ERROR: " + de.getMessage() + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Delete Failed</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Information about job " + jobID + " could not be removed from the configuration " + "directory." + EOL); htmlBody.append("See the error message above for additional " + "information about the failure." + EOL); } } else { infoMessage.append("Job " + jobID + " was not deleted.<BR>" + EOL); try { generateViewJobBody(requestInfo, scheduler.getJob(jobID)); } catch (SLAMDServerException sse) {} } } } /** * Handles all processing necessary to temporarily disable a pending job, * including first obtaining confirmation from the user so that a job is not * inadvertently disabled. * * @param requestInfo The state information for this request. */ static void handleDisableJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handleDisableJob()"); // If the user doesn't have permission to schedule jobs, then they can't // see this if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "disable jobs."); return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // There should have been a job ID specified. If not, then there's not // really much that can be done, so just print an info message and leave // the rest of the page blank. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { infoMessage.append("ERROR: Unable to determine the job ID of the " + "job to disable.<BR>" + EOL); } else { // Disabling a job requires confirmation. If confirmation has not // yet been obtained, then display a form that allows the user to // provide this confirmation. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr == null) || ((! confirmStr.equalsIgnoreCase("yes")) && (! confirmStr.equalsIgnoreCase("no")))) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Disable Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to disable this job?" + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_DISABLE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\" CELLPADDING=\"20\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Yes\"></TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"No\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } else if (confirmStr.equalsIgnoreCase("yes")) { try { scheduler.disableJob(jobID); infoMessage.append("Job " + jobID + " has been temporarily disabled.<BR>" + EOL); } catch (SLAMDServerException sse) { infoMessage.append("ERROR: Unable to disable job " + jobID + " -- " + sse + "<BR>" + EOL); } try { generateViewJobBody(requestInfo, scheduler.getJob(jobID)); } catch (SLAMDServerException sse) {} } else { infoMessage.append("Job " + jobID + " was not disabled.<BR>" + EOL); try { generateViewJobBody(requestInfo, scheduler.getJob(jobID)); } catch (SLAMDServerException sse) {} } } } /** * Handles all processing necessary to re-enable a disabled job, including * first obtaining confirmation from the user so that a job is not * inadvertently re-enabled. * * @param requestInfo The state information for this request. */ static void handleEnableJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handleEnableJob()"); // If the user doesn't have permission to schedule jobs, then they can't // see this if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "enable jobs."); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // There should have been a job ID specified. If not, then there's not // really much that can be done, so just print an info message and leave // the rest of the page blank. String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID == null) || (jobID.length() == 0)) { infoMessage.append("ERROR: Unable to determine the job ID of the " + "job to enable.<BR>" + EOL); } else { // Enabling a job requires confirmation. If confirmation has not // yet been obtained, then display a form that allows the user to // provide this confirmation. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr == null) || ((! confirmStr.equalsIgnoreCase("yes")) && (! confirmStr.equalsIgnoreCase("no")))) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Enable Job " + jobID + "</SPAN>" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("Are you sure that you want to enable this job?" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_ENABLE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\" CELLPADDING=\"20\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Yes\"></TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"No\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } else if (confirmStr.equalsIgnoreCase("yes")) { try { scheduler.enableJob(jobID); infoMessage.append("Job " + jobID + " has been re-enabled.<BR>" + EOL); } catch (SLAMDServerException sse) { infoMessage.append("ERROR: Unable to re-enable job " + jobID + " -- " + sse + "<BR>" + EOL); } try { generateViewJobBody(requestInfo, scheduler.getJob(jobID)); } catch (SLAMDServerException sse) {} } else { infoMessage.append("Job " + jobID + " was not re-enabled.<BR>" + EOL); try { generateViewJobBody(requestInfo, scheduler.getJob(jobID)); } catch (SLAMDServerException sse) {} } } } /** * Handles all processing associated with scheduling a self-optimizing job. * * @param requestInfo The state information for this request. */ static void handleOptimizeJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handleOptimizeJob()"); // If the user doesn't have permission to schedule jobs, then they can't // see this if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "schedule jobs."); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // There should have been either a job ID specified or a job class. Look // for a job ID first and if that is not present, then get the job class // name. Job job = null; JobClass jobClass = null; ParameterList optimizationParameters = null; ParameterList parameters = null; String jobID = request.getParameter(Constants.SERVLET_PARAM_JOB_ID); if ((jobID != null) && (jobID.length() > 0)) { try { job = configDB.getJob(jobID); } catch (Exception e) { infoMessage.append("ERROR: Unable to retrieve job \"" + jobID + "\" -- " + e.getMessage() + "<BR>" + EOL); return; } if (job == null) { infoMessage.append("ERROR: Unable to retrieve job \"" + jobID + "\" from the configuration directory.<BR>" + EOL); return; } jobClass = job.getJobClass(); parameters = job.getParameterList().clone(); } else { String jobClassName = request.getParameter(Constants.SERVLET_PARAM_JOB_CLASS); if ((jobClassName == null) || (jobClassName.length() == 0)) { infoMessage.append("ERROR: Neither a job ID nor a job class name " + "was provided to use for the optimizing job.<BR>" + EOL); return; } jobClass = slamdServer.getJobClass(jobClassName); if (jobClass == null) { infoMessage.append("ERROR: Unknown job class \"" + jobClassName + "\" specified for the optimizing job.<BR>" + EOL); return; } // This is a temporary placeholder. We'll fill in the values later. parameters = jobClass.getParameterStubs().clone(); } // Figure out which optimization algorithm should be used. If one was // specified in the request, then assume it has already been provided. // Otherwise, show the user a set of the options available to them. OptimizationAlgorithm optimizationAlgorithm; String optimizationAlgorithmClass = request.getParameter(Constants.SERVLET_PARAM_OPTIMIZATION_ALGORITHM); if ((optimizationAlgorithmClass == null) || (optimizationAlgorithmClass.length() == 0)) { // Get a list of the available optimization algorithms that can be used // for this job and allow the user to choose which one he/she wants. // If none are available, display an error message. ArrayList<OptimizationAlgorithm> availableAlgorithmList = new ArrayList<OptimizationAlgorithm>(); OptimizationAlgorithm[] algorithms = slamdServer.getOptimizationAlgorithms(); if ((algorithms == null) || (algorithms.length == 0)) { infoMessage.append("WARNING: No optimization algorithms have been " + "configured in the server. Using the default.<BR>" + EOL); algorithms = new OptimizationAlgorithm[] { new SingleStatisticOptimizationAlgorithm() }; } for (int i=0; i < algorithms.length; i++) { if (algorithms[i].availableWithJobClass(jobClass)) { availableAlgorithmList.add(algorithms[i]); } } if (availableAlgorithmList.isEmpty()) { infoMessage.append("ERROR: There are no optimization algorithms " + "configured in the server that may be used with " + jobClass.getJobName() + " jobs.<BR>" + EOL); if (job == null) { handleViewOptimizing(requestInfo, false); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, jobID); } return; } else if (availableAlgorithmList.size() == 1) { optimizationAlgorithm = availableAlgorithmList.get(0); } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Select an Optimization Algorithm</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Select the optimization algorithm that you wish to " + "use for this optimizing " + jobClass.getJobName() + " job." + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + requestInfo.servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, requestInfo.section) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, requestInfo.subsection) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_CLASS, jobClass.getClass().getName()) + EOL); if (jobID != null) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobID) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_OPTIMIZATION_ALGORITHM + "\">" + EOL); for (int i=0; i < availableAlgorithmList.size(); i++) { OptimizationAlgorithm algorithm = availableAlgorithmList.get(i); htmlBody.append(" <OPTION VALUE=\"" + algorithm.getClass().getName() + "\">" + algorithm.getOptimizationAlgorithmName() + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" <BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Continue\">" + EOL); htmlBody.append("</FORM>" + EOL); return; } } else { optimizationAlgorithm = slamdServer.getOptimizationAlgorithm(optimizationAlgorithmClass); if (optimizationAlgorithm == null) { infoMessage.append("ERROR: Undefined optimization algorithm class \"" + optimizationAlgorithmClass + "\" specified for the optimizing job.<BR>" + EOL); if (job == null) { handleViewOptimizing(requestInfo, false); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, jobID); } return; } } // See if the user has submitted the form that should allow them to specify // the information needed for generating the optimizing job. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && (confirmStr.length() > 0)) { if (confirmStr.equals(Constants.SUBMIT_STRING_CANCEL)) { infoMessage.append("The self-optimizing job was not scheduled.<BR>" + EOL); if (job == null) { handleViewOptimizing(requestInfo, false); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, jobID); } return; } // The user wants to schedule the job. Set up the variables to do this. boolean displayInReadOnlyMode = false; boolean jobIsValid = true; boolean includeThreadCount = false; boolean monitorClientsIfAvailable = false; boolean reRunBestIteration = false; Date startTime = null; int collectionInterval = 60; int delayBetweenJobs = 0; int duration = -1; int numClients = -1; int maxNonImproving = -1; int maxThreads = -1; int minThreads = -1; int reRunDuration = -1; int threadIncrement = -1; int threadStartupDelay = 0; String description = null; String folderName = null; String[] notifyAddresses = null; String[] requestedClients = null; String[] monitorClients = null; // Get the description specified by the user. We don't require any // validation for this. description = request.getParameter(Constants.SERVLET_PARAM_JOB_DESCRIPTION); // Get the flag that specifies whether to include the thread count in the // description. includeThreadCount = false; String includeThreadStr = request.getParameter( Constants.SERVLET_PARAM_JOB_INCLUDE_THREAD_IN_DESCRIPTION); if (includeThreadStr != null) { includeThreadCount = (includeThreadStr.equalsIgnoreCase("true") || includeThreadStr.equalsIgnoreCase("yes") || includeThreadStr.equalsIgnoreCase("on") || includeThreadStr.equalsIgnoreCase("1")); } // Get the flag that specifies whether to display the optimizing job in // read-only mode. displayInReadOnlyMode = false; String displayStr = request.getParameter(Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY); if (displayStr != null) { displayInReadOnlyMode = (displayStr.equalsIgnoreCase("true") || displayStr.equalsIgnoreCase("yes") || displayStr.equalsIgnoreCase("on") || displayStr.equalsIgnoreCase("1")); } // Get the start time for the first iteration. If it is specified, then // it must be 14 digits in the form "YYYYMMDDhhmmss". String startTimeStr = request.getParameter(Constants.SERVLET_PARAM_JOB_START_TIME); if ((startTimeStr == null) || (startTimeStr.length() == 0)) { startTime = new Date(); } else { if (startTimeStr.length() != 14) { infoMessage.append("ERROR: The job start time must be in the " + "form YYYYMMDDhhmmss (14 digits).<BR>" + EOL); jobIsValid = false; } else { try { startTime = dateFormat.parse(startTimeStr); } catch (ParseException pe) { infoMessage.append("ERROR: Unable to parse the job start " + "time \"" + startTimeStr + "\" as a date in the form YYYYMMDDhhmmss.<BR>" + EOL); jobIsValid = false; } } } // Get the duration for the job. If it is specified, it must be a // positive integer. String durationStr = request.getParameter(Constants.SERVLET_PARAM_JOB_DURATION); if ((durationStr == null) || (durationStr.length() == 0)) { duration = -1; } else { try { duration = DurationParser.parse(durationStr); if (duration <= 0) { infoMessage.append("ERROR: The job duration must be positive." + "<BR>" + EOL); jobIsValid = false; } } catch (SLAMDException se) { infoMessage.append("ERROR: " + se.getMessage() + "<BR>" + EOL); jobIsValid = false; } } // Get the delay between iterations. This must be specified and must be // an integer greater than or equal to zero. String delayStr = request.getParameter(Constants.SERVLET_PARAM_TIME_BETWEEN_STARTUPS); if ((delayStr == null) || (delayStr.length() == 0)) { infoMessage.append("ERROR: No value specified for the delay between " + "iterations.<BR>" + EOL); jobIsValid = false; } else { try { delayBetweenJobs = Integer.parseInt(delayStr); if (delayBetweenJobs < 0) { infoMessage.append("ERROR: The delay between job iterations " + "must be greater than or equal to zero.<BR>" + EOL); jobIsValid = false; } } catch (NumberFormatException nfe) { infoMessage.append("ERROR: Unable to parse the delay between job " + "iterations \"" + delayStr + "\" as an integer value.<BR>" + EOL); jobIsValid = false; } } // Get the number of clients. This must be specified and must be a // positive integer. String clientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NUM_CLIENTS); if ((clientsStr == null) || (clientsStr.length() == 0)) { infoMessage.append("ERROR: No value specified for the number of " + "clients to use.<BR>" + EOL); jobIsValid = false; } else { try { numClients = Integer.parseInt(clientsStr); if (numClients <= 0) { infoMessage.append("ERROR: The number of clients must be " + "positive.<BR>" + EOL); jobIsValid = false; } } catch (NumberFormatException nfe) { infoMessage.append("ERROR: Unable to parse the number of clients " + '"' + clientsStr + "\" as an integer value.<BR>" + EOL); jobIsValid = false; } } // Get the addresses of any specific clients that should be used to run // the job. Make sure that all client addresses are resolvable. clientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_CLIENTS); if ((clientsStr == null) || (clientsStr.length() == 0)) { requestedClients = new String[0]; } else { ArrayList<String> clientList = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(clientsStr); while (tokenizer.hasMoreTokens()) { String address = tokenizer.nextToken(); try { InetAddress clientAddress = InetAddress.getByName(address); clientList.add(clientAddress.getHostAddress()); } catch (UnknownHostException uhe) { infoMessage.append("ERROR: Unable to resolve client address \"" + address + "\".<BR>" + EOL); jobIsValid = false; } } requestedClients = new String[clientList.size()]; clientList.toArray(requestedClients); if (requestedClients.length > numClients) { infoMessage.append("ERROR: Specific set of requested clients may " + "not contain more than the specified number of " + "clients.<BR>" + EOL); jobIsValid = false; } } // Get the addresses of any resource monitor clients that should be used. // Make sure that all addresses are resolvable. clientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS); if ((clientsStr == null) || (clientsStr.length() == 0)) { monitorClients = new String[0]; } else { ArrayList<String> clientList = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(clientsStr); while (tokenizer.hasMoreTokens()) { String address = tokenizer.nextToken(); try { InetAddress clientAddress = InetAddress.getByName(address); clientList.add(clientAddress.getHostAddress()); } catch (UnknownHostException uhe) { infoMessage.append("ERROR: Unable to resolve client address \"" + address + "\".<BR>" + EOL); jobIsValid = false; } } monitorClients = new String[clientList.size()]; clientList.toArray(monitorClients); } // Determine whether to automatically monitor any client systems that may // be used. String monitorStr = request.getParameter( Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS_IF_AVAILABLE); if ((monitorStr != null) && (monitorStr.length() > 0)) { monitorClientsIfAvailable = (monitorStr.equalsIgnoreCase("true") || monitorStr.equalsIgnoreCase("yes") || monitorStr.equalsIgnoreCase("on") || monitorStr.equalsIgnoreCase("1")); } // Get the minimum number of threads per client. This must be specified // and must be a positive integer. String minThreadStr = request.getParameter(Constants.SERVLET_PARAM_JOB_THREADS_MIN); if ((minThreadStr == null) || (minThreadStr.length() == 0)) { infoMessage.append("ERROR: No value specified for the minimum " + "number of threads to use.<BR>" + EOL); jobIsValid = false; } else { try { minThreads = Integer.parseInt(minThreadStr); if (minThreads <= 0) { infoMessage.append("ERROR: The minimum number of threads must " + "be positive.<BR>" + EOL); jobIsValid = false; } } catch (NumberFormatException nfe) { infoMessage.append("ERROR: Unable to parse the minimum number of " + "threads \"" + minThreadStr + "\" as an integer value.<BR>" + EOL); jobIsValid = false; } } // Get the maximum number of threads per client. This does not have to // be specified, but if it is then it must be a positive integer value // greater than the minimum number of threads. String maxThreadStr = request.getParameter(Constants.SERVLET_PARAM_JOB_THREADS_MAX); if ((maxThreadStr == null) || (maxThreadStr.length() == 0)) { maxThreads = -1; } else { try { maxThreads = Integer.parseInt(maxThreadStr); if ((minThreads > 0) && (maxThreads < minThreads)) { infoMessage.append("ERROR: The maximum number of threads must " + "be greater than or equal to the minimum " + "number of threads.<BR>" + EOL); jobIsValid = false; } } catch (NumberFormatException nfe) { infoMessage.append("ERROR: Unable to parse the maximum number of " + "threads \"" + maxThreadStr + "\" as an integer value.<BR>" + EOL); jobIsValid = false; } } // Get the increment to use when increasing the number of threads between // iterations. It must be specified and it must be a positive integer. String incrementStr = request.getParameter(Constants.SERVLET_PARAM_THREAD_INCREMENT); if ((incrementStr == null) || (incrementStr.length() == 0)) { infoMessage.append("ERROR: No value specified for the thread " + "increment.<BR>" + EOL); jobIsValid = false; } else { try { threadIncrement = Integer.parseInt(incrementStr); if (threadIncrement <= 0) { infoMessage.append("ERROR: The thread increment must be greater " + "than zero.<BR>" + EOL); jobIsValid = false; } } catch (NumberFormatException nfe) { infoMessage.append("ERROR: Unable to parse the thread increment \"" + incrementStr + "\" as an integer value.<BR>" + EOL); jobIsValid = false; } } // Get the thread startup delay. It is optional. String startupDelayStr = request.getParameter( Constants.SERVLET_PARAM_JOB_THREAD_STARTUP_DELAY); if ((startupDelayStr != null) && (startupDelayStr.length() > 0)) { try { threadStartupDelay = Integer.parseInt(startupDelayStr); } catch (NumberFormatException nfe) { infoMessage.append("ERROR: Unable to parse the thread startup " + "delay \"" + startupDelayStr + "\" as an integer value.<BR>" + EOL); jobIsValid = false; } } // Get the statistics collection interval. If it is specified, then it // must be positive and should not be greater than or equal to the // duration. String intervalStr = request.getParameter( Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL); if ((intervalStr != null) && (intervalStr.length() > 0)) { try { collectionInterval = DurationParser.parse(intervalStr); if (collectionInterval <= 0) { infoMessage.append("ERROR: Statistics collection interval must " + "be greater than zero.<BR>" + EOL); jobIsValid = false; } else if ((duration > 0) && (collectionInterval >= duration)) { infoMessage.append("ERROR: Statistics collection interval must " + "be less than the maximum duration.<BR>" + EOL); jobIsValid = false; } } catch (SLAMDException se) { infoMessage.append("ERROR: " + se.getMessage() + "<BR>" + EOL); jobIsValid = false; } } // Get the maximum number of non-improving iterations. It must be // specified and must be an integer value greater than or equal to zero. String nonImprovingStr = request.getParameter(Constants.SERVLET_PARAM_JOB_MAX_NON_IMPROVING); if ((nonImprovingStr == null) || (nonImprovingStr.length() == 0)) { infoMessage.append("ERROR: No value specified for the maximum " + "number of consecutive non-improving " + "iterations.<BR>" + EOL); jobIsValid = false; } else { try { maxNonImproving = Integer.parseInt(nonImprovingStr); if (maxNonImproving < 0) { infoMessage.append("ERROR: Maximum number of consecutive " + "non-improving iterations must be greater " + "than or equal to zero.<BR>" + EOL); jobIsValid = false; } } catch (NumberFormatException nfe) { infoMessage.append("ERROR: Unable to parse the maximum number of " + "consecutive non-improving iterations \"" + nonImprovingStr + "\" as an integer value.<BR>" + EOL); jobIsValid = false; } } // Determine whether to re-run the best iteration. String reRunStr = request.getParameter(Constants.SERVLET_PARAM_RERUN_BEST_ITERATION); if (reRunStr != null) { reRunBestIteration = (reRunStr.equalsIgnoreCase("true") || reRunStr.equalsIgnoreCase("yes") || reRunStr.equalsIgnoreCase("on") || reRunStr.equalsIgnoreCase("1")); } // Determine the duration to use when re-running the best iteration. String reRunDurationStr = request.getParameter(Constants.SERVLET_PARAM_RERUN_DURATION); if (reRunDurationStr != null) { try { reRunDuration = DurationParser.parse(reRunDurationStr); } catch (SLAMDException se) {} } // Get the e-mail address(es) to be notified when the optimization process // is complete. String addressStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NOTIFY_ADDRESS); if ((addressStr == null) || (addressStr.length() == 0)) { notifyAddresses = new String[0]; } else { ArrayList<String> addressList = new ArrayList<String>(); StringTokenizer tokenizer = new StringTokenizer(addressStr, ", "); while (tokenizer.hasMoreTokens()) { addressList.add(tokenizer.nextToken()); } notifyAddresses = new String[addressList.size()]; addressList.toArray(notifyAddresses); } // Get the optimizing job comments. String comments = request.getParameter(Constants.SERVLET_PARAM_JOB_COMMENTS); if ((comments == null) || (comments.length() == 0)) { comments = null; } // Get the dependencies to use for the optimizing job. String[] dependencies = request.getParameterValues(Constants.SERVLET_PARAM_JOB_DEPENDENCY); if (dependencies == null) { dependencies = new String[0]; } // Get the folder name to use when creating the job. folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); // Get the optimization algorithm configuration parameters. Parameter[] params = optimizationAlgorithm. getOptimizationAlgorithmParameterStubs(jobClass).clone(). getParameters(); for (int i=0; i < params.length; i++) { try { params[i].htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_OPTIMIZATION_PARAM_PREFIX + params[i].getName())); } catch (InvalidValueException ive) { infoMessage.append("ERROR: The value for " + params[i].getDisplayName() + " is invalid -- " + ive.getMessage() + "<BR>" + EOL); jobIsValid = false; } } optimizationParameters = new ParameterList(params); // Get the job-specific parameters. params = jobClass.getParameterStubs().clone().getParameters(); for (int i=0; i < params.length; i++) { try { params[i].htmlInputFormToValue( request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + params[i].getName())); } catch (InvalidValueException ive) { infoMessage.append("ERROR: The value for " + params[i].getDisplayName() + " is invalid -- " + ive.getMessage() + "<BR>" + EOL); jobIsValid = false; } } parameters.setParameters(params); // Validate the configuration of the job as a whole. if (jobIsValid) { try { jobClass.validateJobInfo(numClients, minThreads, 0, startTime, null, duration, collectionInterval, parameters); } catch (InvalidValueException ive) { infoMessage.append("ERROR: The information provided is not valid " + "for this job: " + ive.getMessage() + "<BR>" + EOL); jobIsValid = false; } } // If the job is valid, then determine if we should test the job // parameters or schedule it for execution. If it is not valid, then // return the user to the schedule form. if (jobIsValid) { if ((confirmStr != null) && (confirmStr.equals(Constants.SUBMIT_STRING_TEST_PARAMS))) { ArrayList<String> messageList = new ArrayList<String>(); try { jobClass.testJobParameters(parameters, messageList); } catch (Exception e) { messageList.add("ERROR: Exception caught while testing job " + "parameters: " + JobClass.stackTraceToString(e)); } infoMessage.append("Results of testing job parameters:<BR><BR>" + EOL); for (int i=0; i < messageList.size(); i++) { Object o = messageList.get(i); if (o != null) { infoMessage.append(o.toString() + "<BR>" + EOL); } } if (job == null) { generateOptimizeJobForm(requestInfo, jobClass, optimizationAlgorithm); } else { generateOptimizeJobForm(requestInfo, job, optimizationAlgorithm); } return; } else { String optimizingJobID = scheduler.generateUniqueID(); OptimizingJob optimizingJob = new OptimizingJob(slamdServer, optimizingJobID, optimizationAlgorithm, jobClass, folderName, description, includeThreadCount, startTime, duration, delayBetweenJobs, numClients, requestedClients, monitorClients, monitorClientsIfAvailable, minThreads, maxThreads, threadIncrement, collectionInterval, maxNonImproving, notifyAddresses, reRunBestIteration, reRunDuration, parameters, displayInReadOnlyMode); optimizingJob.setDependencies(dependencies); optimizingJob.setThreadStartupDelay(threadStartupDelay); optimizingJob.setComments(comments); try { optimizationAlgorithm.initializeOptimizationAlgorithm(optimizingJob, optimizationParameters); } catch (InvalidValueException ive) { infoMessage.append("ERROR: Invalid value for one or more " + "optimization settings: " + ive.getMessage() + "<BR>" + EOL); if (job == null) { generateOptimizeJobForm(requestInfo, jobClass, optimizationAlgorithm); } else { generateOptimizeJobForm(requestInfo, job, optimizationAlgorithm); } return; } try { scheduler.scheduleOptimizingJob(optimizingJob, folderName); // Update the HTTP header of the response to include the job ID. HttpServletResponse response = requestInfo.response; response.addHeader(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID); generateViewOptimizingJobBody(requestInfo, optimizingJobID); } catch (SLAMDServerException sse) { infoMessage.append("ERROR: Unable to schedule the optimizing " + "job -- " + sse.getMessage() + "<BR>" + EOL); if (job == null) { generateOptimizeJobForm(requestInfo, jobClass, optimizationAlgorithm); } else { generateOptimizeJobForm(requestInfo, job, optimizationAlgorithm); } } } } else { generateOptimizeJobForm(requestInfo, jobClass, optimizationAlgorithm); } } else { if (job == null) { generateOptimizeJobForm(requestInfo, jobClass, optimizationAlgorithm); } else { generateOptimizeJobForm(requestInfo, job, optimizationAlgorithm); } } } /** * Generates a form that allows the user to schedule a self-optimizing job. * * @param requestInfo The state information for this request. * @param jobClass The job class that should be used to obtain * information for scheduling the optimizing * job. * @param optimizationAlgorithm The optimization algorithm to use for the * optimizing job. */ static void generateOptimizeJobForm(RequestInfo requestInfo, JobClass jobClass, OptimizationAlgorithm optimizationAlgorithm) { logMessage(requestInfo, "In generateOptimizeJobForm(" + jobClass.getJobName() + ')'); // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; int jobNumClients = jobClass.overrideNumClients(); int jobInterval = jobClass.overrideCollectionInterval(); // See if the job class is deprecated. If so, then add a warning message at // the top of the page. StringBuilder deprecatedMessage = new StringBuilder(); if (jobClass.isDeprecated(deprecatedMessage)) { infoMessage.append("WARNING: This job class has been deprecated."); if (deprecatedMessage.length() > 0) { infoMessage.append(" "); infoMessage.append(deprecatedMessage); } infoMessage.append("<BR><BR>" + EOL); } String star = "<SPAN CLASS=\"" + Constants.STYLE_WARNING_TEXT + "\">*</SPAN>"; htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Optimize Results for a \"" + jobClass.getJobName() + "\" Job</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Enter the following information about the way in which " + "the optimization should proceed." + EOL); htmlBody.append("Note that parameters marked with an asterisk (" + star + ") are required to have a value." + EOL); String link = generateNewWindowLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_OPTIMIZE_HELP, Constants.SERVLET_PARAM_JOB_CLASS, jobClass.getClass().getName(), Constants.SERVLET_PARAM_OPTIMIZATION_ALGORITHM, optimizationAlgorithm.getClass().getName(), "Click here for help regarding these parameters"); htmlBody.append(link + '.' + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM CLASS=\"" + Constants.STYLE_MAIN_FORM + "\" METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_OPTIMIZE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_CLASS, jobClass.getClass().getName()) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZATION_ALGORITHM, optimizationAlgorithm.getClass().getName()) + EOL); if (jobNumClients > 0) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_NUM_CLIENTS, String.valueOf(jobNumClients)) + EOL); } if (jobInterval > 0) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL, secondsToHumanReadableDuration(jobInterval)) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); // The description for the job. String description = request.getParameter(Constants.SERVLET_PARAM_JOB_DESCRIPTION); if ((description == null) || (description.length() == 0)) { description = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DESCRIPTION + "\" VALUE=\"" + description + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to include the number of threads in the description. boolean includeThreadInDescription = false; String includeThreadStr = request.getParameter( Constants.SERVLET_PARAM_JOB_INCLUDE_THREAD_IN_DESCRIPTION); if (includeThreadStr != null) { includeThreadInDescription = (includeThreadStr.equalsIgnoreCase("true") || includeThreadStr.equalsIgnoreCase("yes") || includeThreadStr.equalsIgnoreCase("on") || includeThreadStr.equalsIgnoreCase("1")); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Include Thread Count in Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_INCLUDE_THREAD_IN_DESCRIPTION + '"' + (includeThreadInDescription ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to display the job in restricted read-only mode. boolean displayInReadOnlyMode = false; String displayStr = request.getParameter(Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY); if (displayStr != null) { displayInReadOnlyMode = (displayStr.equalsIgnoreCase("true") || displayStr.equalsIgnoreCase("yes") || displayStr.equalsIgnoreCase("on") || displayStr.equalsIgnoreCase("1")); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Display In Read-Only Mode</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY + '"' + (displayInReadOnlyMode ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The name of the folder to use for the job. String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); JobFolder[] folders = null; try { folders = configDB.getFolders(); } catch (DatabaseException de) {} if ((folders != null) && (folders.length > 0)) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Place in Folder</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_FOLDER + "\">" + EOL); for (int i=0; i < folders.length; i++) { if ((folderName != null) && folderName.equals(folders[i].getFolderName())) { htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + "\" SELECTED>" + folders[i].getFolderName() + EOL); } else { htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + "\">" + folders[i].getFolderName() + EOL); } } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The start time for the job. String startTimeStr = request.getParameter(Constants.SERVLET_PARAM_JOB_START_TIME); if ((startTimeStr == null) || (startTimeStr.length() == 0)) { if (populateStartTime) { startTimeStr = dateFormat.format(new Date()); } else { startTimeStr = ""; } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Start Time <FONT SIZE=\"-1\">(YYYYMMDDhhmmss)" + "</FONT></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_START_TIME + "\" VALUE=\"" + startTimeStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The duration for the job. String durationStr = request.getParameter(Constants.SERVLET_PARAM_JOB_DURATION); if (durationStr == null) { durationStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Duration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DURATION + "\" VALUE=\"" + durationStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The delay that should be included between the individual copies of the // job. String delayStr = request.getParameter(Constants.SERVLET_PARAM_TIME_BETWEEN_STARTUPS); if ((delayStr == null) || (delayStr.length() == 0)) { delayStr = "0"; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Delay Between Iterations " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_TIME_BETWEEN_STARTUPS + "\" VALUE=\"" + delayStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of clients to use. if (jobNumClients <= 0) { String clientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NUM_CLIENTS); if (clientsStr == null) { clientsStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Number of Clients " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_NUM_CLIENTS + "\" VALUE=\"" + clientsStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The specific set of clients to use. String clientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_CLIENTS); if (clientsStr == null) { clientsStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Use Specific Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_CLIENTS + "\" ROWS=\"5\" " + "COLS=\"40\">" + clientsStr + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The set of resource monitor clients to use. clientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS); if (clientsStr == null) { clientsStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Resource Monitor Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS + "\" ROWS=\"5\" COLS=\"40\">" + clientsStr + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to automatically monitor client systems if available. boolean monitorClientsIfAvailable = false; String monitorStr = request.getParameter( Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS_IF_AVAILABLE); if (monitorStr != null) { monitorClientsIfAvailable = (monitorStr.equalsIgnoreCase("true") || monitorStr.equalsIgnoreCase("yes") || monitorStr.equalsIgnoreCase("on") || monitorStr.equalsIgnoreCase("1")); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Monitor Clients if Available</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS_IF_AVAILABLE + '"' + (monitorClientsIfAvailable ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The minimum number of threads to use. String minThreadsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_THREADS_MIN); if ((minThreadsStr == null) || (minThreadsStr.length() == 0)) { minThreadsStr = "1"; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Minimum Number of Threads " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREADS_MIN + "\" VALUE=\"" + minThreadsStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The maximum number of threads to use. String maxThreadsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_THREADS_MAX); if (maxThreadsStr == null) { maxThreadsStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Maximum Number of Threads</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREADS_MAX + "\" VALUE=\"" + maxThreadsStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The thread increment to use. String incrementStr = request.getParameter(Constants.SERVLET_PARAM_THREAD_INCREMENT); if ((incrementStr == null) || (incrementStr.length() == 0)) { incrementStr = "1"; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Thread Increment Between Iterations " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_THREAD_INCREMENT + "\" VALUE=\"" + incrementStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The thread startup delay to use. String startupDelayStr = request.getParameter(Constants.SERVLET_PARAM_JOB_THREAD_STARTUP_DELAY); if ((startupDelayStr == null) || (startupDelayStr.length() == 0)) { startupDelayStr = "0"; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Thread Startup Delay (ms)</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREAD_STARTUP_DELAY + "\" VALUE=\"" + startupDelayStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The statistics collection interval. if (jobInterval <= 0) { String intervalStr = request.getParameter( Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL); if (intervalStr == null) { intervalStr = secondsToHumanReadableDuration( Constants.DEFAULT_COLLECTION_INTERVAL); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Statistics Collection Interval</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL + "\" VALUE=\"" + intervalStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The number of consecutive non-improving results before ending testing. String maxNonImprovingStr = request.getParameter(Constants.SERVLET_PARAM_JOB_MAX_NON_IMPROVING); if ((maxNonImprovingStr == null) || (maxNonImprovingStr.length() == 0)) { maxNonImprovingStr = "1"; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Max. Consecutive Non-Improving Iterations " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_MAX_NON_IMPROVING + "\" VALUE=\"" + maxNonImprovingStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to re-run the best iteration of the optimizing job once it is // found. boolean reRunBestIteration = false; String reRunBestStr = request.getParameter(Constants.SERVLET_PARAM_RERUN_BEST_ITERATION); if (reRunBestStr != null) { reRunBestStr = reRunBestStr.toLowerCase(); reRunBestIteration = (reRunBestStr.equals("true") || reRunBestStr.equals("yes") || reRunBestStr.equals("on") || reRunBestStr.equals("1")); } String checkedStr = (reRunBestIteration ? " CHECKED" : ""); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Re-Run Best Iteration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_RERUN_BEST_ITERATION + '"' + checkedStr + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The duration to use when re-running the best iteration. String reRunDurationStr = request.getParameter(Constants.SERVLET_PARAM_RERUN_DURATION); if (reRunDurationStr == null) { reRunDurationStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Re-Run Duration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_RERUN_DURATION + "\" VALUE=\"" + reRunDurationStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The dependencies for this job. String dependencyID = request.getParameter(Constants.SERVLET_PARAM_JOB_DEPENDENCY); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Dependencies</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_DEPENDENCY + "\">" + EOL); htmlBody.append(" <OPTION VALUE=\"\">No Dependency" + EOL); Job[] pendingJobs = scheduler.getPendingJobs(); Job[] runningJobs = scheduler.getRunningJobs(); OptimizingJob[] optimizingJobs; try { optimizingJobs = scheduler.getUncompletedOptimizingJobs(); if (optimizingJobs == null) { optimizingJobs = new OptimizingJob[0]; } } catch (SLAMDServerException sse) { infoMessage.append("ERROR: Unable to get the list of uncompleted " + "optimizing jobs to use in the dependency list -- " + sse + "<BR>" + EOL); optimizingJobs = new OptimizingJob[0]; } for (int j=0; j < pendingJobs.length; j++) { description = pendingJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } if ((dependencyID != null) && dependencyID.equals(pendingJobs[j].getJobID())) { htmlBody.append(" <OPTION VALUE=\"" + pendingJobs[j].getJobID() + "\" SELECTED>" + pendingJobs[j].getJobID() + " -- Pending " + pendingJobs[j].getJobName() + description + EOL); } else { htmlBody.append(" <OPTION VALUE=\"" + pendingJobs[j].getJobID() + "\">" + pendingJobs[j].getJobID() + " -- Pending " + pendingJobs[j].getJobName() + description + EOL); } } for (int j=0; j < runningJobs.length; j++) { description = runningJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } if ((dependencyID != null) && dependencyID.equals(runningJobs[j].getJobID())) { htmlBody.append(" <OPTION VALUE=\"" + runningJobs[j].getJobID() + "\" SELECTED>" + runningJobs[j].getJobID() + " -- Running " + runningJobs[j].getJobName() + description + EOL); } else { htmlBody.append(" <OPTION VALUE=\"" + runningJobs[j].getJobID() + "\">" + runningJobs[j].getJobID() + " -- Running " + runningJobs[j].getJobName() + description + EOL); } } for (int j=0; j < optimizingJobs.length; j++) { description = optimizingJobs[j].getDescription(); if (description == null) { description = ""; } else { description = " -- " + description; } if ((dependencyID != null) && dependencyID.equals(optimizingJobs[j].getOptimizingJobID())) { htmlBody.append(" <OPTION VALUE=\"" + optimizingJobs[j].getOptimizingJobID() + "\" SELECTED>" + optimizingJobs[j].getOptimizingJobID() + " -- Optimizing " + optimizingJobs[j].getJobClass().getJobName() + description + EOL); } else { htmlBody.append(" <OPTION VALUE=\"" + optimizingJobs[j].getOptimizingJobID() + "\">" + optimizingJobs[j].getOptimizingJobID() + " -- Optimizing " + optimizingJobs[j].getJobClass().getJobName() + description + EOL); } } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The e-mail address(es) to notify when the job is complete. if (slamdServer.getMailer().isEnabled()) { String mailStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NOTIFY_ADDRESS); if (mailStr == null) { mailStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Notify on Completion</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_NOTIFY_ADDRESS + "\" VALUE=\"" + mailStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The list of optimization-algorithm specific parameters. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); boolean confirmed = ((confirmStr != null) && (confirmStr.length() > 0)); Parameter[] params = optimizationAlgorithm. getOptimizationAlgorithmParameterStubs(jobClass).clone(). getParameters(); for (int i=0; i < params.length; i++) { Parameter stub = params[i]; if (confirmed) { String[] values = request.getParameterValues( Constants.SERVLET_PARAM_OPTIMIZATION_PARAM_PREFIX + stub.getName()); try { stub.htmlInputFormToValue(values); } catch (InvalidValueException ive) {} } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + stub.getDisplayName() + (stub.isRequired() ? star : "") + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" " + stub.getHTMLInputForm( Constants.SERVLET_PARAM_OPTIMIZATION_PARAM_PREFIX) + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The list of job-specific parameters. params = jobClass.getParameterStubs().clone().getParameters(); for (int i=0; i < params.length; i++) { Parameter stub = params[i]; if (confirmed) { String[] values = request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + stub.getName()); try { stub.htmlInputFormToValue(values); } catch (InvalidValueException ive) {} } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + stub.getDisplayName() + (stub.isRequired() ? star : "") + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" " + stub.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The comments field. String comments = request.getParameter(Constants.SERVLET_PARAM_JOB_COMMENTS); if (comments == null) { comments = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Comments</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_COMMENTS + "\" ROWS=\"5\" " + "COLS=\"80\">" + comments + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The submit button. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); if (jobClass.providesParameterTest()) { htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"" + Constants.SUBMIT_STRING_TEST_PARAMS + "\">" + EOL); htmlBody.append("    " + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Schedule\">" + EOL); htmlBody.append("    " + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"" + Constants.SUBMIT_STRING_CANCEL + "\">" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } /** * Generates a form that allows the user to schedule a self-optimizing job. * * @param requestInfo The state information for this request. * @param job The job that will be used as the basis for * the self-optimizing job. * @param optimizationAlgorithm The optimization algorithm to use for the * optimizing job. */ static void generateOptimizeJobForm(RequestInfo requestInfo, Job job, OptimizationAlgorithm optimizationAlgorithm) { logMessage(requestInfo, "In generateOptimizeJobForm(" + job.getJobID() + ')'); // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; int jobNumClients = job.getJobClass().overrideNumClients(); int jobInterval = job.getJobClass().overrideCollectionInterval(); // See if the job class is deprecated. If so, then add a warning message at // the top of the page. StringBuilder deprecatedMessage = new StringBuilder(); if (job.getJobClass().isDeprecated(deprecatedMessage)) { infoMessage.append("WARNING: This job class has been deprecated."); if (deprecatedMessage.length() > 0) { infoMessage.append(" "); infoMessage.append(deprecatedMessage); } infoMessage.append("<BR><BR>" + EOL); } String star = "<SPAN CLASS=\"" + Constants.STYLE_WARNING_TEXT + "\">*</SPAN>"; htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Optimize Results for Job " + job.getJobID() + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Enter the following information about the way in which " + "the optimization should proceed." + EOL); htmlBody.append("Note that parameters marked with an asterisk (" + star + ") are required to have a value." + EOL); String link = generateNewWindowLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_OPTIMIZE_HELP, Constants.SERVLET_PARAM_JOB_CLASS, job.getJobClassName(), Constants.SERVLET_PARAM_OPTIMIZATION_ALGORITHM, optimizationAlgorithm.getClass().getName(), "Click here for help regarding these parameters"); htmlBody.append(link + '.' + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM CLASS=\"" + Constants.STYLE_MAIN_FORM + "\" METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_OPTIMIZE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_CLASS, job.getJobClassName()) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZATION_ALGORITHM, optimizationAlgorithm.getClass().getName()) + EOL); if (jobNumClients > 0) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_NUM_CLIENTS, String.valueOf(jobNumClients)) + EOL); } if (jobInterval > 0) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL, String.valueOf(jobInterval)) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); // The description for the job. String description = request.getParameter(Constants.SERVLET_PARAM_JOB_DESCRIPTION); if ((description == null) || (description.length() == 0)) { description = job.getJobDescription(); if (description == null) { description = ""; } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DESCRIPTION + "\" VALUE=\"" + description + "\" SIZE=\"80\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to include the number of threads in the description. boolean includeThreadInDescription = false; String includeThreadStr = request.getParameter( Constants.SERVLET_PARAM_JOB_INCLUDE_THREAD_IN_DESCRIPTION); if (includeThreadStr != null) { includeThreadInDescription = (includeThreadStr.equalsIgnoreCase("true") || includeThreadStr.equalsIgnoreCase("yes") || includeThreadStr.equalsIgnoreCase("on") || includeThreadStr.equalsIgnoreCase("one")); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Include Thread Count in Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_INCLUDE_THREAD_IN_DESCRIPTION + '"' + (includeThreadInDescription ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to display the job in restricted read-only mode. boolean displayInReadOnlyMode = false; String displayStr = request.getParameter(Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY); if (displayStr != null) { displayInReadOnlyMode = (displayStr.equalsIgnoreCase("true") || displayStr.equalsIgnoreCase("yes") || displayStr.equalsIgnoreCase("on") || displayStr.equalsIgnoreCase("1")); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Display In Read-Only Mode</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY + '"' + (displayInReadOnlyMode ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The name of the folder to use for the job. JobFolder[] folders = null; try { folders = configDB.getFolders(); } catch (DatabaseException de) {} if ((folders != null) && (folders.length > 0)) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Place in Folder</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_FOLDER + "\">" + EOL); for (int i=0; i < folders.length; i++) { if ((job.getFolderName() != null) && job.getFolderName().equalsIgnoreCase(folders[i].getFolderName())) { htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + "\" SELECTED>" + folders[i].getFolderName() + EOL); } else { htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + "\">" + folders[i].getFolderName() + EOL); } } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The start time for the job. String startTimeStr = request.getParameter(Constants.SERVLET_PARAM_JOB_START_TIME); if ((startTimeStr == null) || (startTimeStr.length() == 0)) { if (populateStartTime) { startTimeStr = dateFormat.format(new Date()); } else { startTimeStr = ""; } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Start Time <FONT SIZE=\"-1\">(YYYYMMDDhhmmss)" + "</FONT></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_START_TIME + "\" VALUE=\"" + startTimeStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The duration for the job. String durationStr = request.getParameter(Constants.SERVLET_PARAM_JOB_DURATION); if ((durationStr == null) || (durationStr.length() == 0)) { int duration = job.getDuration(); if (duration > 0) { durationStr = secondsToHumanReadableDuration(duration); } else { durationStr = ""; } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Duration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DURATION + "\" VALUE=\"" + durationStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The delay that should be included between the individual copies of the // job. String delayStr = request.getParameter(Constants.SERVLET_PARAM_TIME_BETWEEN_STARTUPS); if ((delayStr == null) || (delayStr.length() == 0)) { delayStr = "0"; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Delay Between Iterations " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_TIME_BETWEEN_STARTUPS + "\" VALUE=\"" + delayStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of clients to use. if (jobNumClients <= 0) { String clientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NUM_CLIENTS); if ((clientsStr == null) || (clientsStr.length() == 0)) { clientsStr = String.valueOf(job.getNumberOfClients()); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Number of Clients " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_NUM_CLIENTS + "\" VALUE=\"" + clientsStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The specific set of clients to use. String clientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_CLIENTS); if (clientsStr == null) { clientsStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Use Specific Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_CLIENTS + "\" ROWS=\"5\" " + "COLS=\"40\">" + clientsStr + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The set of resource monitor clients to use. clientsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS); if (clientsStr == null) { clientsStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Resource Monitor Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS + "\" ROWS=\"5\" COLS=\"40\">" + clientsStr + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to automatically monitor client systems if available. boolean monitorClientsIfAvailable = job.monitorClientsIfAvailable(); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Monitor Clients if Available</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS_IF_AVAILABLE + '"' + (monitorClientsIfAvailable ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The minimum number of threads to use. String minThreadsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_THREADS_MIN); if ((minThreadsStr == null) || (minThreadsStr.length() == 0)) { minThreadsStr = "1"; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Minimum Number of Threads " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREADS_MIN + "\" VALUE=\"" + minThreadsStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The maximum number of threads to use. String maxThreadsStr = request.getParameter(Constants.SERVLET_PARAM_JOB_THREADS_MAX); if ((maxThreadsStr == null) || (maxThreadsStr.length() == 0)) { maxThreadsStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Maximum Number of Threads</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREADS_MAX + "\" VALUE=\"" + maxThreadsStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The thread increment to use. String incrementStr = request.getParameter(Constants.SERVLET_PARAM_THREAD_INCREMENT); if ((incrementStr == null) || (incrementStr.length() == 0)) { incrementStr = "1"; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Thread Increment Between Iterations " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_THREAD_INCREMENT + "\" VALUE=\"" + incrementStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The thread startup delay to use. String startupDelayStr = request.getParameter(Constants.SERVLET_PARAM_JOB_THREAD_STARTUP_DELAY); if ((startupDelayStr == null) || (startupDelayStr.length() == 0)) { startupDelayStr = "0"; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Thread Startup Delay (ms)</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREAD_STARTUP_DELAY + "\" VALUE=\"" + startupDelayStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The statistics collection interval. if (jobInterval <= 0) { String intervalStr = request.getParameter( Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL); if ((intervalStr == null) || (intervalStr.length() == 0)) { intervalStr = secondsToHumanReadableDuration(job.getCollectionInterval()); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Statistics Collection Interval</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL + "\" VALUE=\"" + intervalStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The number of consecutive non-improving results before ending testing. String maxNonImprovingStr = request.getParameter(Constants.SERVLET_PARAM_JOB_MAX_NON_IMPROVING); if ((maxNonImprovingStr == null) || (maxNonImprovingStr.length() == 0)) { maxNonImprovingStr = "1"; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Max. Consecutive Non-Improving Iterations " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_MAX_NON_IMPROVING + "\" VALUE=\"" + maxNonImprovingStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to re-run the best iteration of the optimizing job once it is // found. boolean reRunBestIteration = false; String reRunBestStr = request.getParameter(Constants.SERVLET_PARAM_RERUN_BEST_ITERATION); if (reRunBestStr != null) { reRunBestStr = reRunBestStr.toLowerCase(); reRunBestIteration = (reRunBestStr.equals("true") || reRunBestStr.equals("yes") || reRunBestStr.equals("on") || reRunBestStr.equals("1")); } String checkedStr = (reRunBestIteration ? " CHECKED" : ""); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Re-Run Best Iteration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_RERUN_BEST_ITERATION + '"' + checkedStr + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The duration to use when re-running the best iteration. String reRunDurationStr = request.getParameter(Constants.SERVLET_PARAM_RERUN_DURATION); if (reRunDurationStr == null) { reRunDurationStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Re-Run Duration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_RERUN_DURATION + "\" VALUE=\"" + reRunDurationStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The dependencies for this job. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Dependencies</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_DEPENDENCY + "\">" + EOL); htmlBody.append(" <OPTION VALUE=\"\">No Dependency" + EOL); Job[] pendingJobs = scheduler.getPendingJobs(); Job[] runningJobs = scheduler.getRunningJobs(); OptimizingJob[] optimizingJobs; try { optimizingJobs = scheduler.getUncompletedOptimizingJobs(); if (optimizingJobs == null) { optimizingJobs = new OptimizingJob[0]; } } catch (SLAMDServerException sse) { infoMessage.append("ERROR: Unable to get the list of uncompleted " + "optimizing jobs to use in the dependency list -- " + sse + "<BR>" + EOL); optimizingJobs = new OptimizingJob[0]; } for (int j=0; j < pendingJobs.length; j++) { description = pendingJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + pendingJobs[j].getJobID() + "\">" + pendingJobs[j].getJobID() + " -- Pending " + pendingJobs[j].getJobName() + description + EOL); } for (int j=0; j < runningJobs.length; j++) { description = runningJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + runningJobs[j].getJobID() + "\">" + runningJobs[j].getJobID() + " -- Running " + runningJobs[j].getJobName() + description + EOL); } for (int j=0; j < optimizingJobs.length; j++) { description = optimizingJobs[j].getDescription(); if (description == null) { description = ""; } else { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + optimizingJobs[j].getOptimizingJobID() + "\">" + optimizingJobs[j].getOptimizingJobID() + " -- Optimizing " + optimizingJobs[j].getJobClass().getJobName() + description + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The e-mail address(es) to notify when the job is complete. if (slamdServer.getMailer().isEnabled()) { String mailStr = request.getParameter(Constants.SERVLET_PARAM_JOB_NOTIFY_ADDRESS); if (mailStr == null) { mailStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Notify on Completion</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_NOTIFY_ADDRESS + "\" VALUE=\"" + mailStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The list of optimization-algorithm specific parameters. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); boolean confirmed = ((confirmStr != null) && (confirmStr.length() > 0)); Parameter[] params = optimizationAlgorithm. getOptimizationAlgorithmParameterStubs(job.getJobClass()).clone(). getParameters(); for (int i=0; i < params.length; i++) { Parameter stub = params[i]; if (confirmed) { String[] values = request.getParameterValues( Constants.SERVLET_PARAM_OPTIMIZATION_PARAM_PREFIX + stub.getName()); try { stub.htmlInputFormToValue(values); } catch (InvalidValueException ive) {} } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + stub.getDisplayName() + (stub.isRequired() ? star : "") + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" " + stub.getHTMLInputForm( Constants.SERVLET_PARAM_OPTIMIZATION_PARAM_PREFIX) + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The list of job-specific parameters. params = job.getParameterStubs().clone().getParameters(); for (int i=0; i < params.length; i++) { Parameter stub = params[i]; if (confirmed) { String[] values = request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + stub.getName()); try { stub.htmlInputFormToValue(values); } catch (InvalidValueException ive) { Parameter p = job.getParameterList().getParameter(stub.getName()); if (p != null) { stub.setValueFrom(p); } } } else { Parameter p = job.getParameterList().getParameter(stub.getName()); if (p != null) { stub.setValueFrom(p); } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + stub.getDisplayName() + (stub.isRequired() ? star : "") + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" " + stub.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The comments field. String comments = request.getParameter(Constants.SERVLET_PARAM_JOB_COMMENTS); if (comments == null) { comments = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Comments</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_COMMENTS + "\" ROWS=\"5\" " + "COLS=\"80\">" + comments + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The submit button. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); if (job.getJobClass().providesParameterTest()) { htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"" + Constants.SUBMIT_STRING_TEST_PARAMS + "\">" + EOL); htmlBody.append("    " + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Schedule\">" + EOL); htmlBody.append("    " + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"" + Constants.SUBMIT_STRING_CANCEL + "\">" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } /** * Generates a form that allows the user to schedule a self-optimizing job * based on a previous optimizing job. * * @param requestInfo The state information for this request. */ static void generateCloneOptimizingJobForm(RequestInfo requestInfo) { logMessage(requestInfo, "In generateCloneOptimizeJobForm()"); // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // Get the job ID for the optimizing job. String optimizingJobID = request.getParameter(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID); if (optimizingJobID == null) { infoMessage.append("ERROR: Unable to determine the job ID for the " + "optimizing job to clone<BR>" + EOL); handleViewOptimizing(requestInfo, true); return; } // Get the optimizing job with the provided ID. OptimizingJob optimizingJob; try { optimizingJob = getOptimizingJob(optimizingJobID); } catch (Exception e) { infoMessage.append("ERROR: Unable to retrieve optimizing job " + optimizingJobID + " from the configuration " + "directory -- " + e + "<BR>" + EOL); handleViewOptimizing(requestInfo, true); return; } if (optimizingJob == null) { infoMessage.append("ERROR: Unable to retrieve optimizing job " + optimizingJobID + " from the configuration " + "directory<BR>" + EOL); handleViewOptimizing(requestInfo, true); return; } int jobNumClients = optimizingJob.getJobClass().overrideNumClients(); int jobInterval = optimizingJob.getJobClass().overrideCollectionInterval(); // See if the job class is deprecated. If so, then add a warning message at // the top of the page. StringBuilder deprecatedMessage = new StringBuilder(); if (optimizingJob.getJobClass().isDeprecated(deprecatedMessage)) { infoMessage.append("WARNING: This job class has been deprecated."); if (deprecatedMessage.length() > 0) { infoMessage.append(" "); infoMessage.append(deprecatedMessage); } infoMessage.append("<BR><BR>" + EOL); } String star = "<SPAN CLASS=\"" + Constants.STYLE_WARNING_TEXT + "\">*</SPAN>"; htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Clone Optimizing Job " + optimizingJobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Enter the following information about the way in which " + "the optimization should proceed." + EOL); htmlBody.append("Note that parameters marked with an asterisk (" + star + ") are required to have a value." + EOL); String link = generateNewWindowLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_OPTIMIZE_HELP, Constants.SERVLET_PARAM_JOB_CLASS, optimizingJob.getJobClassName(), Constants.SERVLET_PARAM_OPTIMIZATION_ALGORITHM, optimizingJob.getOptimizationAlgorithm().getClass(). getName(), "Click here for help regarding these parameters"); htmlBody.append(link + '.' + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM CLASS=\"" + Constants.STYLE_MAIN_FORM + "\" METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_OPTIMIZE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_CLASS, optimizingJob.getJobClassName()) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZATION_ALGORITHM, optimizingJob.getOptimizationAlgorithm().getClass(). getName()) + EOL); if (jobNumClients > 0) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_NUM_CLIENTS, String.valueOf(jobNumClients)) + EOL); } if (jobInterval > 0) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL, secondsToHumanReadableDuration(jobInterval)) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); // The description for the job. String description = request.getParameter(Constants.SERVLET_PARAM_JOB_DESCRIPTION); if ((description == null) || (description.length() == 0)) { description = optimizingJob.getDescription(); if (description == null) { description = ""; } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DESCRIPTION + "\" VALUE=\"" + description + "\" SIZE=\"80\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to include the number of threads in the description. boolean includeThreadInDescription = optimizingJob.includeThreadsInDescription(); String includeThreadStr = request.getParameter( Constants.SERVLET_PARAM_JOB_INCLUDE_THREAD_IN_DESCRIPTION); if (includeThreadStr != null) { includeThreadInDescription = (includeThreadStr.equalsIgnoreCase("true") || includeThreadStr.equalsIgnoreCase("yes") || includeThreadStr.equalsIgnoreCase("on") || includeThreadStr.equalsIgnoreCase("one")); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Include Thread Count in Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_INCLUDE_THREAD_IN_DESCRIPTION + '"' + (includeThreadInDescription ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to display the job in restricted read-only mode. boolean displayInReadOnlyMode = false; String displayStr = request.getParameter(Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY); if (displayStr != null) { displayInReadOnlyMode = (displayStr.equalsIgnoreCase("true") || displayStr.equalsIgnoreCase("yes") || displayStr.equalsIgnoreCase("on") || displayStr.equalsIgnoreCase("1")); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Display In Read-Only Mode</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY + '"' + (displayInReadOnlyMode ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The name of the folder to use for the job. JobFolder[] folders = null; try { folders = configDB.getFolders(); } catch (DatabaseException de) {} if ((folders != null) && (folders.length > 0)) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Place in Folder</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_FOLDER + "\">" + EOL); for (int i=0; i < folders.length; i++) { if ((optimizingJob.getFolderName() != null) && optimizingJob.getFolderName().equalsIgnoreCase( folders[i].getFolderName())) { htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + "\" SELECTED>" + folders[i].getFolderName() + EOL); } else { htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + "\">" + folders[i].getFolderName() + EOL); } } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The start time for the job. This will not be set from the provided job. String startTimeStr = request.getParameter(Constants.SERVLET_PARAM_JOB_START_TIME); if ((startTimeStr == null) || (startTimeStr.length() == 0)) { if (populateStartTime) { startTimeStr = dateFormat.format(new Date()); } else { startTimeStr = ""; } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Start Time <FONT SIZE=\"-1\">(YYYYMMDDhhmmss)" + "</FONT></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_START_TIME + "\" VALUE=\"" + startTimeStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The duration for the job. int duration = optimizingJob.getDuration(); String durationStr; if (duration > 0) { durationStr = secondsToHumanReadableDuration(duration); } else { durationStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Duration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DURATION + "\" VALUE=\"" + durationStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The delay that should be included between the individual copies of the // job. String delayStr = String.valueOf(optimizingJob.getDelayBetweenIterations()); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Delay Between Iterations " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_TIME_BETWEEN_STARTUPS + "\" VALUE=\"" + delayStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of clients to use. if (jobNumClients <= 0) { String clientsStr = String.valueOf(optimizingJob.getNumClients()); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Number of Clients " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_NUM_CLIENTS + "\" VALUE=\"" + clientsStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The specific set of clients to use. String clientsStr; String[] clients = optimizingJob.getRequestedClients(); if ((clients == null) || (clients.length == 0)) { clientsStr = ""; } else { clientsStr = clients[0]; for (int i=1; i < clients.length; i++) { clientsStr += '\n' + clients[i]; } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Use Specific Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_CLIENTS + "\" ROWS=\"5\" " + "COLS=\"40\">" + clientsStr + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The set of resource monitor clients to use. String[] monitorClients = optimizingJob.getResourceMonitorClients(); if ((monitorClients == null) || (monitorClients.length == 0)) { clientsStr = ""; } else { clientsStr = monitorClients[0]; for (int i=1; i < monitorClients.length; i++) { clientsStr += '\n' + monitorClients[i]; } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Resource Monitor Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS + "\" ROWS=\"5\" COLS=\"40\">" + clientsStr + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to automatically monitor client systems if available. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Monitor Clients if Available</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_MONITOR_CLIENTS_IF_AVAILABLE + '"' + (optimizingJob.monitorClientsIfAvailable() ? " CHECKED" : "") + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The minimum number of threads to use. String minThreadsStr = String.valueOf(optimizingJob.getMinThreads()); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Minimum Number of Threads " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREADS_MIN + "\" VALUE=\"" + minThreadsStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The maximum number of threads to use. int maxThreads = optimizingJob.getMaxThreads(); String maxThreadsStr; if (maxThreads > 0) { maxThreadsStr = String.valueOf(maxThreads); } else { maxThreadsStr = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Maximum Number of Threads</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREADS_MAX + "\" VALUE=\"" + maxThreadsStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The thread increment to use. String incrementStr = String.valueOf(optimizingJob.getThreadIncrement()); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Thread Increment Between Iterations " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_THREAD_INCREMENT + "\" VALUE=\"" + incrementStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The thread startup delay to use. String startupDelayStr = String.valueOf(optimizingJob.getThreadStartupDelay()); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Thread Startup Delay (ms)</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_THREAD_STARTUP_DELAY + "\" VALUE=\"" + startupDelayStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The statistics collection interval. if (jobInterval <= 0) { String intervalStr = secondsToHumanReadableDuration( optimizingJob.getCollectionInterval()); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Statistics Collection Interval</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_COLLECTION_INTERVAL + "\" VALUE=\"" + intervalStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The number of consecutive non-improving results before ending testing. String maxNonImprovingStr = String.valueOf(optimizingJob.getMaxNonImproving()); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Max. Consecutive Non-Improving Iterations " + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_MAX_NON_IMPROVING + "\" VALUE=\"" + maxNonImprovingStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to re-run the best iteration of the optimizing job once it is // found. boolean reRunBestIteration = optimizingJob.reRunBestIteration(); String checkedStr = (reRunBestIteration ? " CHECKED" : ""); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Re-Run Best Iteration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_RERUN_BEST_ITERATION + '"' + checkedStr + "></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The duration to use when re-running the best iteration. String reRunDurationStr = ""; if (optimizingJob.getReRunDuration() > 0) { reRunDurationStr = secondsToHumanReadableDuration(optimizingJob.getReRunDuration()); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Re-Run Duration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_RERUN_DURATION + "\" VALUE=\"" + reRunDurationStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The dependencies for this job. This will not be set from the provided // optimizing job. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Dependencies</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_DEPENDENCY + "\">" + EOL); htmlBody.append(" <OPTION VALUE=\"\">No Dependency" + EOL); Job[] pendingJobs = scheduler.getPendingJobs(); Job[] runningJobs = scheduler.getRunningJobs(); OptimizingJob[] optimizingJobs; try { optimizingJobs = scheduler.getUncompletedOptimizingJobs(); if (optimizingJobs == null) { optimizingJobs = new OptimizingJob[0]; } } catch (SLAMDServerException sse) { infoMessage.append("ERROR: Unable to get the list of uncompleted " + "optimizing jobs to use in the dependency list -- " + sse + "<BR>" + EOL); optimizingJobs = new OptimizingJob[0]; } for (int j=0; j < pendingJobs.length; j++) { description = pendingJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + pendingJobs[j].getJobID() + "\">" + pendingJobs[j].getJobID() + " -- Pending " + pendingJobs[j].getJobName() + description + EOL); } for (int j=0; j < runningJobs.length; j++) { description = runningJobs[j].getJobDescription(); if (description == null) { description = ""; } else if (description.length() > 0) { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + runningJobs[j].getJobID() + "\">" + runningJobs[j].getJobID() + " -- Running " + runningJobs[j].getJobName() + description + EOL); } for (int j=0; j < optimizingJobs.length; j++) { description = optimizingJobs[j].getDescription(); if (description == null) { description = ""; } else { description = " -- " + description; } htmlBody.append(" <OPTION VALUE=\"" + optimizingJobs[j].getOptimizingJobID() + "\">" + optimizingJobs[j].getOptimizingJobID() + " -- Optimizing " + optimizingJobs[j].getJobClass().getJobName() + description + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The e-mail address(es) to notify when the job is complete. if (slamdServer.getMailer().isEnabled()) { String[] notifyAddresses = optimizingJob.getNotifyAddresses(); String mailStr; if ((notifyAddresses == null) || (notifyAddresses.length == 0)) { mailStr = ""; } else { mailStr = notifyAddresses[0]; for (int i=1; i < notifyAddresses.length; i++) { mailStr += ", " + notifyAddresses[i]; } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Notify on Completion</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_NOTIFY_ADDRESS + "\" VALUE=\"" + mailStr + "\" SIZE=\"40\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The list of optimization-algorithm specific parameters. Parameter[] stubs = optimizingJob.getOptimizationParameterStubs().clone(). getParameters(); ParameterList paramList = optimizingJob.getOptimizationParameters(); for (int i=0; i < stubs.length; i++) { Parameter p = paramList.getParameter(stubs[i].getName()); if (p != null) { try { stubs[i].setValueFrom(p); } catch (Exception e) { e.printStackTrace(); } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + stubs[i].getDisplayName() + (stubs[i].isRequired() ? star : "") + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" " + stubs[i].getHTMLInputForm( Constants.SERVLET_PARAM_OPTIMIZATION_PARAM_PREFIX) + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The list of job-specific parameters. Parameter[] params = optimizingJob.getJobClass().getParameterStubs(). clone().getParameters(); for (int i=0; i < params.length; i++) { Parameter stub = params[i]; Parameter p = optimizingJob.getParameters().getParameter(stub.getName()); if (p != null) { stub.setValueFrom(p); } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + stub.getDisplayName() + (stub.isRequired() ? star : "") + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" " + stub.getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } // The comments field. String comments = request.getParameter(Constants.SERVLET_PARAM_JOB_COMMENTS); if (comments == null) { comments = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Comments</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_COMMENTS + "\" ROWS=\"5\" " + "COLS=\"80\">" + comments + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The submit button. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); if (optimizingJob.getJobClass().providesParameterTest()) { htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"" + Constants.SUBMIT_STRING_TEST_PARAMS + "\">" + EOL); htmlBody.append("    " + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Schedule\">" + EOL); htmlBody.append("    " + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"" + Constants.SUBMIT_STRING_CANCEL + "\">" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } /** * Generates an HTML page that may be used to display information that can * help a user understand the kinds of information that should be provided * when scheduling an optimizing job. * * @param requestInfo The state information for this request. */ static void generateOptimizeHelpPage(RequestInfo requestInfo) { logMessage(requestInfo, "In generateOptimizeHelpPage()"); // If the user doesn't have schedule permission, then they can't see this if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "schedule jobs for execution."); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; StringBuilder htmlBody = requestInfo.htmlBody; htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Help for Scheduling an Optimizing Job</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("The following parameters may be specified when " + "scheduling an optimizing job:" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<TABLE BORDER=\"1\">" + EOL); // The job description htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Description</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" A string that can contain any kind of " + "information about this job." + EOL); htmlBody.append(" It is only used for display in the " + "administrative interface to help users more quickly " + "determine the purpose of a particular job." + EOL); htmlBody.append(" This parameter is optional." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to include thread count in description htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Include Thread Count in Description</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" Indicates whether the description for each " + "individual job in this set should include the number " + "of threads used for that job." + EOL); htmlBody.append(" This is a convenience feature for use when " + "comparing or graphing the jobs run as part of an " + "optimizing job." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The start time htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Start Time</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The time at which the first iteration of this " + "optimizing job should start running." + EOL); htmlBody.append(" It should be specified using the 14-digit form " + "\"YYYYMMDDhhmmss\"." + EOL); htmlBody.append(" If it is not provided, then the current time will " + "be used and the job will be considered immediately " + "eligible for execution." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The duration htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Duration</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The maximum length of time in seconds that each " + "iteration should be allowed to run before it is stopped." + EOL); htmlBody.append(" If you leave the value unspecified, then the " + "job will continue running until it has completed, or " + "until it is stopped by an administrator." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The delay between iterations. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Delay Between Iterations</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The length of time in seconds that should elapse " + "between the end of one job iteration and the beginning " + "of the next." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The number of clients htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Number of Clients</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The number of clients that should be used to run " + "this job." + EOL); htmlBody.append(" Note that the specified number of clients must be " + "available when the start time is reached or the job " + "will not be able to run." + EOL); htmlBody.append(" This is a required parameter." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The requested clients htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Use Specific Clients</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The addresses of specific client systems that " + "should be used to run the job." + EOL); htmlBody.append(" The addresses may be either DNS-resolvable host " + "names or IP addresses." + EOL); htmlBody.append(" A separate address should be used per line." + EOL); htmlBody.append(" If no set of clients is specified, then any " + "available clients will be used, up to the specified " + "number of clients." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The resource monitor clients htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Resource Monitor Clients</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The addresses of the resource monitor client " + "systems that should be used for the job." + EOL); htmlBody.append(" The addresses may be either DNS-resolvable host " + "names or IP addresses." + EOL); htmlBody.append(" A separate address should be used per line." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // Whether to automatically monitor client systems htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Monitor Clients if Available</TD>" + EOL); htmlBody.append(" <TD>"); htmlBody.append(" Indicates whether the job should automatically " + "attempt to use any resource monitor clients that are " + "running on client system(s) when the job is running." + EOL); htmlBody.append(" If so, then any clients used that also have " + "resource monitors running will report resource monitor " + "statistics for the job." + EOL); htmlBody.append(" If no resource monitor client is available on one " + "or more client systems, then the job will still be " + "processed by those clients but no monitor information " + "will be collected for those systems." + EOL); htmlBody.append(" </TD>"); htmlBody.append(" </TR>" + EOL); // The minimum number of threads htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Minimum Number of Threads</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The minimum number of threads that should be used " + "by each client when trying to determine the optimal " + "performance for the specified statistic." + EOL); htmlBody.append(" The first iteration of this optimizing job will " + "use this number of threads, and then each iteration " + "thereafter will use an increasingly greater number of " + "threads per client." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The maximum number of threads htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Maximum Number of Threads</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The maximum number of threads per client that " + "should be used when trying to determine the optimal " + "performance for the specified statistic." + EOL); htmlBody.append(" Note that if this is too low, then it may cause " + "the optimization process to stop before it has " + "identified the optimum value for the specified " + "statistic." + EOL); htmlBody.append(" Also note that the optimization process may stop " + "before this number of threads has been reached if " + "the maximum number of consecutive non-improving " + "iterations has been reached." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The thread increment between iterations htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Thread Increment Between Iterations</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The increment by which the number of threads per " + "client should be raised between iterations of this " + "optimizing job." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The collection interval htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Statistics Collection Interval</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The length of time in seconds for a statistics " + "collection interval." + EOL); htmlBody.append(" In addition to the summary statistics gathered " + "during job processing, the time that a job is running " + "will be broken up into intervals of this length and " + "statistics will be made available for each of those " + "intervals." + EOL); htmlBody.append(" If no value is specified, a default of " + Constants.DEFAULT_COLLECTION_INTERVAL + " seconds will be used." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The maximum number of non-improving iterations htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Max. Consecutive Non-Improving " + "Iterations</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" Specifies the maximum number of consecutive " + "non-improving job iterations that will be allowed " + "before the optimization process completes." + EOL); htmlBody.append(" A non-improving job iteration is any job " + "iteration in which the value for the specified statistic" + "is not closer to the optimum value than any of the " + "previous iterations." + EOL); htmlBody.append(" For an optimization type of \"maximize\", this " + "would be any job that does not yield a higher value " + "for the tracked statistic than all previous iterations." + EOL); htmlBody.append(" For an optimization type of \"minimize\", this " + "would be any job that does not yield a lower value " + "for the tracked statistic than all previous iterations." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The job dependencies htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Job Dependencies</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The set of jobs that must complete running before " + "this job will be considered eligible to run." + EOL); htmlBody.append(" If dependencies are specified and at least one " + "on which this job is dependent has not yet completed " + "running when the start time for this job arrives, then " + "the execution of this job will be delayed until all " + "dependencies have been fulfilled." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // The e-mail address(es) to notify on completion of this job. htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Notify on Completion</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" The e-mail address(es) of the user(s) that should " + "be sent an e-mail message when the optimization process " + "has completed." + EOL); htmlBody.append(" This message will contain a summary of the " + "job execution results and may optionally include a " + "link to view more information about the job through the " + "SLAMD administrative interface." + EOL); htmlBody.append(" If multiple addresses should be notified, then " + "they should be separated with spaces and/or commas." + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); // See if a job class has been provided. We will need that for both the // optimization algorithm and the job-specific parameters. String jobClassName = request.getParameter(Constants.SERVLET_PARAM_JOB_CLASS); JobClass jobClass = null; if ((jobClassName != null) && (jobClassName.length() > 0) && ((jobClass = slamdServer.getJobClass(jobClassName)) != null)) { // See if an optimization algorithm has been provided. If so, then provide // help information for those parameters as well. String optimizationAlgorithmName = request.getParameter(Constants.SERVLET_PARAM_OPTIMIZATION_ALGORITHM); if ((optimizationAlgorithmName != null) && (optimizationAlgorithmName.length() > 0)) { OptimizationAlgorithm optimizationAlgorithm = slamdServer.getOptimizationAlgorithm(optimizationAlgorithmName); if (optimizationAlgorithm != null) { Parameter[] stubs = optimizationAlgorithm. getOptimizationAlgorithmParameterStubs(jobClass).clone(). getParameters(); for (int i=0; i < stubs.length; i++) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + stubs[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD>" + EOL); String description = replaceText(stubs[i].getDescription(), "\r\n", "<BR>"); description = replaceText(description, "\n", "<BR>"); description = replaceText(description, "\t", "      " + "  "); htmlBody.append(" " + description + EOL); if (stubs[i].isRequired()) { htmlBody.append(" <BR>" + EOL); htmlBody.append(" This is a required parameter." + EOL); } htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } } Parameter[] stubs = jobClass.getParameterStubs().clone().getParameters(); for (int i=0; i < stubs.length; i++) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + stubs[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD>" + EOL); String description = replaceText(stubs[i].getDescription(), "\r\n", "<BR>"); description = replaceText(description, "\n", "<BR>"); description = replaceText(description, "\t", "      " + "  "); htmlBody.append(" " + description + EOL); if (stubs[i].isRequired()) { htmlBody.append(" <BR>" + EOL); htmlBody.append(" This is a required parameter." + EOL); } htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } htmlBody.append("</TABLE>" + EOL); } /** * Handles the work of viewing information about one or multiple optimizing * jobs. * * @param requestInfo The state information for this request. * @param showAll Indicates whether information about all optimizing * jobs should be shown even if an optimizing job ID * has been provided. */ static void handleViewOptimizing(RequestInfo requestInfo, boolean showAll) { HttpServletRequest request = requestInfo.request; String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); handleViewOptimizing(requestInfo, showAll, folderName); } /** * Handles the work of viewing information about one or multiple optimizing * jobs. * * @param requestInfo The state information for this request. * @param showAll Indicates whether information about all optimizing * jobs should be shown even if an optimizing job ID * has been provided. * @param folderName The name of the job folder that should be * displayed. */ static void handleViewOptimizing(RequestInfo requestInfo, boolean showAll, String folderName) { logMessage(requestInfo, "In generateOptimizeHelpPage()"); // If the user doesn't have permission to view jobs, then they can't see // this if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "view job information."); return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // See if an optimizing job ID has been specified. If so, then show that // specific job. If not, then show the list of all optimizing jobs. if (! showAll) { String optimizingJobID = request.getParameter(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID); if ((optimizingJobID != null) && (optimizingJobID.length() > 0)) { generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } } if ((folderName == null) || (folderName.length() == 0)) { folderName = Constants.FOLDER_NAME_UNCLASSIFIED; } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">View Optimizing Jobs</SPAN>" + EOL); htmlBody.append("<BR>" + EOL); String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, Constants.SERVLET_PARAM_JOB_FOLDER, folderName, "Switch to completed jobs for this folder"); htmlBody.append(link + EOL); htmlBody.append("<BR><BR>" + EOL); JobFolder folder = null; JobFolder[] folders = null; try { folders = configDB.getFolders(); } catch (DatabaseException de) {} if ((folders != null) && (folders.length > 0)) { htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" View Optimizing Jobs in Folder" + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_FOLDER + "\">" + EOL); for (int i=0; i < folders.length; i++) { String selectedStr; if ((folderName != null) && folderName.equals(folders[i].getFolderName())) { selectedStr = "SELECTED "; folder = folders[i]; } else { selectedStr = ""; } htmlBody.append(" <OPTION " + selectedStr + "VALUE=\"" + folders[i].getFolderName() + "\">" + folders[i].getFolderName() + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Refresh\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR>" + EOL); } else { htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Refresh\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR>" + EOL); } if (requestInfo.mayScheduleJob) { htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_OPTIMIZE) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" Schedule an optimizing " + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_CLASS + "\">" + EOL); JobClass[][] jobClasses = slamdServer.getCategorizedJobClasses(); for (int i=0; i < jobClasses.length; i++) { for (int j=0; j < jobClasses[i].length; j++) { String category = jobClasses[i][j].getJobCategoryName(); if ((category == null) || (category.length() == 0)) { category = "Unclassified"; } htmlBody.append(" <OPTION VALUE=\"" + jobClasses[i][j].getClass().getName() + "\">" + category + " -- " + jobClasses[i][j].getJobName() + EOL); } } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" job." + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Submit\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR><BR>" + EOL); } if (folder != null) { htmlBody.append("<B>Jobs for Folder " + folder.getFolderName() + "</B>" + EOL); htmlBody.append("<BR>" + EOL); String description = folder.getDescription(); if ((description != null) && (description.length() > 0)) { htmlBody.append("<BLOCKQUOTE>" + description + "</BLOCKQUOTE>" + EOL); } if (requestInfo.mayManageFolders) { htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_OPTIMIZING_FOLDER_DESCRIPTION) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); if (requestInfo.debugHTML) { htmlBody.append( generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"Edit Description\">" + EOL); htmlBody.append("</FORM>" + EOL); } htmlBody.append("<BR>" + EOL); if (requestInfo.mayManageFolders && enableReadOnlyManagement) { if (folder.displayInReadOnlyMode()) { htmlBody.append("This folder is currently visible in " + "restricted read-only mode." + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_OPTIMIZING_FOLDER_PUBLISH) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); if (requestInfo.debugHTML) { htmlBody.append( generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_DEPUBLISH_FOLDER + "\">" + EOL); htmlBody.append("  " + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_DEPUBLISH_FOLDER_JOBS + "\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR>" + EOL); } else { htmlBody.append("This folder is currently not visible in " + "restricted read-only mode." + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_OPTIMIZING_FOLDER_PUBLISH) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); if (requestInfo.debugHTML) { htmlBody.append( generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_PUBLISH_FOLDER + "\">" + EOL); htmlBody.append("  " + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_PUBLISH_FOLDER_JOBS + "\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR>" + EOL); } } } // Get the list of optimizing jobs that have been defined in the config // directory. OptimizingJob[] optimizingJobs = null; try { optimizingJobs = configDB.getSummaryOptimizingJobs(folderName); } catch (Exception e) { infoMessage.append("ERROR: Unable to retrieve the set of optimizing " + "jobs -- " + e.getMessage() + "<BR>" + EOL); htmlBody.append("Unable to retrieve the set of optimizing jobs." + EOL); return; } if ((optimizingJobs == null) || (optimizingJobs.length == 0)) { if ((folders == null) || (folders.length == 0)) { htmlBody.append("There are no optimizing jobs in the " + "configuration directory.<BR><BR>" + EOL); } else { if ((folderName == null) || (folderName.length() == 0)) { htmlBody.append("There are no optimizing jobs in the " + Constants.FOLDER_NAME_UNCLASSIFIED + "\" job folder.<BR><BR>" + EOL); } else { htmlBody.append("There are no optimizing jobs in the " + folderName + "\" job folder.<BR><BR>" + EOL); } } } else { htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_MASS_OPTIMIZING) + EOL); if (folderName != null) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\" CELLSPACING=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); if (! readOnlyMode) { htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); } htmlBody.append(" <TD><B>Job ID</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><B>Description</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><B>Job Type</B></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><B>Actual Start Time</B></TD>" + EOL); if (enableReadOnlyManagement && (! readOnlyMode)) { htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><B>Read-Only Status</B></TD>" + EOL); } htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><B>Current State</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); boolean selectAll = false; boolean deselectAll = false; String submitStr = request.getParameter(Constants.SERVLET_PARAM_SUBMIT); if ((submitStr != null) && submitStr.equals(Constants.SUBMIT_STRING_SELECT_ALL)) { selectAll = true; } else if ((submitStr != null) && submitStr.equals(Constants.SUBMIT_STRING_DESELECT_ALL)) { deselectAll = true; } String[] selectedJobs = request.getParameterValues( Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID); for (int i=0; i < optimizingJobs.length; i++) { if ((i % 2) == 0) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); } else { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); } String checkedStr = ""; String jobID = optimizingJobs[i].getOptimizingJobID(); if (! readOnlyMode) { if (selectAll) { checkedStr = " CHECKED"; } else if (! deselectAll) { if (selectedJobs != null) { for (int j=0; j < selectedJobs.length; j++) { if (selectedJobs[j].equals(jobID)) { checkedStr = " CHECKED"; break; } } } } htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID + "\" VALUE=\"" + jobID + '"' + checkedStr + "></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); } link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING, Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, jobID, jobID); htmlBody.append(" <TD>" + link + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); String description = optimizingJobs[i].getDescription(); if (description == null) { description = ""; } htmlBody.append(" <TD>" + description + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); String jobName = optimizingJobs[i].getJobClass().getJobName(); htmlBody.append(" <TD>" + jobName + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); String startTimeStr; Date startTime = optimizingJobs[i].getActualStartTime(); if (startTime == null) { startTime = optimizingJobs[i].getStartTime(); } if (startTime == null) { startTimeStr = ""; } else { startTimeStr = displayDateFormat.format(startTime); } htmlBody.append(" <TD>" + startTimeStr + "</TD>" + EOL); if (enableReadOnlyManagement && (! readOnlyMode)) { htmlBody.append(" <TD> </TD>" + EOL); if (optimizingJobs[i].displayInReadOnlyMode()) { htmlBody.append(" <TD>Published</TD>" + EOL); } else { htmlBody.append(" <TD>Not Published</TD>" + EOL); } } String stateStr; switch (optimizingJobs[i].getJobState()) { case Constants.JOB_STATE_CANCELLED: case Constants.JOB_STATE_STOPPED_BY_USER: stateStr = "Cancelled"; break; case Constants.JOB_STATE_COMPLETED_SUCCESSFULLY: case Constants.JOB_STATE_COMPLETED_WITH_ERRORS: case Constants.JOB_STATE_STOPPED_DUE_TO_DURATION: case Constants.JOB_STATE_STOPPED_DUE_TO_STOP_TIME: stateStr = "Completed"; break; case Constants.JOB_STATE_DISABLED: stateStr = "Disabled"; break; case Constants.JOB_STATE_NOT_YET_STARTED: case Constants.JOB_STATE_UNINITIALIZED: stateStr = "Pending"; break; case Constants.JOB_STATE_RUNNING: stateStr = "Running"; break; case Constants.JOB_STATE_STOPPED_BY_SHUTDOWN: case Constants.JOB_STATE_STOPPED_DUE_TO_ERROR: stateStr = "Stopped"; break; default: stateStr = "Unknown"; break; } htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + stateStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append(" </TABLE>" + EOL); if (! readOnlyMode) { ArrayList<String> actions = new ArrayList<String>(); actions.add(Constants.SUBMIT_STRING_SELECT_ALL); actions.add(Constants.SUBMIT_STRING_DESELECT_ALL); if (requestInfo.mayDeleteJob) { actions.add(Constants.SUBMIT_STRING_DELETE); } if (requestInfo.mayManageFolders) { if ((folders != null) && (folders.length > 0)) { actions.add(Constants.SUBMIT_STRING_MOVE); } if (enableReadOnlyManagement) { actions.add(Constants.SUBMIT_STRING_PUBLISH_JOBS); actions.add(Constants.SUBMIT_STRING_DEPUBLISH_JOBS); } } if ((reportGenerators != null) && (reportGenerators.length > 0)) { actions.add(Constants.SUBMIT_STRING_GENERATE_REPORT); } htmlBody.append(" <TABLE BORDER=\"0\" WIDTH=\"100%\">" + EOL); htmlBody.append(" <TR>" + EOL); for (int i=0; i < actions.size(); i++) { htmlBody.append(" <TD WIDTH=\"20%\" ALIGN=\"CENTER\"><INPUT " + "TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + actions.get(i) + "\">" + EOL); if (((i % 4) == 3) && ((i+1) < actions.size())) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } if ((actions.size() % 4) != 0) { for (int i=0; i < (4 - (actions.size() % 4)); i++) { htmlBody.append(" <TD> </TD>" + EOL); } } htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); } htmlBody.append("</FORM>" + EOL); } // The remainder of this section deals with file uploads. If the file // upload capability has been disabled, then don't add that content to // the page. if (disableUploads) { return; } htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Uploaded Files</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); UploadedFile[] files = null; try { files = configDB.getUploadedFiles(folderName); } catch (DatabaseException de) { infoMessage.append("Unable to retrieve uploaded file list -- " + de.getMessage() + "<BR>" + EOL); } if ((files == null) || (files.length == 0)) { htmlBody.append("No files have been uploaded into this folder." + EOL); } else { htmlBody.append("The following files have been uploaded:" + EOL); htmlBody.append("<TABLE BORDER=\"1\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><B>File Name</B></TD>" + EOL); htmlBody.append(" <TD><B>File Type</B></TD>" + EOL); htmlBody.append(" <TD><B>File Size (bytes)</B></TD>" + EOL); htmlBody.append(" <TD><B>Description</B></TD>" + EOL); htmlBody.append(" <TD><B>Action</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); for (int i=0; i < files.length; i++) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + files[i].getFileName() + "</TD>" + EOL); htmlBody.append(" <TD>" + files[i].getFileType() + "</TD>" + EOL); htmlBody.append(" <TD>" + files[i].getFileSize() + "</TD>" + EOL); String desc = files[i].getFileDescription(); if ((desc == null) || (desc.length() == 0)) { desc = " "; } htmlBody.append(" <TD>" + desc + "</TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\" TARGET=\"_BLANK\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_UPLOAD) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_ACTION, Constants.FILE_ACTION_VIEW) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_NAME, files[i].getFileName()) +EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_IN_OPTIMIZING, "true") + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"View\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_UPLOAD) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_ACTION, Constants.FILE_ACTION_SAVE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_NAME, files[i].getFileName()) +EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_IN_OPTIMIZING, "true") + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"Save\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); if (requestInfo.mayManageFolders) { htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_UPLOAD) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_FILE_ACTION, Constants.FILE_ACTION_EDIT_TYPE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_NAME, files[i].getFileName()) +EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_IN_OPTIMIZING, "true") + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"Edit MIME Type\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_UPLOAD) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_FILE_ACTION, Constants.FILE_ACTION_DELETE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_NAME, files[i].getFileName()) +EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_IN_OPTIMIZING, "true") + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"Delete\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); } htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append("</TABLE>" + EOL); } if (requestInfo.mayManageFolders) { htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_UPLOAD) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_ACTION, Constants.FILE_ACTION_UPLOAD) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_IN_OPTIMIZING, "true") + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Upload File\">" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Generates a page that may be used to view information about an optimizing * job. * * @param requestInfo The state information for this request. * @param optimizingJobID The unique ID of the optimizing job to display. */ static void generateViewOptimizingJobBody(RequestInfo requestInfo, String optimizingJobID) { logMessage(requestInfo, "In generateOptimizeHelpPage()"); // If the user doesn't have permission to view jobs, then they can't see // this if (! requestInfo.mayViewJob) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "view job information."); return; } // Get the important state information for this request. String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // Get the optimizing job to be viewed. OptimizingJob optimizingJob = null; try { optimizingJob = getOptimizingJob(optimizingJobID); if (optimizingJob == null) { throw new SLAMDException("Optimizing job " + optimizingJobID + " does not exist in the SLAMD database."); } } catch (Exception e) { infoMessage.append("ERROR: Unable to retrieve information for " + "optimizing job " + optimizingJobID + " -- " + e + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">View Optimizing Job</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("No information about optimizing job " + optimizingJobID + " could be retrieved from the configuration directory." + EOL); htmlBody.append("<BR><BR>" + EOL); String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING, "here"); htmlBody.append("Click " + link + " to return to the list of " + "optimizing jobs." + EOL); return; } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">View Optimizing Job " + optimizingJobID + "</SPAN>" + EOL); int buttonsAdded = 0; boolean isUnknownJob = ((optimizingJob == null) || (optimizingJob.getJobClass() == null) || (optimizingJob.getJobClass() instanceof UnknownJobClass)); htmlBody.append("<TABLE BORDER=\"0\" WIDTH=\"100%\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Refresh\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } JobFolder[] folders = null; try { folders = configDB.getFolders(); } catch (DatabaseException de) {} if (requestInfo.mayManageFolders && (folders != null) && (folders.length > 0)) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_MOVE_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Move\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } if (requestInfo.mayScheduleJob && (! isUnknownJob)) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_CLONE_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Clone\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } if (requestInfo.mayScheduleJob) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_EDIT_OPTIMIZING_COMMENTS) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Edit " + "Comments\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } if (optimizingJob.doneRunning()) { if (optimizingJob.hasStats()) { ArrayList<String> jobIDList = new ArrayList<String>(); Job[] jobs = optimizingJob.getAssociatedJobsIncludingReRun(); for (int i=0; i < jobs.length; i++) { if (jobs[i].hasStats()) { jobIDList.add(jobs[i].getJobID()); } } if (! jobIDList.isEmpty()) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_COMPARE) + EOL); for (int i=0; i < jobIDList.size(); i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDList.get(i)) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Compare\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } } Job[] jobs = optimizingJob.getAssociatedJobs(); if ((jobs != null) && (jobs.length > 0)) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_EXPORT) + EOL); for (int i=0; i < jobs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobs[i].getJobID()) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Export\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } if (requestInfo.mayDeleteJob) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_DELETE_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Delete\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } if ((reportGenerators != null) && (reportGenerators.length > 0)) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_GENERATE_REPORT) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" " + "VALUE=\"Generate Report\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if ((buttonsAdded % 5) == 0) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } } else { if (requestInfo.mayCancelJob) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_CANCEL_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Cancel\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; if (optimizingJob.pauseRequested()) { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_UNPAUSE_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Unpause\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; } else { htmlBody.append(" <TD ALIGN=\"CENTER\">" + EOL); htmlBody.append(" <FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_PAUSE_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Pause\">" + EOL); htmlBody.append(" </FORM>" + EOL); htmlBody.append(" </TD>" + EOL); buttonsAdded++; } } } while ((buttonsAdded % 5) != 0) { htmlBody.append(" <TD> </TD>" + EOL); buttonsAdded++; } htmlBody.append(" </TR>" + EOL); htmlBody.append("</TABLE>" + EOL); String folderName = optimizingJob.getFolderName(); if ((folderName != null) && (folderName.length() > 0)) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING, Constants.SERVLET_PARAM_JOB_FOLDER, folderName, folderName); htmlBody.append("Return to optimizing job folder " + link + '.' + EOL); htmlBody.append("<BR><BR>" + EOL); } htmlBody.append("<TABLE BORDER=\"0\" CELLSPACING=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>General Information</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Optimizing Job ID</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimizingJobID + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); JobClass jobClass = optimizingJob.getJobClass(); String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_CLASSES, Constants.SERVLET_PARAM_JOB_CLASS, jobClass.getClass().getName(), jobClass.getJobName()); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Job Type</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + link + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); String jobGroup = optimizingJob.getJobGroup(); if (jobGroup == null) { jobGroup = "(not specified)"; } else { jobGroup = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GROUP, Constants.SERVLET_PARAM_JOB_GROUP_NAME, jobGroup, jobGroup); } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Job Group</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + jobGroup + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); String descriptionStr = optimizingJob.getDescription(); if ((descriptionStr == null) || (descriptionStr.length() == 0)) { descriptionStr = "(not specified)"; } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Base Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + descriptionStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Include Thread Count in Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimizingJob.includeThreadsInDescription() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); String stateStr = Constants.jobStateToString(optimizingJob.getJobState()); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Current State</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + stateStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); String stopReason = optimizingJob.getStopReason(); if ((stopReason == null) || (stopReason.length() == 0)) { stopReason = "(not applicable)"; } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Stop Reason</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + stopReason + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); String comments = optimizingJob.getComments(); if ((comments == null) || (comments.length() == 0)) { comments = "(none)"; } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Comments</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + comments + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>Schedule Information</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); String startTimeStr = displayDateFormat.format(optimizingJob.getStartTime()); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Start Time</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + startTimeStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); String durationStr; if (optimizingJob.getDuration() > 0) { durationStr = secondsToHumanReadableDuration(optimizingJob.getDuration()); } else { durationStr = "(not specified)"; } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Job Duration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + durationStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Delay Between Iterations</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimizingJob.getDelayBetweenIterations() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Number of Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimizingJob.getNumClients() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); if (! (readOnlyMode && hideSensitiveInformation)) { String[] requestedClients = optimizingJob.getRequestedClients(); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Requested Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); if ((requestedClients == null) || (requestedClients.length == 0)) { htmlBody.append(" <TD>(none specified)</TD>" + EOL); } else { htmlBody.append(" <TD>" + EOL); for (int i=0; i < requestedClients.length; i++) { htmlBody.append(" " + requestedClients[i] + "<BR>" + EOL); } htmlBody.append(" </TD>" + EOL); } htmlBody.append(" </TR>" + EOL); String[] monitorClients = optimizingJob.getResourceMonitorClients(); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Resource Monitor Clients</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); if ((monitorClients == null) || (monitorClients.length == 0)) { htmlBody.append(" <TD>(none specified)</TD>" + EOL); } else { htmlBody.append(" <TD>" + EOL); for (int i=0; i < monitorClients.length; i++) { htmlBody.append(" " + monitorClients[i] + "<BR>" + EOL); } htmlBody.append(" </TD>" + EOL); } htmlBody.append(" </TR>" + EOL); } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Monitor Client If Available</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimizingJob.monitorClientsIfAvailable() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Minimum Number of Threads</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimizingJob.getMinThreads() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); String maxThreadStr; if (optimizingJob.getMaxThreads() > 0) { maxThreadStr = String.valueOf(optimizingJob.getMaxThreads()); } else { maxThreadStr = "(not specified)"; } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Maximum Number of Threads</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + maxThreadStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Thread Increment Between Iterations</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimizingJob.getThreadIncrement() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Thread Startup Delay (ms)</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimizingJob.getThreadStartupDelay() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Statistics Collection Interval</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + secondsToHumanReadableDuration(optimizingJob.getCollectionInterval()) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); if (! (readOnlyMode && hideSensitiveInformation)) { String[] notifyAddresses = optimizingJob.getNotifyAddresses(); String addressStr; if ((notifyAddresses == null) || (notifyAddresses.length == 0)) { addressStr = "(none specified)"; } else { addressStr = "<A HREF=\"mailto:" + notifyAddresses[0] + "\">" + notifyAddresses[0] + "</A>"; for (int i=1; i < notifyAddresses.length; i++) { addressStr += ", <A HREF=\"mailto:" + notifyAddresses[i] + "\">" + notifyAddresses[i] + "</A>"; } } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Notify on Completion</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + addressStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } String[] dependencies = optimizingJob.getDependencies(); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Job Dependencies</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); if ((dependencies == null) || (dependencies.length == 0)) { htmlBody.append(" (none specified)<BR>" + EOL); } else { for (int i=0; i < dependencies.length; i++) { if ((dependencies[i] == null) || (dependencies[i].length() == 0)) { // If somehow we have an empty dependency, then skip it. continue; } // Try to determine whether this dependency is for a normal or an // optimizing job. Job j = null; String dependencyStr = dependencies[i]; try { j = configDB.getJob(dependencies[i]); if (j != null) { link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, dependencies[i], dependencies[i]); String description = j.getJobDescription(); if (description == null) { description = ""; } else { description = " -- " + description; } dependencyStr = link + " -- " + j.getJobName() + description; } } catch (Exception e) {} if (j == null) { try { OptimizingJob oj = getOptimizingJob(dependencies[i]); if (oj != null) { link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING, Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, dependencies[i], dependencies[i]); String description = oj.getDescription(); if (description == null) { description = ""; } else { description = " -- " + description; } dependencyStr = link + " -- Optimizing " + oj.getJobClass().getJobName() + description; } } catch (Exception e) {} } htmlBody.append(" " + dependencyStr + "<BR>" + EOL); } } htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>Optimization Settings</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Max. Consecutive Non-Improving " + "Iterations</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimizingJob.getMaxNonImproving() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Re-Run Best Iteration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimizingJob.reRunBestIteration() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Re-Run Duration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + ((optimizingJob.getReRunDuration() > 0) ? secondsToHumanReadableDuration(optimizingJob.getReRunDuration()) : "(not specified)") + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Optimization Algorithm</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimizingJob.getOptimizationAlgorithm(). getOptimizationAlgorithmName() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); if (! (jobClass instanceof UnknownJobClass)) { Parameter[] parameters = optimizingJob.getOptimizationAlgorithm(). getOptimizationAlgorithmParameters().getParameters(); for (int i=0; i < parameters.length; i++) { if ((i % 2) == 0) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); } else { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); } if (parameters[i] instanceof PlaceholderParameter) { htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); } else if (readOnlyMode && hideSensitiveInformation && parameters[i].isSensitive()) { htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); } else { htmlBody.append(" <TD>" + parameters[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + parameters[i].getHTMLDisplayValue() + "</TD>" + EOL); } htmlBody.append(" </TR>" + EOL); } } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>Parameter Information</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); Parameter[] parameters = optimizingJob.getParameters().getParameters(); for (int i=0; i < parameters.length; i++) { if ((i % 2) == 0) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); } else { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); } if (parameters[i] instanceof PlaceholderParameter) { htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); } else if (readOnlyMode && hideSensitiveInformation && parameters[i].isSensitive()) { htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); } else { htmlBody.append(" <TD>" + parameters[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + parameters[i].getHTMLDisplayValue() + "</TD>" + EOL); } htmlBody.append(" </TR>" + EOL); } Job[] jobIterations = optimizingJob.getAssociatedJobs(); if (optimizingJob.doneRunning()) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>Execution Data</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); Date actualStartTime = optimizingJob.getActualStartTime(); if (actualStartTime == null) { startTimeStr = "(not available)"; } else { startTimeStr = displayDateFormat.format(actualStartTime); } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Actual Start Time</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + startTimeStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); Date actualStopTime = optimizingJob.getActualStopTime(); String stopTimeStr; if (actualStopTime == null) { stopTimeStr = "(not available)"; } else { stopTimeStr = displayDateFormat.format(actualStopTime); } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Actual Stop Time</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + stopTimeStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); String iterationsStr; if (jobIterations == null) { iterationsStr = "0"; } else { iterationsStr = String.valueOf(jobIterations.length); } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Job Iterations Completed</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + iterationsStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); int optimalThreads = optimizingJob.getOptimalThreadCount(); double optimalValue = optimizingJob.getOptimalValue(); String optimalJobID = optimizingJob.getOptimalJobID(); if (optimalThreads > 0) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Optimal Thread Count</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + optimalThreads + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Optimal Value</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + decimalFormat.format(optimalValue) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, optimalJobID, optimalJobID); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Optimal Job Iteration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + link + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); String valueStr; Job reRunIteration = optimizingJob.getReRunIteration(); if (reRunIteration == null) { if (optimizingJob.reRunBestIteration()) { valueStr = "(not available)"; } else { valueStr = "(none specified)"; } } else { String jobID = reRunIteration.getJobID(); valueStr = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, jobID, jobID); } htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Re-Run of Best Iteration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + valueStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); if (reRunIteration != null) { String statString = "(not available)"; try { double value = optimizingJob.getOptimizationAlgorithm(). getIterationOptimizationValue(reRunIteration); statString = decimalFormat.format(value); } catch (Exception e) {} htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Re-Run Iteration Value</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + statString + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } else { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Optimal Thread Count</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>(not available)</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Optimal Value</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>(not available)</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Optimal Job Iteration</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>(not available)</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } } if ((jobIterations != null) && (jobIterations.length > 0)) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"> </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\"><B>Job Iterations</B></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD COLSPAN=\"3\" WIDTH=\"100%\">" + EOL); htmlBody.append(" <TABLE BORDER=\"0\" CELLSPACING=\"0\" " + "WIDTH=\"100%\">" + EOL); for (int i=0; i < jobIterations.length; i++) { if ((i % 2) == 0) { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); } else { htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); } link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, jobIterations[i].getJobID(), jobIterations[i].getJobID()); htmlBody.append(" <TD>" + link + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); String statString = " "; try { double value = optimizingJob.getOptimizationAlgorithm(). getIterationOptimizationValue(jobIterations[i]); statString = decimalFormat.format(value); } catch (Exception e) {} htmlBody.append(" <TD>" + statString + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); stateStr = Constants.jobStateToString(jobIterations[i].getJobState()); htmlBody.append(" <TD>" + stateStr + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append(" </TABLE>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append("</TABLE>" + EOL); } /** * Handles the work of cancelling an optimizing job in the SLAMD server. * * @param requestInfo The state information for this request. */ static void handleCancelOptimizingJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handleCancelOptimizingJob()"); // If the user doesn't have cancel permission, then they can't see this if (! requestInfo.mayCancelJob) { logMessage(requestInfo, "No mayCancelJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "cancel jobs."); return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // Get the job ID of the optimizing job to cancel. String optimizingJobID = request.getParameter(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID); if ((optimizingJobID == null) || (optimizingJobID.length() == 0)) { String message = "No optimizing job specified to cancel."; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); handleOptimizeJob(requestInfo); return; } // Get the optimizing job and make sure it exists. OptimizingJob optimizingJob; try { optimizingJob = getOptimizingJob(optimizingJobID); } catch (Exception e) { String message = "Could not retrieve optimizing job " + optimizingJobID + "from the configuration directory -- " + e; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); handleViewOptimizing(requestInfo, true); return; } if (optimizingJob == null) { String message = "Could not retrieve optimizing job " + optimizingJobID + "from the configuration directory."; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); handleViewOptimizing(requestInfo, true); return; } // See if the user has provided confirmation for the cancel. If not, then // request it. If so, then take the appropriate action. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && confirmStr.equalsIgnoreCase("Yes")) { try { optimizingJob.cancel(); infoMessage.append("A request has been submitted to cancel the " + "optimizing job. It may take some time for the " + "cancel to occur.<BR>" + EOL); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } catch (SLAMDServerException sse) { String message = "Unable to cancel optimizing job " + optimizingJobID + " -- " + sse; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } } else if ((confirmStr != null) && confirmStr.equalsIgnoreCase("No")) { infoMessage.append("Optimizing job " + optimizingJobID + " was not cancelled.<BR>" + EOL); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Cancel Optimizing Job " + optimizingJobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to cancel this job?" + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_CANCEL_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\" CELLPADDING=\"20\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Yes\"></TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"No\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles the work of pausing an optimizing job in the SLAMD server. * * @param requestInfo The state information for this request. */ static void handlePauseOptimizingJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handlePauseOptimizingJob()"); // If the user doesn't have cancel permission, then they can't see this if (! requestInfo.mayCancelJob) { logMessage(requestInfo, "No mayCancelJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "pause jobs."); return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // Get the job ID of the optimizing job to pause. String optimizingJobID = request.getParameter(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID); if ((optimizingJobID == null) || (optimizingJobID.length() == 0)) { String message = "No optimizing job specified to pause."; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); handleOptimizeJob(requestInfo); return; } // Get the optimizing job and make sure it exists. OptimizingJob optimizingJob; try { optimizingJob = getOptimizingJob(optimizingJobID); } catch (Exception e) { String message = "Could not retrieve optimizing job " + optimizingJobID + "from the configuration directory -- " + e; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); handleViewOptimizing(requestInfo, true); return; } if (optimizingJob == null) { String message = "Could not retrieve optimizing job " + optimizingJobID + "from the configuration directory."; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); handleViewOptimizing(requestInfo, true); return; } // See if the user has provided confirmation for the pause. If not, then // request it. If so, then take the appropriate action. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && confirmStr.equalsIgnoreCase("Yes")) { optimizingJob.pauseBeforeNextIteration(); infoMessage.append("A request has been submitted to pause the " + "optimizing job. The next iteration of this job " + "will be created as disabled and must be " + "manually enabled before it will run.<BR>" + EOL); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } else if ((confirmStr != null) && confirmStr.equalsIgnoreCase("No")) { infoMessage.append("Optimizing job " + optimizingJobID + " was not paused.<BR>" + EOL); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Pause Optimizing Job " + optimizingJobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to pause this optimizing " + "job?" + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_PAUSE_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\" CELLPADDING=\"20\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Yes\"></TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"No\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles the work of unpausing an optimizing job in the SLAMD server. * * @param requestInfo The state information for this request. */ static void handleUnpauseOptimizingJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handleUnpauseOptimizingJob()"); // If the user doesn't have cancel permission, then they can't see this if (! requestInfo.mayCancelJob) { logMessage(requestInfo, "No mayCancelJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "pause or unpause jobs."); return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // Get the job ID of the optimizing job to un-pause. String optimizingJobID = request.getParameter(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID); if ((optimizingJobID == null) || (optimizingJobID.length() == 0)) { String message = "No optimizing job specified to unpause."; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); handleOptimizeJob(requestInfo); return; } // Get the optimizing job and make sure it exists. OptimizingJob optimizingJob; try { optimizingJob = getOptimizingJob(optimizingJobID); } catch (Exception e) { String message = "Could not retrieve optimizing job " + optimizingJobID + "from the configuration directory -- " + e; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); handleViewOptimizing(requestInfo, true); return; } if (optimizingJob == null) { String message = "Could not retrieve optimizing job " + optimizingJobID + "from the configuration directory."; infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); handleViewOptimizing(requestInfo, true); return; } // See if the user has provided confirmation for the un-pause. If not, then // request it. If so, then take the appropriate action. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && confirmStr.equalsIgnoreCase("Yes")) { optimizingJob.cancelPause(); infoMessage.append("A request has been submitted to unpause the " + "optimizing job. The next iteration of this job " + "will not be disabled when it is scheduled.<BR>" + EOL); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } else if ((confirmStr != null) && confirmStr.equalsIgnoreCase("No")) { infoMessage.append("Optimizing job " + optimizingJobID + " was not unpaused.<BR>" + EOL); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Unpause Optimizing Job " + optimizingJobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to unpause this optimizing " + "job?" + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_UNPAUSE_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\" CELLPADDING=\"20\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Yes\"></TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"No\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles the work of removing information about an optimizing job from the * SLAMD server. * * @param requestInfo The state information for this request. */ static void handleDeleteOptimizingJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handleDeleteOptimizingJob()"); // If the user doesn't have delete permission, then they can't see this if (! requestInfo.mayDeleteJob) { logMessage(requestInfo, "No mayDeleteJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "delete job information."); return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // Get the job ID of the optimizing job to delete. String optimizingJobID = request.getParameter(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID); if ((optimizingJobID == null) || (optimizingJobID.length() == 0)) { infoMessage.append("ERROR: No optimizing job specified to delete.<BR>" + EOL); handleOptimizeJob(requestInfo); return; } // See if the user has provided confirmation for the delete. If not, then // request it. If so, then take the appropriate action. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && confirmStr.equalsIgnoreCase("Yes")) { try { boolean includeIterations = false; String includeStr = request.getParameter( Constants.SERVLET_PARAM_OPTIMIZING_JOB_INCLUDE_ITERATIONS); includeIterations = ((includeStr != null) && (includeStr.equalsIgnoreCase("true") || includeStr.equalsIgnoreCase("yes") || includeStr.equalsIgnoreCase("on") || includeStr.equalsIgnoreCase("1"))); if (includeIterations) { OptimizingJob optimizingJob = getOptimizingJob(optimizingJobID); if (optimizingJob == null) { infoMessage.append("ERROR: Unable to retrieve optimizing job " + optimizingJobID + "<BR>" + EOL); handleViewOptimizing(requestInfo, true); return; } Job[] iterations = optimizingJob.getAssociatedJobs(); if ((iterations != null) && (iterations.length > 0)) { for (int i=0; i < iterations.length; i++) { try { configDB.removeJob(iterations[i].getJobID()); } catch (Exception e) { infoMessage.append("Unable to remove optimizing job " + "iteration " + iterations[i].getJobID() + " -- " + e); } } } Job reRunIteration = optimizingJob.getReRunIteration(); if (reRunIteration != null) { try { configDB.removeJob(reRunIteration.getJobID()); } catch (Exception e) { infoMessage.append("Unable to remove optimizing job re-run " + "iteration " + reRunIteration.getJobID() + " -- " + e); } } } configDB.removeOptimizingJob(optimizingJobID); infoMessage.append("Successfully removed optimizing job " + optimizingJobID + " from the configuration directory.<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Optimizing Job " + optimizingJobID + " Removed</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Information about optimizing job " + optimizingJobID + " has been removed from the configuration directory." + EOL); htmlBody.append("<BR><BR>" + EOL); String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING, "here"); htmlBody.append("Click " + link + " to return to the list of " + "optimizing jobs." + EOL); return; } catch (Exception e) { infoMessage.append("ERROR: Unable to remove optimizing job " + optimizingJobID + " from the configuration " + "directory -- " + e + "<BR>" + EOL); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } } else if ((confirmStr != null) && confirmStr.equalsIgnoreCase("No")) { infoMessage.append("Optimizing job " + optimizingJobID + " was not removed from the configuration " + "directory.<BR>" + EOL); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Delete Optimizing Job " + optimizingJobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to delete this job?" + EOL); htmlBody.append("<BR>"); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_DELETE_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_OPTIMIZING_JOB_INCLUDE_ITERATIONS + "\" CHECKED>Delete all iterations of this optimizing job" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append(" <TABLE BORDER=\"0\" CELLPADDING=\"20\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Yes\"></TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"No\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles the work of editing the comments for an optimizing job. * * @param requestInfo The state information for this request. */ static void handleEditOptimizingComments(RequestInfo requestInfo) { logMessage(requestInfo, "In handleMoveOptimizingJob()"); // If the user doesn't have the schedule job permission, then they can't see // this if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "edit optimizing job information."); return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // Get the job ID of the optimizing job to edit. String optimizingJobID = request.getParameter(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID); if ((optimizingJobID == null) || (optimizingJobID.length() == 0)) { infoMessage.append("ERROR: No optimizing job specified to edit.<BR>" + EOL); handleOptimizeJob(requestInfo); return; } // Get the optimizing job from the configuration database. OptimizingJob optimizingJob = null; try { optimizingJob = configDB.getOptimizingJob(optimizingJobID); if (optimizingJob == null) { infoMessage.append("ERROR: Optimizing job " + optimizingJobID + " was not found in the configuration database.<BR>" + EOL); handleOptimizeJob(requestInfo); return; } } catch (Exception e) { infoMessage.append("ERROR: Could not get optimizing job " + optimizingJobID + " from the configuration " + "database: " + e + ".<BR>" + EOL); handleOptimizeJob(requestInfo); return; } // Determine whether the user submitted the form to update the comments. If // so, then update the job. Otherwise, display the form. String submitStr = request.getParameter(Constants.SERVLET_PARAM_SUBMIT); if ((submitStr != null) && (submitStr.length() > 0)) { String comments = request.getParameter(Constants.SERVLET_PARAM_JOB_COMMENTS); try { optimizingJob.setComments(comments); configDB.writeOptimizingJob(optimizingJob); // If the optimizing job is held in memory by the scheduler, then update // that copy as well. if ((optimizingJob = scheduler.getOptimizingJob(optimizingJobID)) != null) { optimizingJob.setComments(comments); } infoMessage.append("Successfully updated the optimizing job " + "comments.<BR>"); } catch (Exception e) { infoMessage.append("ERROR: Unable to update optimizing job " + "comments: " + e + ".<BR>" + EOL); } generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } else { String comments = optimizingJob.getComments(); if (comments == null) { comments = ""; } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Edit Comments for Optimizing Job " + optimizingJobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Edit the set of comments for the optimizing job and " + "click the update button when finished." + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_EDIT_OPTIMIZING_COMMENTS) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TD>Job Comments</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_COMMENTS + "\" ROWS=\"10\" " + "COLS=\"80\">" + comments + "</TEXTAREA></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" " + "VALUE=\"Update\">" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles the work of moving an optimizing job from one folder to another. * * @param requestInfo The state information for this request. */ static void handleMoveOptimizingJob(RequestInfo requestInfo) { logMessage(requestInfo, "In handleMoveOptimizingJob()"); // If the user doesn't have manage folders permission, then they can't see // this if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "move job information."); return; } // Get the important state information for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // Get the job ID of the optimizing job to delete. String optimizingJobID = request.getParameter(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID); if ((optimizingJobID == null) || (optimizingJobID.length() == 0)) { infoMessage.append("ERROR: No optimizing job specified to move.<BR>" + EOL); handleOptimizeJob(requestInfo); return; } // Make sure that one or more folders exists in the configuration directory. JobFolder[] folders = null; try { folders = configDB.getFolders(); } catch (DatabaseException de) {} if ((folders == null) || (folders.length == 0)) { infoMessage.append("ERROR: No job folders have been defined in the " + "configuration directory.<BR>" + EOL); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } // See if the user has provided confirmation for the move. If not, then // request it. If so, then take the appropriate action. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && confirmStr.equalsIgnoreCase("Move")) { try { String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); boolean includeIterations = false; String includeStr = request.getParameter( Constants.SERVLET_PARAM_OPTIMIZING_JOB_INCLUDE_ITERATIONS); includeIterations = ((includeStr != null) && (includeStr.equalsIgnoreCase("true") || includeStr.equalsIgnoreCase("yes") || includeStr.equalsIgnoreCase("on") || includeStr.equalsIgnoreCase("1"))); if (includeIterations) { OptimizingJob optimizingJob = getOptimizingJob(optimizingJobID); if (optimizingJob == null) { infoMessage.append("ERROR: Unable to retrieve optimizing job " + optimizingJobID + "<BR>" + EOL); handleViewOptimizing(requestInfo, true); return; } Job[] iterations = optimizingJob.getAssociatedJobs(); if ((iterations != null) && (iterations.length > 0)) { for (int i=0; i < iterations.length; i++) { try { configDB.moveJob(iterations[i].getJobID(), folderName); } catch (Exception e) { infoMessage.append("Unable to move optimizing job iteration " + iterations[i].getJobID() + " -- " + e); } } } Job reRunIteration = optimizingJob.getReRunIteration(); if (reRunIteration != null) { try { configDB.moveJob(reRunIteration.getJobID(), folderName); } catch (Exception e) { infoMessage.append("Unable to move optimizing job re-run " + "iteration " + reRunIteration.getJobID() + " -- " + e); } } } configDB.moveOptimizingJob(optimizingJobID, folderName); infoMessage.append("Successfully moved optimizing job " + optimizingJobID + ".<BR>" + EOL); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } catch (Exception e) { infoMessage.append("ERROR: Unable to move optimizing job " + optimizingJobID + " -- " + e + "<BR>" + EOL); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } } else if ((confirmStr != null) && confirmStr.equalsIgnoreCase("Cancel")) { infoMessage.append("Optimizing job " + optimizingJobID + " was not moved.<BR>" + EOL); generateViewOptimizingJobBody(requestInfo, optimizingJobID); return; } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Move Optimizing Job " + optimizingJobID + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">" + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SECTION, Constants.SERVLET_SECTION_JOB) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_JOB_MOVE_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobID) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" Move to folder:" + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_FOLDER + "\">" + EOL); for (int i=0; i < folders.length; i++) { htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + "\">" + folders[i].getFolderName() + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append("<BR>"); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_OPTIMIZING_JOB_INCLUDE_ITERATIONS + "\" CHECKED>Move all iterations of this optimizing job" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append(" <TABLE BORDER=\"0\" CELLPADDING=\"20\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Move\"></TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Cancel\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Retrieves the requested optimizing job from the scheduler if possible, or * from the config DB if necessary. * * @param optimizingJobID The ID of the optimizing job to retrieve. * * @return The requested optimizing job, or <CODE>null</CODE> if the * requested optimizing job does not exist. * * @throws DatabaseException If a problem occurs while interacting with the * SLAMD database. * * @throws DecodeException If a problem occurs while attempting to decode * the optimizing job information from the DB. * * @throws SLAMDServerException If some other problem occurs while * attempting to retrieve the optimizing job. */ static OptimizingJob getOptimizingJob(String optimizingJobID) throws DatabaseException, DecodeException, SLAMDServerException { if (scheduler == null) { return configDB.getOptimizingJob(optimizingJobID); } else { return scheduler.getOptimizingJob(optimizingJobID); } } }