/* * 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.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URLEncoder; import java.security.AlgorithmParameters; import java.security.MessageDigest; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.Properties; import java.util.StringTokenizer; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import netscape.ldap.LDAPException; import org.apache.commons.fileupload.DefaultFileItemFactory; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUpload; import com.sleepycat.je.DatabaseException; import com.slamd.common.Constants; import com.slamd.common.DynamicConstants; import com.slamd.common.SLAMDException; import com.slamd.db.DSMigrator; import com.slamd.db.JobFolder; import com.slamd.db.SLAMDDB; import com.slamd.job.Job; import com.slamd.job.JobClass; import com.slamd.job.OptimizingJob; import com.slamd.job.UnknownJobClass; import com.slamd.jobgroup.JobGroup; import com.slamd.parameter.BooleanParameter; import com.slamd.parameter.IntegerParameter; import com.slamd.parameter.InvalidValueException; import com.slamd.parameter.Parameter; import com.slamd.parameter.ParameterList; import com.slamd.parameter.PasswordParameter; import com.slamd.parameter.PlaceholderParameter; import com.slamd.parameter.StringParameter; import com.slamd.report.ReportGenerator; import com.slamd.server.SLAMDServer; import com.slamd.server.SLAMDServerException; import com.slamd.server.Scheduler; import com.slamd.server.UploadedFile; import com.slamd.stat.StatTracker; import com.unboundid.util.Base64; import static com.slamd.admin.AdminAccess.*; import static com.slamd.admin.AdminConfig.*; import static com.slamd.admin.AdminDebug.*; import static com.slamd.admin.AdminJob.*; import static com.slamd.admin.AdminJobGroup.*; import static com.slamd.admin.AdminUI.*; /** * This class serves as the single point of entry for the Web-based SLAMD * administration interface. It provides a user-friendly mechanism for the end * user to access the SLAMD server. * * * @author Neil A. Wilson */ public class AdminServlet extends HttpServlet { /** * The serial version UID for this serializable class. */ private static final long serialVersionUID = 5218965023006249116L; /** * The name that will be used to identify the admin interface as a * configuration subscriber. */ public static final String CONFIG_SUBSCRIBER_NAME = "User Interface"; /** * The end of line character that will be used for the generated HTML content. */ public static final String EOL = "\n"; /** * The reference to this admin servlet. */ public static AdminServlet adminServlet = null; /** * The reference to the SLAMD server with which this admin servlet is * associated, if there is one. */ public static SLAMDServer slamdServer = null; /** * The access control manager for the administrative interface. */ static AccessManager accessManager; /** * Indicates whether to always show advanced scheduling options when * scheduling a job. */ static boolean alwaysShowAdvancedOptions; /** * Indicates whether the configuration database has been created and exists on * the disk. */ static boolean configDBExists; /** * Indicates whether the graphing capability of SLAMD should be disabled. */ static boolean disableGraphs; /** * Indicates whether the file upload capability of SLAMD should be disabled. */ static boolean disableUploads; /** * Indicates whether to enable management of options that are only applicable * if the server will be run in restricted read-only mode. */ static boolean enableReadOnlyManagement; /** * Indicates whether graphs should be generated in a new window. */ static boolean graphInNewWindow; /** * Indicates whether the individual iterations of an optimizing job should be * hidden when viewing a list of completed jobs. */ static boolean hideOptimizingIterations; /** * Indicates whether the SLAMD server should attempt to hide sensitive * information when displaying a job in read-only mode. This sensitive * information can include the addresses of client systems, e-mail addresses * for job notification, and the values of any parameters that are marked * sensitive in the associated job. */ static boolean hideSensitiveInformation; /** * Indicates whether to include the address of the SLAMD server in the title * of the generated HTML pages. */ static boolean includeAddressInPageTitle; /** * Indicates whether the admin interface should automatically place the * current time in the start time text field when scheduling a new job. */ static boolean populateStartTime; /** * Indicates whether the admin interface should operate in read-only mode. In * read-only mode, users will only be able to view job information -- they * will not be allowed to schedule jobs or alter the configuration. */ static boolean readOnlyMode; /** * Indicates whether the admin interface should restrict the set of jobs and * folders that are displayed when the server is operating in read-only mode. */ static boolean restrictedReadOnlyMode; /** * Indicates whether the admin interface should allow users to search for * jobs when operating in read-only mode. */ static boolean searchReadOnly; /** * Indicates whether the login ID of the currently-authenticated user will be * displayed in the navigation bar. */ static boolean showLoginID; /** * Indicates whether the SLAMD Server Status link should be shown first or * last in the navigation sidebar. By default it will be shown last. */ static boolean showStatusFirstInSidebar; /** * Indicates whether the current time should be displayed in the sidebar. */ static boolean showTimeInSidebar; /** * Indicates whether the SLAMD server is currently running. */ static boolean slamdRunning; /** * Indicates whether access control should be used when determining whether to * allow a given operation. */ static boolean useAccessControl; /** * Indicates whether the SLAMD server should blindly trust any SSL certificate * presented by the user directory. */ static boolean userDirBlindTrust; /** * Indicates whether the connection to the user directory should be encrypted * using SSL. */ static boolean userDirUseSSL; /** * The byte array containing the encoded SLAMD logo. */ static byte[] slamdLogoBytes; /** * The configuration database for the SLAMD server. */ static SLAMDDB configDB; /** * The decimal formatter used by the admin servlet. */ static DecimalFormat decimalFormat; /** * The default width to use for generated graphs. */ static int defaultGraphWidth; /** * The default height to use for generated graphs. */ static int defaultGraphHeight; /** * The default height to use for resource monitor graphs. */ static int defaultMonitorGraphHeight; /** * The port number to use to connect to the user directory. */ static int userDirPort; /** * The maximum file size that will be allowed via upload. A value of -1 * indicates no limit. */ static int maxUploadSize; /** * The request ID that will be used for the next request. */ static int nextID; /** * The set of properties associated with the servlet configuration file. */ static Properties configProperties; /** * The set of report generators that have been configured in the SLAMD server. */ static ReportGenerator[] reportGenerators; /** * The SLAMD server scheduler. */ static Scheduler scheduler; /** * The date formatter that will be used to format dates in a form that will be * stored in the directory server and also when users enter date information * via a form. */ static SimpleDateFormat dateFormat; /** * The date formatter that will be used to format dates that will be displayed * to the end user. */ static SimpleDateFormat displayDateFormat; /** * The lines that should be added to the HTML header for generated pages. */ static String addedHeaderLines = null; /** * The HTML target that will be used to determine whether to create a new * window for the specified content. */ static String blankTarget; /** * The location on the filesystem under which the job classes may be found. */ static String classPath; /** * The location of the configuration database files. */ static String configDBDirectory; /** * The servlet configuration file that may be an alternate source for init * parameters. */ static String configFile; /** * The HTML that should be displayed on the main page displayed when a user * initially accesses the SLAMD administrative interface. */ static String defaultHTML = null; /** * The HTML that should be displayed at the bottom of every page generated. */ static String pageFooter = null; /** * The HTML that should be displayed at the top of every page generated. */ static String pageHeader = null; /** * The DN of the group/role that specifies who can add job classes. */ static String resourceDNAddJobClass; /** * The DN of the group/role that specifies which users can be used by clients * to authenticate. */ static String resourceDNAuthenticateClient; /** * The DN of the group/role that specifies who can cancel jobs. */ static String resourceDNCancelJob; /** * The DN of the group/role that specifies who can delete jobs. */ static String resourceDNDeleteJob; /** * The DN of the group/role that specifies who can delete job classes. */ static String resourceDNDeleteJobClass; /** * The DN of the group/role that specifies who can disconnect clients. */ static String resourceDNDisconnectClient; /** * The DN of the group/role that specifies who can edit the servlet config. */ static String resourceDNEditServletConfig; /** * The DN of the group/role that specifies who can edit the SLAMD config. */ static String resourceDNEditSLAMDConfig; /** * The DN of the group/role that specifies who can export job information. */ static String resourceDNExportJob; /** * The DN of the group/role that specifies who has full access to anything. */ static String resourceDNFullAccess; /** * The DN of the group/role that specifies who can manage real and virtual * job folders. */ static String resourceDNManageJobFolders; /** * The DN of the group/role that specifies who can start and stop the SLAMD * server. */ static String resourceDNRestartSLAMD; /** * The DN of the group/role that specifies who can start and stop the access * control manager. */ static String resourceDNRestartACL; /** * The DN of the group/role that specifies who can view job information. */ static String resourceDNViewJob; /** * The DN of the group/role that specifies who can view job class definitions. */ static String resourceDNViewJobClass; /** * The DN of the group/role that specifies who can schedule jobs. */ static String resourceDNScheduleJob; /** * The DN of the group/role that specifies who can view the servlet config. */ static String resourceDNViewServletConfig; /** * The DN of the group/role that specifies who can view the SLAMD config. */ static String resourceDNViewSLAMDConfig; /** * The DN of the group/role that specifies who can view SLAMD status info. */ static String resourceDNViewStatus; /** * The style sheet that should be used for generated HTML pages. */ static String styleSheet = null; /** * The location of the JSSE key store to use for establishing SSL-based * connections. */ static String sslKeyStore; /** * The password for the JSSE key store. */ static String sslKeyStorePassword; /** * The location of the JSSE trust store to use for establishing SSL-based * connections. */ static String sslTrustStore; /** * The password for the JSSE trust store. */ static String sslTrustStorePassword; /** * The reason that the administrative interface is unavailable. */ static String unavailableReason; /** * The base DN under which the user accounts are located in the user * directory. */ static String userDirBase; /** * The DN to use to bind to the user directory server. */ static String userDirBindDN; /** * The password for the user directory bind DN. */ static String userDirBindPW; /** * The host name or IP address for the user directory server. */ static String userDirHost; /** * The name of the LDAP attribute that will be used to find user entries in * the user directory from the login ID that has been provided. */ static String userIDAttribute; /** * The absolute path to the WEB-INF directory for the admin interface. */ static String webInfBasePath; /** * Perform the one-time initialization for the servlet that is done when the * servlet is first loaded. */ @Override() public void init() { adminServlet = this; // Initialize the static variables that won't get caught elsewhere slamdRunning = false; nextID = 0; dateFormat = new SimpleDateFormat(Constants.ATTRIBUTE_DATE_FORMAT); displayDateFormat = new SimpleDateFormat(Constants.DISPLAY_DATE_FORMAT); unavailableReason = "The servlet initialization did not complete " + "properly."; defaultGraphWidth = Constants.DEFAULT_GRAPH_WIDTH; defaultGraphHeight = Constants.DEFAULT_GRAPH_HEIGHT; defaultMonitorGraphHeight = Constants.DEFAULT_MONITOR_GRAPH_HEIGHT; decimalFormat = new DecimalFormat("0.000"); webInfBasePath = getServletContext().getRealPath( Constants.DEFAULT_WEB_APP_PATH); showStatusFirstInSidebar = false; // Read the SLAMD logo into the corresponding byte array. slamdLogoBytes = new byte[0]; try { InputStream inputStream = getClass().getClassLoader(). getResourceAsStream("slamd_logo.gif"); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(8192); int bytesRead; byte[] buffer = new byte[8192]; while ((bytesRead = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, bytesRead); } slamdLogoBytes = outputStream.toByteArray(); } catch (Exception e) {} // First, read the servlet configuration try { if (! readServletConfig(getServletConfig())) { // We don't need to set the unavailable reason here because // readServletConfig() will do that for us. return; } } catch (IOException ioe) { if ((configFile != null) && (configFile.length() > 0)) { unavailableReason = "Unable to read the servlet configuration file " + configFile + ": " + ioe; } else { unavailableReason = "Unable to obtain the servlet configuration."; } return; } // Configure the access control manager if access control checking will be // used if ((! readOnlyMode) && useAccessControl) { accessManager = new AccessManager(userDirHost, userDirPort, userDirBindDN, userDirBindPW, userDirBase, userIDAttribute, userDirUseSSL, userDirBlindTrust, sslKeyStore, sslKeyStorePassword, sslTrustStore, sslTrustStorePassword); // Register all of the protected resources RequestInfo requestInfo = new RequestInfo(null, null); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_FULL, resourceDNFullAccess, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_RESTART_SLAMD, resourceDNRestartSLAMD, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_RESTART_ACL, resourceDNRestartACL, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_VIEW_SERVLET_CONFIG, resourceDNViewServletConfig, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_EDIT_SERVLET_CONFIG, resourceDNEditServletConfig, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_VIEW_SLAMD_CONFIG, resourceDNViewSLAMDConfig, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_EDIT_SLAMD_CONFIG, resourceDNEditSLAMDConfig, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_VIEW_STATUS, resourceDNViewStatus, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_DISCONNECT_CLIENT, resourceDNDisconnectClient, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_VIEW_JOB, resourceDNViewJob, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_EXPORT_JOB, resourceDNExportJob, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_SCHEDULE_JOB, resourceDNScheduleJob, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_CANCEL_JOB, resourceDNCancelJob, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_DELETE_JOB, resourceDNDeleteJob, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_MANAGE_JOB_FOLDERS, resourceDNManageJobFolders, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_VIEW_JOB_CLASS, resourceDNViewJobClass, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_ADD_JOB_CLASS, resourceDNAddJobClass, false); registerACL(requestInfo, Constants.SERVLET_INIT_PARAM_ACCESS_DELETE_JOB_CLASS, resourceDNDeleteJobClass, false); // Start the access control manager. try { accessManager.startAccessManager(); } catch (LDAPException le) { unavailableReason = "The access control manager was not able to be " + "started because the connection to the " + "configuration directory could not be " + "established: " + le.getMessage(); return; } } // Determine whether the configuration database has been created yet. If // not, then set a flag so that the admin interface will prompt the user to // create it. configDBExists = false; try { configDBExists = SLAMDDB.dbExists(configDBDirectory); if (! configDBExists) { slamdServer = null; scheduler = null; configDB = null; unavailableReason = "The configuration database has not yet been " + "created."; return; } } catch (Exception e) { e.printStackTrace(); slamdServer = null; scheduler = null; configDB = null; unavailableReason = "Could not determine if the configuration " + "database already exists: " + e; return; } // Create the SLAMD server instance. try { slamdServer = new SLAMDServer(this, readOnlyMode, configDBDirectory, sslKeyStore, sslKeyStorePassword, sslTrustStore, sslTrustStorePassword); scheduler = slamdServer.getScheduler(); configDB = slamdServer.getConfigDB(); } catch (Exception e) { e.printStackTrace(); slamdServer = null; scheduler = null; configDB = null; unavailableReason = "Could not create the SLAMD server instance: " + e.getMessage(); return; } // Register as a configuration subscriber configDB.registerAsSubscriber(ADMIN_CONFIG); ADMIN_CONFIG.refreshSubscriberConfiguration(); // If we have made it to this point, then the server has started up and // should be ready to handle requests and for administrative interaction. slamdRunning = true; } /** * Indicates that the servlet engine is shutting down and that the appropriate * action should be taken to ensure that SLAMD is properly stopped. */ @Override() public void destroy() { if (slamdServer != null) { slamdServer.logMessage(Constants.LOG_LEVEL_ANY, "SLAMD servlet engine is shutting down."); if (slamdRunning) { slamdServer.stopSLAMD(); slamdRunning = false; } } } /** * Receives an HTTP GET request from a client, interprets the request, and * generates the appropriate response. * * @param request Information about the HTTP GET request issued by the * client. * @param response Information about the HTTP response that will be * returned to the client. * * @throws IOException If a problem is encountered while reading from or * writing to the client. */ @Override() public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { // We don't need to distinguish between requests made via GET and those // made via POST, so just treat a GET the same as a POST. doPost(request, response); } /** * Receives an HTTP POST request from a client, interprets the request, and * generates the appropriate response. * * @param request Information about the HTTP POST request issued by the * client. * @param response Information about the HTTP response that will be * returned to the client. * * @throws IOException If a problem is encountered while reading from or * writing to the client. */ @Override() public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { // First, create the request info variable. RequestInfo requestInfo = new RequestInfo(request, response); requestInfo.requestID = getNextID(); String section = requestInfo.section; String subsection = requestInfo.subsection; String dbgStr = request.getParameter(Constants.SERVLET_PARAM_HTML_DEBUG); requestInfo.debugHTML = ((dbgStr != null) && (dbgStr.length() > 0)); requestInfo.generateSidebar = true; String param = request.getParameter(Constants.SERVLET_PARAM_HIDE_SIDEBAR); if ((param != null) && (param.equalsIgnoreCase(Constants.CONFIG_VALUE_TRUE))) { requestInfo.generateSidebar = false; } if (useAccessControl && ((requestInfo.userIdentifier == null) || (requestInfo.userIdentifier.length() == 0))) { handleUnauthenticatedUser(requestInfo); } else { // Initialize the variables used for access control. setAccessControlVariables(requestInfo); // Check to see if the SLAMD server is running. If not, then display the // appropriate page to the user. if ((! configDBExists) && (! section.equals(Constants.SERVLET_SECTION_DOCUMENTATION)) && (! section.equals(Constants.SERVLET_SECTION_LICENSE_HTML)) && (! section.equals(Constants.SERVLET_SECTION_LICENSE_TEXT)) && (! section.equals(Constants.SERVLET_SECTION_SLAMD_LOGO))) { handleNoDB(requestInfo); } else if ((! slamdRunning) && (! section.equals(Constants.SERVLET_SECTION_CONFIG)) && (! section.equals(Constants.SERVLET_SECTION_STATUS)) && (! section.equals(Constants.SERVLET_SECTION_DOCUMENTATION)) && (! section.equals(Constants.SERVLET_SECTION_LICENSE_HTML)) && (! section.equals(Constants.SERVLET_SECTION_LICENSE_TEXT)) && (! section.equals(Constants.SERVLET_SECTION_SLAMD_LOGO))) { handleSLAMDUnavailable(requestInfo); } else { // See if the user just wants to view a job. If so, then take them to // it. This can make for shorter URLs if you are only interested in // viewing job information. String getJobID = request.getParameter(Constants.SERVLET_PARAM_GET_JOB); if ((getJobID != null) && (getJobID.length() > 0)) { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, null, getJobID); } // Determine what to do from the parameters that have been provided else if (section.equals(Constants.SERVLET_SECTION_SLAMD_LOGO)) { handleSLAMDLogo(requestInfo); } else if (section.equals(Constants.SERVLET_SECTION_CONFIG)) { if (subsection.equals(Constants.SERVLET_SECTION_CONFIG_SERVLET)) { handleServletConfig(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_CONFIG_ACCESS)) { handleAccessControlConfig(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_CONFIG_SLAMD)) { handleSLAMDConfig(requestInfo); } else { handleConfig(requestInfo); } } else if (section.equals(Constants.SERVLET_SECTION_DOCUMENTATION)) { handleDocumentation(requestInfo); } else if (section.equals(Constants.SERVLET_SECTION_LICENSE_HTML)) { handleHTMLLicense(requestInfo); } else if (section.equals(Constants.SERVLET_SECTION_LICENSE_TEXT)) { handleTextLicense(requestInfo); } else if (section.equals(Constants.SERVLET_SECTION_STATUS)) { if (subsection.equals(Constants.SERVLET_SECTION_STATUS_VIEW_LOG)) { handleViewLog(requestInfo); } else { handleStatus(requestInfo); } } else if (section.equals(Constants.SERVLET_SECTION_JOB)) { if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_PENDING) || subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_RUNNING) || subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED) || subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_GENERIC)) { handleViewJob(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_VIEW_AS_TEXT)) { handleViewJobAsText(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING_AS_TEXT)) { handleViewOptimizingJobAsText(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_VIEW_LOG_MESSAGES)) { handleViewJobLogMessages(requestInfo); requestInfo.generateSidebar = false; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_GROUPS)) { handleViewJobGroups(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_GROUP)) { handleViewJobGroup(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_EDIT_GROUP_DESCRIPTION)) { handleEditJobGroupDescription(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_EDIT_GROUP_PARAMS)) { handleEditJobGroupParams(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_EDIT_GROUP_JOB)) { handleEditJobGroupJob(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_EDIT_GROUP_OPTIMIZING_JOB)) { handleEditJobGroupOptimizingJob(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_ADD_GROUP)) { handleAddJobGroup(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_ADD_JOB_TO_GROUP)) { handleAddJobToGroup(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_ADD_OPTIMIZING_JOB_TO_GROUP)) { handleAddOptimizingJobToGroup(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_REMOVE_JOB_FROM_GROUP)) { handleRemoveJobFromGroup(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_REMOVE_GROUP)) { handleRemoveJobGroup(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_SCHEDULE_GROUP)) { handleScheduleJobGroup(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_CLONE_GROUP)) { handleCloneJobGroup(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_REAL)) { handleViewRealFolderList(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_LIST_REAL_FOLDERS)) { handleListRealFolders(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_LIST_VIRTUAL_FOLDERS)) { handleListVirtualFolders(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_FOLDER_DESCRIPTION)) { handleEditFolderDescription(requestInfo, false); } else if (subsection.equals( Constants.SERVLET_SECTION_OPTIMIZING_FOLDER_DESCRIPTION)) { handleEditFolderDescription(requestInfo, true); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_FOLDER_PUBLISH)) { handlePublishFolder(requestInfo, false); } else if (subsection.equals( Constants.SERVLET_SECTION_OPTIMIZING_FOLDER_PUBLISH)) { handlePublishFolder(requestInfo, true); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_VIEW_VIRTUAL)) { handleVirtualJobFolders(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_STATS)) { handleViewJobStatistics(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_SAVE_STATS)) { handleSaveJobStatistics(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_GRAPH)) { if (! disableGraphs) { handleViewGraph(requestInfo); if (graphInNewWindow) { requestInfo.generateSidebar = false; } } } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_VIEW_MONITOR_GRAPH)) { if (! disableGraphs) { handleViewMonitorGraph(requestInfo); if (graphInNewWindow) { requestInfo.generateSidebar = false; } } } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_GRAPH)) { if (! disableGraphs) { handleGraph(requestInfo); requestInfo.generateHTML = false; } } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_VIEW_GRAPH_REAL_TIME)) { if (! disableGraphs) { handleViewRealTimeGraph(requestInfo); if (graphInNewWindow) { requestInfo.generateSidebar = false; } } } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_GRAPH_REAL_TIME)) { if (! disableGraphs) { handleRealTimeGraph(requestInfo); requestInfo.generateHTML = false; } } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_GRAPH_MONITOR)) { if (! disableGraphs) { handleMonitorGraph(requestInfo); requestInfo.generateHTML = false; } } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_VIEW_OVERLAY)) { if (! disableGraphs) { handleViewOverlay(requestInfo); if (graphInNewWindow) { requestInfo.generateSidebar = false; } } } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_OVERLAY)) { if (! disableGraphs) { handleOverlay(requestInfo); requestInfo.generateHTML = false; } } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_UPLOAD)) { handleUploadedFile(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_SCHEDULE)) { handleScheduleJob(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_CLONE)) { handleCloneJob(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_EDIT)) { handleEditJob(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_EDIT_COMMENTS)) { handleEditJobComments(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_IMPORT_PERSISTENT)) { handleImportPersistentStats(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_CANCEL)) { handleCancelJob(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_CANCEL_AND_DELETE)) { handleCancelAndDelete(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_DELETE)) { handleDeleteJob(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_DISABLE)) { handleDisableJob(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_ENABLE)) { handleEnableJob(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_GENERATE_REPORT)) { handleGenerateReport(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_MASS_OP)) { handleMassOperation(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_MASS_OPTIMIZING)) { handleMassOptimizing(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_IMPORT_JOB_DATA)) { handleDataImport(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_EXPORT_JOB_DATA)) { handleDataExport(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_MIGRATE)) { handleMigrateData(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_VIEW_CLASSES)) { handleViewJobClass(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_ADD_CLASS)) { handleAddJobClass(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_INSTALL_JOB_PACK)) { handleInstallJobPack(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_DELETE_CLASS)) { handleDeleteJobClass(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_SCHEDULE_HELP)) { generateScheduleHelpPage(requestInfo); requestInfo.generateSidebar = false; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_OPTIMIZE)) { handleOptimizeJob(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_CANCEL_OPTIMIZING)) { handleCancelOptimizingJob(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_PAUSE_OPTIMIZING)) { handlePauseOptimizingJob(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_UNPAUSE_OPTIMIZING)) { handleUnpauseOptimizingJob(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_DELETE_OPTIMIZING)) { handleDeleteOptimizingJob(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING)) { handleViewOptimizing(requestInfo, false); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_MOVE_OPTIMIZING)) { handleMoveOptimizingJob(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_CLONE_OPTIMIZING)) { generateCloneOptimizingJobForm(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_EDIT_OPTIMIZING_COMMENTS)) { handleEditOptimizingComments(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_OPTIMIZE_HELP)) { generateOptimizeHelpPage(requestInfo); requestInfo.generateSidebar = false; } else { if (readOnlyMode) { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } else { requestInfo.htmlBody.append(getDefaultHTML(requestInfo)); } } } else if (section.equals(Constants.SERVLET_SECTION_DEBUG)) { if (subsection.equals(Constants.SERVLET_SECTION_DEBUG_THREADS)) { handleDebugThreads(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_DEBUG_SYSPROPS)) { handleDebugSystemProperties(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_DEBUG_REQUEST)) { handleDebugRequest(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_DEBUG_DB)) { handleDebugDatabase(requestInfo); } else if (subsection.equals(Constants.SERVLET_SECTION_DEBUG_GC)) { handleDebugGC(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_DEBUG_ENABLE_INSTRUCTION_TRACE)) { handleDebugEnableInstructionTrace(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_DEBUG_DISABLE_INSTRUCTION_TRACE)) { handleDebugDisableInstructionTrace(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_DEBUG_ENABLE_METHOD_TRACE)) { handleDebugEnableMethodTrace(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_DEBUG_DISABLE_METHOD_TRACE)) { handleDebugDisableMethodTrace(requestInfo); } else if (subsection.equals( Constants.SERVLET_SECTION_DEBUG_STACK_TRACE)) { handleDebugStackTrace(requestInfo); } } else { boolean pageGenerated = false; String queryString = request.getQueryString(); if ((queryString != null) && (queryString.length() > 0)) { try { MessageDigest md5Digest = MessageDigest.getInstance("MD5"); byte[] queryBytes = queryString.getBytes("UTF-8"); String queryDigest = Base64.encode(md5Digest.digest(queryBytes)); for (int i=0; i < Constants.QUERY_STRING_MD5.length; i++) { if (queryDigest.equals(Constants.QUERY_STRING_MD5[i])) { generatePageFromMD5(requestInfo, queryDigest); pageGenerated = true; break; } } } catch (Exception e) {} } if (! pageGenerated) { if (readOnlyMode) { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } else { requestInfo.htmlBody.append(getDefaultHTML(requestInfo)); } } } } } // If the response hasn't been sent back yet, then do it now. if (requestInfo.generateHTML) { response.setContentType("text/html"); PrintWriter writer = response.getWriter(); if (requestInfo.generateSidebar) { writer.println(generateHTMLHeader(requestInfo)); writer.println("<!-- START INFO MESSAGE -->" + EOL); writer.println(generateWarning(requestInfo.infoMessage.toString())); writer.println("<!-- END INFO MESSAGE -->" + EOL + EOL); } else { writer.println(generateHTMLHeaderWithoutSidebar(requestInfo)); writer.println("<!-- START INFO MESSAGE -->" + EOL); writer.println(generateWarning(requestInfo.infoMessage.toString())); writer.println("<!-- END INFO MESSAGE -->" + EOL + EOL); } writer.println("<!-- START MAIN BODY -->" + EOL); writer.println(requestInfo.htmlBody.toString()); writer.println("<!-- END MAIN BODY -->" + EOL + EOL); writer.println(generateHTMLFooter(requestInfo)); writer.flush(); } } /** * Handles the work of processing requests related to files that have been * uploaded to the SLAMD server. * * @param requestInfo The state information for this request. */ static void handleUploadedFile(RequestInfo requestInfo) { logMessage(requestInfo, "In handleUploadedFile()"); // If file uploads have been disabled, then no one can see this section. if (disableUploads) { logMessage(requestInfo, "File uploads disabled"); generateAccessDeniedBody(requestInfo, "Access to file uploads has been disabled."); return; } // The user must have at least view status 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; } // First, see if the request is multi-part content. If it is, then we can // be pretty confident that the user is uploading a file. if (FileUpload.isMultipartContent(requestInfo.request)) { handleFileUpload(requestInfo); return; } // Get the important state information for the request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // See if the user is doing this in the context of optimizing jobs. boolean inOptimizing = false; String optStr = request.getParameter(Constants.SERVLET_PARAM_IN_OPTIMIZING); if (optStr != null) { inOptimizing = optStr.equalsIgnoreCase("true"); } // Get the file action to determine what we want to do. String fileAction = request.getParameter(Constants.SERVLET_PARAM_FILE_ACTION); if (fileAction == null) { infoMessage.append("ERROR: No action specified.<BR>" + EOL); if (inOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } return; } else if (fileAction.equals(Constants.FILE_ACTION_VIEW)) { handleRetrieveFile(requestInfo, inOptimizing, true); } else if (fileAction.equals(Constants.FILE_ACTION_SAVE)) { handleRetrieveFile(requestInfo, inOptimizing, false); } else if (fileAction.equals(Constants.FILE_ACTION_EDIT_TYPE)) { // No matter what, we need the folder name and file name. String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); String fileName = request.getParameter(Constants.SERVLET_PARAM_FILE_NAME); if ((fileName == null) || (fileName.length() == 0)) { infoMessage.append("The name of the file to delete was not " + "provided.<BR>" + EOL); if (inOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } return; } UploadedFile file = null; try { file = configDB.getUploadedFile(folderName, fileName); } catch (Exception e) { infoMessage.append("Unable to retrieve the requested file -- " + e + ".<BR>" + EOL); if (inOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } return; } // See if the user has submitted the new MIME type to use. String newType = request.getParameter(Constants.SERVLET_PARAM_FILE_TYPE); if ((newType != null) && (newType.length() > 0)) { try { file.setFileType(newType); configDB.writeUploadedFile(file, folderName); infoMessage.append("Successfully updated MIME type for file \"" + fileName + "\"<BR>" + EOL); } catch (DatabaseException de) { infoMessage.append("Unable to update MIME type: " + de.getMessage() + "<BR>" + EOL); } if (inOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } return; } else { // Display a form that allows the user to specify the new MIME type. htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Update MIME Type for File " + fileName + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Please enter the new MIME type for the file" + 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_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, fileName) + EOL); if (inOptimizing) { 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=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_FILE_TYPE + "\" VALUE=\"" + file.getFileType() + "\"><BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Update MIME Type\">" + EOL); htmlBody.append("</FORM>" + EOL); } } else if (fileAction.equals(Constants.FILE_ACTION_DELETE)) { // We need the name of the folder and the name of the file. The folder // can be null, but the file cannot. String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); String fileName = request.getParameter(Constants.SERVLET_PARAM_FILE_NAME); if ((fileName == null) || (fileName.length() == 0)) { infoMessage.append("The name of the file to delete was not " + "provided.<BR>" + EOL); if (inOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } return; } // Deleting a file 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")))) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Delete File " + fileName + "</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to delete this file?" + 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_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, fileName) + EOL); if (inOptimizing) { 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(" <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.removeUploadedFile(folderName, fileName); infoMessage.append("Successfully removed " + fileName + " from the configuration directory.<BR>" + EOL); if (inOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } } catch (DatabaseException de) { infoMessage.append("Unable to remove " + fileName + " from the configuration directory -- " + de.getMessage() + "<BR>" + EOL); if (inOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } } } else { infoMessage.append("File " + fileName + " was not removed from the configuration " + "directory.<BR>" + EOL); if (inOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } } } else if (fileAction.equals(Constants.FILE_ACTION_UPLOAD)) { if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "remove files from job folders."); return; } // See if the user wants to upload file from the server's filesystem. String filePath = request.getParameter(Constants.SERVLET_PARAM_UPLOAD_FILE_PATH); if ((filePath == null) || (filePath.length() == 0)) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Upload a File</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Upload a file through the browser." + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" " + "ENCTYPE=\"multipart/form-data\" 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_UPLOAD) + EOL); String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if (folderName != null) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); } if (inOptimizing) { 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(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>File to Upload</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"FILE\" NAME=\"" + Constants.SERVLET_PARAM_UPLOAD_FILE + "\">" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>File Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_FILE_DESCRIPTION + "\">" + 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=\"Upload File\"</TD>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR><BR><HR><BR>" + EOL); htmlBody.append("Upload a file on the server's filesystem." + 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_UPLOAD) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_FILE_ACTION, Constants.FILE_ACTION_UPLOAD) + EOL); if (folderName != null) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); } if (inOptimizing) { 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(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>File Path</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_UPLOAD_FILE_PATH + "\" SIZE=\"40\">" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>File TYPE</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_FILE_TYPE + "\">" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>File Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_FILE_DESCRIPTION + "\">" + 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=\"Upload File\"</TD>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } else { // The user wants to upload a local file. Read the rest of the request // parameters that may have been specified. String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); String fileType = request.getParameter(Constants.SERVLET_PARAM_FILE_TYPE); if ((fileType == null) || (fileType.length() == 0)) { fileType = "application/octet-stream"; } String fileDescription = request.getParameter(Constants.SERVLET_PARAM_FILE_DESCRIPTION); if ((fileDescription == null) || (fileDescription.length() == 0)) { fileDescription = null; } // Make sure that the file exists on the local filesystem and that it // is not larger than the maximum upload file size. HttpServletResponse response = requestInfo.response; File uploadFile = new File(filePath); if ((! uploadFile.exists()) || (! uploadFile.isFile())) { String message = "File \"" + filePath + "\" does not exist on the SLAMD server system"; infoMessage.append("ERROR: " + message); response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); if (inOptimizing) { handleViewOptimizing(requestInfo, true, folderName); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } return; } // Read in the file data. byte[] fileData; int fileSize; String fileName; try { fileName = uploadFile.getName(); fileSize = (int) uploadFile.length(); fileData = new byte[fileSize]; int bytesRead = 0; FileInputStream inputStream = new FileInputStream(uploadFile); while (bytesRead < fileSize) { bytesRead += inputStream.read(fileData, bytesRead, (fileSize - bytesRead)); } inputStream.close(); } catch (Exception e) { String message = "Unable to read data from \"" + filePath + "\" -- " + e; infoMessage.append("ERROR: " + message); response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); if (inOptimizing) { handleViewOptimizing(requestInfo, true, folderName); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } return; } // Create the upload file and store it in the config directory. UploadedFile uploadedFile = new UploadedFile(fileName, fileType, fileSize, fileDescription, fileData); try { configDB.writeUploadedFile(uploadedFile, folderName); infoMessage.append("The file was uploaded successfully."); if (inOptimizing) { handleViewOptimizing(requestInfo, true, folderName); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } return; } catch (DatabaseException de) { String message = de.getMessage(); infoMessage.append("ERROR: " + message); response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); if (inOptimizing) { handleViewOptimizing(requestInfo, true, folderName); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } return; } } } else { infoMessage.append("ERROR: Invalid file action \"" + fileAction + "\".<BR>" + EOL); if (inOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } return; } } /** * Handles the work of retrieving the file and sending it back to the client. * * @param requestInfo The state information for this request. * @param inOptimizing Indicates whether this should be done in the * context of the optimizing jobs. * @param useRealContentType Indicates whether the real content type for the * file should be provided when returning the * file. */ static void handleRetrieveFile(RequestInfo requestInfo, boolean inOptimizing, boolean useRealContentType) { // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; HttpServletResponse response = requestInfo.response; StringBuilder infoMessage = requestInfo.infoMessage; String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); String fileName = request.getParameter(Constants.SERVLET_PARAM_FILE_NAME); UploadedFile file = null; String message = "Unable to retrieve information about file \"" + fileName + "\" from folder \"" + folderName + "\" -- "; try { file = configDB.getUploadedFile(folderName, fileName); if (file == null) { message += " no uploaded file found matching that criteria."; } } catch (Exception e) { message += e.getMessage(); } if (file == null) { infoMessage.append(message + "<BR>" + EOL); if (inOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } return; } requestInfo.generateHTML = false; if (useRealContentType) { response.setContentType(file.getFileType()); } else { response.setContentType(Constants.DEFAULT_FILE_CONTENT_TYPE); } response.addHeader("Content-Disposition", "filename=\"" + file.getFileName() + '"'); try { OutputStream outputStream = response.getOutputStream(); outputStream.write(file.getFileData()); outputStream.flush(); } catch (IOException ioe) {} } /** * Handles the work of actually accepting an uploaded file and storing it in * the configuration directory. * * @param requestInfo The state information for this request. */ static void handleFileUpload(RequestInfo requestInfo) { logMessage(requestInfo, "In handleFileUpload()"); if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "upload files into job folders."); return; } StringBuilder infoMessage = requestInfo.infoMessage; FileUpload fileUpload = new FileUpload(new DefaultFileItemFactory()); fileUpload.setSizeMax(maxUploadSize); boolean inOptimizing = false; String folderName = null; try { String fileName = null; String fileType = null; String fileDesc = null; int fileSize = -1; byte[] fileData = null; Iterator iterator = requestInfo.multipartFieldList.iterator(); while (iterator.hasNext()) { FileItem fileItem = (FileItem) iterator.next(); String fieldName = fileItem.getFieldName(); if (fieldName.equals(Constants.SERVLET_PARAM_FILE_DESCRIPTION)) { fileDesc = new String(fileItem.get()); } else if (fieldName.equals(Constants.SERVLET_PARAM_JOB_FOLDER)) { folderName = new String(fileItem.get()); } else if (fieldName.equals(Constants.SERVLET_PARAM_UPLOAD_FILE)) { fileData = fileItem.get(); fileSize = fileData.length; fileType = fileItem.getContentType(); fileName = fileItem.getName(); } else if (fieldName.equals(Constants.SERVLET_PARAM_IN_OPTIMIZING)) { String optStr = new String(fileItem.get()); inOptimizing = optStr.equalsIgnoreCase("true"); } } if (fileName == null) { infoMessage.append("Unable to process file upload: did not receive " + "any actual file data.<BR>" + EOL); if (inOptimizing) { handleViewOptimizing(requestInfo, true, folderName); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } return; } UploadedFile file = new UploadedFile(fileName, fileType, fileSize, fileDesc, fileData); configDB.writeUploadedFile(file, folderName); infoMessage.append("Successfully uploaded file \"" + fileName + "\"<BR>" + EOL); } catch (Exception e) { infoMessage.append("Unable to process file upload: " + e + "<BR>" + EOL); } if (inOptimizing) { handleViewOptimizing(requestInfo, true, folderName); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } } /** * Handles the work of publishing or de-publishing a job folder (and * optionally the jobs contained in it) for display in restricted read-only * mode. * * @param requestInfo The state information for this request. * @param forOptimizing Indicates whether the request was issued in the * context of viewing optimizing jobs or regular * jobs. */ static void handlePublishFolder(RequestInfo requestInfo, boolean forOptimizing) { logMessage(requestInfo, "In handlePublishFolder()"); // The user must have at least manage folder permission to do anything in // this section. if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "manage job folders"); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; StringBuilder infoMessage = requestInfo.infoMessage; // Get the name of the folder to update. String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if ((folderName == null) || (folderName.length() == 0)) { infoMessage.append("ERROR: No folder name provided to publish or " + "de-publish<BR>" + EOL); if (forOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } return; } // Get the submit string to use when determining which action to perform. String submitStr = request.getParameter(Constants.SERVLET_PARAM_SUBMIT); if ((submitStr == null) || (submitStr.length() == 0)) { infoMessage.append("ERROR: Unable to determine the action to take on " + "the job folder<BR>" + EOL); if (forOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } return; } // Determine what action to perform. boolean displayInReadOnlyMode; boolean updateJobs; if (submitStr.equals(Constants.SUBMIT_STRING_PUBLISH_FOLDER)) { displayInReadOnlyMode = true; updateJobs = false; } else if (submitStr.equals(Constants.SUBMIT_STRING_PUBLISH_FOLDER_JOBS)) { displayInReadOnlyMode = true; updateJobs = true; } else if (submitStr.equals(Constants.SUBMIT_STRING_DEPUBLISH_FOLDER)) { displayInReadOnlyMode = false; updateJobs = false; } else if (submitStr.equals(Constants.SUBMIT_STRING_DEPUBLISH_FOLDER_JOBS)) { displayInReadOnlyMode = false; updateJobs = true; } else { infoMessage.append("ERROR: Unable to determine the action to take on " + "the job folder<BR>" + EOL); if (forOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } return; } // Perform the update. try { JobFolder folder = configDB.getFolder(folderName); folder.setDisplayInReadOnlyMode(displayInReadOnlyMode); if (updateJobs) { Job[] jobs = configDB.getJobs(folderName); OptimizingJob[] optimizingJobs = configDB.getOptimizingJobs(folderName); for (int i=0; i < jobs.length; i++) { jobs[i].setDisplayInReadOnlyMode(displayInReadOnlyMode); configDB.writeJob(jobs[i]); } for (int i=0; i < optimizingJobs.length; i++) { optimizingJobs[i].setDisplayInReadOnlyMode(displayInReadOnlyMode); configDB.writeOptimizingJob(optimizingJobs[i]); } } configDB.writeFolder(folder); infoMessage.append("Successfully updated publishing information.<BR>" + EOL); } catch (Exception e) { infoMessage.append("Unable to perform the update: " + e.getMessage() + "<BR>" + EOL); } if (forOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } } /** * Handles all processing related to editing the description of a real job * folder. * * @param requestInfo The state information for this request. * @param forOptimizing Indicates whether the request was made when the * user was viewing optimizing jobs rather than regular * jobs. */ static void handleEditFolderDescription(RequestInfo requestInfo, boolean forOptimizing) { logMessage(requestInfo, "In handleEditFolderDescription()"); // 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.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "manage job folders."); return; } // Get the folder for which to edit the description. String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if ((folderName == null) || (folderName.length() == 0)) { infoMessage.append("ERROR: No job folder name provided for which to " + "edit the description.<BR>" + EOL); handleViewRealFolderList(requestInfo); return; } JobFolder folder = null; try { folder = configDB.getFolder(folderName); } catch (Exception e) { infoMessage.append("ERROR: Could not retrieve job folder \"" + folderName + " from the configuration directory -- " + e + "<BR>" + EOL); handleViewRealFolderList(requestInfo); return; } // See if the form has been submitted. If so, then make the change and // display the folder. If not, then display the form to allow them to // specify a new filter. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && (confirmStr.length() > 0)) { String description = request.getParameter(Constants.SERVLET_PARAM_JOB_DESCRIPTION); 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")); } try { folder.setDescription(description); folder.setDisplayInReadOnlyMode(displayInReadOnlyMode); configDB.writeFolder(folder); infoMessage.append("Successfully updated the job folder " + "description.<BR>" + EOL); } catch (DatabaseException de) { infoMessage.append("ERROR: Unable to update folder description -- " + de + "<BR>" + EOL); } if (forOptimizing) { handleViewOptimizing(requestInfo, true); } else { handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, folderName, null); } } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Update Description for Job Folder \"" + folderName + "\"</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Please provide the new description for the " + "job folder." + 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); if (forOptimizing) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBSECTION, Constants.SERVLET_SECTION_OPTIMIZING_FOLDER_DESCRIPTION) + EOL); } else { 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); } String description = folder.getDescription(); if (description == null) { description = ""; } htmlBody.append(" <TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_DESCRIPTION + "\" ROWS=\"5\" COLS=\"80\">" + description + "</TEXTAREA>" + EOL); htmlBody.append(" <BR><BR>"); boolean displayInReadOnlyMode = folder.displayInReadOnlyMode(); 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")); } String checkedStr = (displayInReadOnlyMode ? " CHECKED" : ""); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY + '"' + checkedStr + '>'); htmlBody.append(" Display In Restricted Read-Only Mode"); htmlBody.append(" <BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Update Description\">" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Writes the list of real job folders to the client as simple text output. * * @param requestInfo The state information for this request. */ static void handleListRealFolders(RequestInfo requestInfo) { // Indicate that we will be generating all our output here. HttpServletResponse response = requestInfo.response; requestInfo.generateHTML = false; response.setContentType("text/plain"); // Retrieve the set of job folders defined in the config directory. JobFolder[] folders; try { folders = configDB.getFolders(); } catch (DatabaseException de) { response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, "Unable to retrieve folder list -- " + de); try { PrintWriter writer = response.getWriter(); writer.println("Unable to retrieve folder list -- " + de); writer.flush(); } catch (IOException ioe) {} return; } // Get the writer that will be used for sending data to the client. PrintWriter writer; try { writer = response.getWriter(); } catch (IOException ioe) { // Not much that can be done about this. ioe.printStackTrace(); return; } // Write the folder list to the client. for (int i=0; i < folders.length; i++) { writer.println(folders[i].getFolderName()); } writer.flush(); } /** * Writes the list of virtual job folders to the client as simple text output. * * @param requestInfo The state information for this request. */ static void handleListVirtualFolders(RequestInfo requestInfo) { // Indicate that we will be generating all our output here. HttpServletResponse response = requestInfo.response; requestInfo.generateHTML = false; response.setContentType("text/plain"); // Retrieve the set of job folders defined in the config directory. JobFolder[] folders; try { folders = configDB.getVirtualFolders(); } catch (DatabaseException de) { response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, "Unable to retrieve folder list -- " + de); try { PrintWriter writer = response.getWriter(); writer.println("Unable to retrieve folder list -- " + de); writer.flush(); } catch (IOException ioe) {} return; } // Get the writer that will be used for sending data to the client. PrintWriter writer; try { writer = response.getWriter(); } catch (IOException ioe) { // Not much that can be done about this. ioe.printStackTrace(); return; } // Write the folder list to the client. for (int i=0; i < folders.length; i++) { writer.println(folders[i].getFolderName()); } writer.flush(); } /** * Handles all processing related to viewing and managing virtual job folders. * * @param requestInfo The state information for this request. */ static void handleVirtualJobFolders(RequestInfo requestInfo) { logMessage(requestInfo, "In handleVirtualJobFolders()"); // 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; } // See if a folder name has been specified. If so, then work with that // folder. Otherwise, show the set of folders that have been defined. String folderName = request.getParameter(Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER); 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")); } if ((folderName != null) && (folderName.length() > 0)) { String submitStr = request.getParameter(Constants.SERVLET_PARAM_SUBMIT); if ((submitStr == null) || (submitStr.length() == 0) || submitStr.equals(Constants.SUBMIT_STRING_SELECT_ALL) || submitStr.equals(Constants.SUBMIT_STRING_DESELECT_ALL)) { handleViewVirtualFolder(requestInfo, folderName); } else if (submitStr.equals(Constants.SUBMIT_STRING_CREATE_VIRTUAL_FOLDER)) { if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission " + "to manage job folders."); } try { JobFolder folder = new JobFolder(folderName, displayInReadOnlyMode, true, null, null, null, null, null, null, null); configDB.writeVirtualFolder(folder); } catch (DatabaseException de) { infoMessage.append(de.getMessage() + "<BR>" + EOL); } handleViewVirtualFolderList(requestInfo); return; } else if (submitStr.equals(Constants.SUBMIT_STRING_DELETE_VIRTUAL_FOLDER)) { if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission " + "to manage job folders."); } String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && confirmStr.equals("Yes")) { try { configDB.removeVirtualFolder(folderName); infoMessage.append("Virtual job folder \"" + folderName + "\" has been removed from the configuration " + "directory.<BR>" + EOL); } catch (DatabaseException de) { infoMessage.append("Unable to remove virtual job folder \"" + folderName + "\" from the configuration " + "directory -- " + de.getMessage() + "<BR>" + EOL); } handleViewVirtualFolderList(requestInfo); } else if ((confirmStr != null) && confirmStr.equals("No")) { infoMessage.append("Virtual job folder \"" + folderName + "\" was not removed from the configuration " + "directory.<BR>" + EOL); handleViewVirtualFolder(requestInfo, folderName); } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Delete Virtual Job Folder \"" + folderName + "\"</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to delete this virtual " + "job folder?" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + 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_VIRTUAL) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_DELETE_VIRTUAL_FOLDER) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIEW_CATEGORY, Constants.SERVLET_SECTION_JOB_VIEW_VIRTUAL) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER, folderName) + 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 (submitStr.equals(Constants.SUBMIT_STRING_EDIT_DESCRIPTION)) { // The user must have permission to manage job folders to be able to // do anything here. if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission " + "to manage job folders."); } // See if the operation has been confirmed. If so, then make the // requested change. If not, then request a new description from the // user. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && (confirmStr.length() > 0)) { // Get the new description to use and update the job information in // the configuration directory. String description = request.getParameter(Constants.SERVLET_PARAM_JOB_DESCRIPTION); try { JobFolder folder = configDB.getVirtualFolder(folderName); folder.setDescription(description); folder.setDisplayInReadOnlyMode(displayInReadOnlyMode); configDB.writeVirtualFolder(folder); infoMessage.append("Successfully updated the folder description." + "<BR>" + EOL); } catch (Exception e) { infoMessage.append("Unable to update the folder description: " + e.getMessage() + "<BR>" + EOL); } handleViewVirtualFolder(requestInfo, folderName); return; } else { // Get the job folder with which we will be working. JobFolder folder = null; try { folder = configDB.getVirtualFolder(folderName); } catch (Exception e) { infoMessage.append("Unable to retrieve virtual job folder \"" + folderName + "\" -- " + e.getMessage() + "<BR>" + EOL); handleViewVirtualFolderList(requestInfo); return; } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Update Description for Virtual Job Folder \"" + folderName + "\"</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Please provide the new description for the " + "virtual job folder." + 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_VIEW_VIRTUAL) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_EDIT_DESCRIPTION) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIEW_CATEGORY, Constants.SERVLET_SECTION_JOB_VIEW_VIRTUAL) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER, folderName) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } String description = folder.getDescription(); if (description == null) { description = ""; } htmlBody.append(" <TEXTAREA NAME=\"" + Constants.SERVLET_PARAM_JOB_DESCRIPTION + "\" ROWS=\"5\" COLS=\"80\">" + description + "</TEXTAREA>" + EOL); htmlBody.append(" <BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY + '"' + (displayInReadOnlyMode ? " CHECKED" : "") + '>' + EOL); htmlBody.append(" Display In Restricted Read-Only Mode" + EOL); htmlBody.append(" <BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Update Description\">" + EOL); htmlBody.append("</FORM>" + EOL); } } else if (submitStr.equals(Constants.SUBMIT_STRING_CLONE)) { String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("ERROR: No job IDs specified to clone.<BR>" + EOL); handleViewVirtualFolder(requestInfo, folderName); return; } handleMassClone(requestInfo, jobIDs); } else if (submitStr.equals(Constants.SUBMIT_STRING_COMPARE)) { String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("ERROR: No job IDs specified to compare.<BR>" + EOL); handleViewVirtualFolder(requestInfo, folderName); return; } handleMassCompare(requestInfo, jobIDs); } else if (submitStr.equals( Constants.SUBMIT_STRING_REMOVE_FROM_VIRTUAL_FOLDER)) { if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission " + "to manage job folders."); } String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("ERROR: No job IDs specified to remove from " + "this virtual job folder.<BR>" + EOL); handleViewVirtualFolder(requestInfo, folderName); return; } String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && confirmStr.equals("Yes")) { try { JobFolder folder = configDB.getVirtualFolder(folderName); for (int i=0; i < jobIDs.length; i++) { folder.removeJobID(jobIDs[i]); } configDB.writeVirtualFolder(folder); infoMessage.append("Successfully removed the selected jobs from " + "virtual job folder \"" + folderName + "\".<BR>" + EOL); } catch (Exception e) { infoMessage.append("Unable to remove jobs from virtual job " + "folder \"" + folderName + "\" from the configuration directory -- " + e.getMessage() + "<BR>" + EOL); } handleViewVirtualFolder(requestInfo, folderName); } else if ((confirmStr != null) && confirmStr.equals("No")) { infoMessage.append("No jobs were removed from virtual job folder \"" + folderName + "\".<BR>" + EOL); handleViewVirtualFolder(requestInfo, folderName); } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Remove Jobs from Virtual Job Folder \"" + folderName + "\"</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to remove the selected " + "jobs from this virtual job folder?" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + 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_VIRTUAL) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_REMOVE_FROM_VIRTUAL_FOLDER) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIEW_CATEGORY, Constants.SERVLET_SECTION_JOB_VIEW_VIRTUAL) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER, folderName) + EOL); for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + 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 (submitStr.equals(Constants.SUBMIT_STRING_EXPORT)) { String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("ERROR: No job IDs specified to export.<BR>" + EOL); handleViewVirtualFolder(requestInfo, folderName); return; } handleMassExport(requestInfo, jobIDs); } else if (submitStr.equals(Constants.SUBMIT_STRING_GENERATE_REPORT)) { handleGenerateReport(requestInfo); } } else { String submitStr = request.getParameter(Constants.SERVLET_PARAM_SUBMIT); if ((submitStr != null) && submitStr.equals(Constants.SUBMIT_STRING_CREATE_VIRTUAL_FOLDER)) { if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission " + "to manage job folders."); } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Create a New Virtual Job Folder</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Enter the name to use for the new virtual job " + "folder." + 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_VIEW_VIRTUAL) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_CREATE_VIRTUAL_FOLDER) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" Virtual Folder Name: " + EOL); htmlBody.append(" <INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER + "\" SIZE=\"40\">" + EOL); htmlBody.append(" <BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_DISPLAY_IN_READ_ONLY + '"' + (displayInReadOnlyMode ? " CHECKED" : "") + '>' + EOL); htmlBody.append(" Display In Restricted Read-Only Mode" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Create Virtual " + "Folder\">" + EOL); htmlBody.append("</FORM>" + EOL); } else { handleViewVirtualFolderList(requestInfo); } } } /** * Handles all processing related to viewing the list of real job folders * that have been defined in the configuration directory. * * @param requestInfo The state information for this request. */ static void handleViewRealFolderList(RequestInfo requestInfo) { // Get the important state information for the request. String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Manage Real Job Folders</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); JobFolder[] folders; try { folders = configDB.getFolders(); } catch (DatabaseException de) { infoMessage.append("ERROR: Unable to retrieve real job folders -- " + de.getMessage() + "<BR>" + EOL); htmlBody.append("Unable to retrieve real job folders." + EOL); return; } if ((folders == null) || (folders.length == 0)) { htmlBody.append("No real job folders have been defined." + EOL); } else { htmlBody.append("The following real job folders have been defined " + "in the SLAMD server:" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + EOL); for (int i=0; ((folders != null) && (i < folders.length)); i++) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, Constants.SERVLET_PARAM_JOB_FOLDER, folders[i].getFolderName(), folders[i].getFolderName()); String description = folders[i].getDescription(); if ((description == null) || (description.length() == 0)) { htmlBody.append(" <LI>" + link + "</LI>" + EOL); } else { htmlBody.append(" <LI>" + link + " -- " + description + "</LI>" + EOL); } } htmlBody.append("</UL>" + 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_MASS_OP) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } if (requestInfo.mayManageFolders) { htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_CREATE_FOLDER + "\">" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_DELETE_FOLDER + "\">" + EOL); } htmlBody.append("</FORM>" + EOL); } /** * Handles all processing related to viewing the list of virtual job folders * that have been defined in the configuration directory. * * @param requestInfo The state information for this request. */ static void handleViewVirtualFolderList(RequestInfo requestInfo) { // Get the important state information for the request. String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Manage Virtual Job Folders</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); JobFolder[] folders; try { folders = configDB.getVirtualFolders(); } catch (DatabaseException de) { infoMessage.append("ERROR: Unable to retrieve virtual job folders -- " + de.getMessage() + "<BR>" + EOL); htmlBody.append("Unable to retrieve virtual job folders." + EOL); return; } if ((folders == null) || (folders.length == 0)) { htmlBody.append("No virtual job folders have been defined." + EOL); } else { htmlBody.append("The following virtual job folders have been defined " + "in the SLAMD server:" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + EOL); for (int i=0; ((folders != null) && (i < folders.length)); i++) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_VIRTUAL, Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER, folders[i].getFolderName(), folders[i].getFolderName()); String description = folders[i].getDescription(); if ((description == null) || (description.length() == 0)) { htmlBody.append(" <LI>" + link + "</LI>" + EOL); } else { htmlBody.append(" <LI>" + link + " -- " + description + "</LI>" + EOL); } } htmlBody.append("</UL>" + 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_VIEW_VIRTUAL) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } if (requestInfo.mayManageFolders) { htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_CREATE_VIRTUAL_FOLDER + "\">" + EOL); } htmlBody.append("</FORM>" + EOL); } /** * Handles all processing related to viewing the list of jobs contained in a * virtual folder. * * @param requestInfo The state information for this request. * @param folderName The name of the virtual folder to view. */ static void handleViewVirtualFolder(RequestInfo requestInfo, String folderName) { logMessage(requestInfo, "In handleVirtualJobFolders()"); // 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 requested virtual folder. JobFolder folder = null; try { folder = configDB.getVirtualFolder(folderName); } catch (Exception e) { infoMessage.append("Unable to retrieve jobs for folder \"" + folderName + "\" -- " + e.getMessage() + "<BR>" + EOL); handleViewVirtualFolderList(requestInfo); return; } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Virtual Job Folder \"" + folderName + "\"</SPAN>" + EOL); htmlBody.append("<BR>" + EOL); if (folder != null) { String description = folder.getDescription(); if ((description != null) && (description.length() > 0)) { htmlBody.append("<BLOCKQUOTE>" + EOL); htmlBody.append(" " + description + EOL); htmlBody.append("</BLOCKQUOTE>" + 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_VIEW_VIRTUAL) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER, folderName) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } if (requestInfo.mayManageFolders) { htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_DELETE_VIRTUAL_FOLDER + "\">" + EOL); htmlBody.append("    " + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_EDIT_DESCRIPTION + "\">" + EOL); } htmlBody.append("</FORM>" + 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_VIEW_VIRTUAL) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIEW_CATEGORY, Constants.SERVLET_SECTION_JOB_VIEW_VIRTUAL) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER, folderName) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } Job[] jobs; try { jobs = configDB.getVirtualJobs(folderName); } catch (Exception e) { infoMessage.append("Unable to retrieve jobs for folder \"" + folderName + "\" -- " + e.getMessage() + "<BR>" + EOL); return; } if (jobs.length == 0) { htmlBody.append("There are no jobs contained in this virtual folder." + EOL); return; } 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); htmlBody.append(" <TD><B>Start Time</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 link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, jobs[i].getJobID(), Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER, folderName, 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); htmlBody.append(" <TD>" + displayDateFormat.format(jobs[i].getStartTime()) + "</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 (requestInfo.mayScheduleJob) { actions.add(Constants.SUBMIT_STRING_CLONE); } if (requestInfo.mayViewJob && (! disableGraphs)) { actions.add(Constants.SUBMIT_STRING_COMPARE); } if (requestInfo.mayExportJobData) { actions.add(Constants.SUBMIT_STRING_EXPORT); } if (requestInfo.mayManageFolders) { actions.add(Constants.SUBMIT_STRING_REMOVE_FROM_VIRTUAL_FOLDER); } if ((reportGenerators != null) && (reportGenerators.length > 0)) { actions.add(Constants.SUBMIT_STRING_GENERATE_REPORT); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); for (int i=0; i < actions.size(); i++) { htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + actions.get(i) + "\">" + EOL); if (((i % 5) == 4) && (i < (actions.size() - 1))) { htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); } } htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } /** * Handles all processing necessary to generate a report of job results. * * @param requestInfo The state information for this request. */ static void handleGenerateReport(RequestInfo requestInfo) { logMessage(requestInfo, "In handleGenerateReport()"); // If the user doesn't have view job permission, 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; // Make sure that at least one report generator has been defined. if ((reportGenerators == null) || (reportGenerators.length == 0)) { infoMessage.append("ERROR: No report generators defined<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Generate Job Data Report</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Job reporting is unavailable because no report " + "generators have been defined in the configuration." + EOL); return; } // Determine which jobs should be included in the report. String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if (jobIDs == null) { jobIDs = new String[0]; } String[] optimizingJobIDs = request.getParameterValues(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID); if (optimizingJobIDs == null) { optimizingJobIDs = new String[0]; } if ((jobIDs.length == 0) && (optimizingJobIDs.length == 0)) { boolean virtualFolder = false; String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if ((folderName == null) || (folderName.length() == 0)) { folderName = request.getParameter(Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER); if (folderName != null) { virtualFolder = true; } } try { Job[] jobs; OptimizingJob[] optimizingJobs; if (virtualFolder) { jobs = configDB.getSummaryVirtualJobs(folderName); optimizingJobs = new OptimizingJob[0]; } else { jobs = configDB.getSummaryJobs(folderName); optimizingJobs = configDB.getSummaryOptimizingJobs(folderName); } jobIDs = new String[jobs.length]; for (int i=0; i < jobs.length; i++) { jobIDs[i] = jobs[i].getJobID(); } optimizingJobIDs = new String[optimizingJobs.length]; for (int i=0; i < optimizingJobs.length; i++) { optimizingJobIDs[i] = optimizingJobs[i].getOptimizingJobID(); } } catch (Exception e) { slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(e)); infoMessage.append("ERROR: Unable to retrieve job information -- " + e.getMessage() + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Generate Job Data Report</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("An error occurred while trying to retrieve " + "information about the jobs and/or optimizing jobs " + "in folder " + folderName + '.' + EOL); return; } if ((jobIDs.length == 0) && (optimizingJobIDs.length == 0)) { infoMessage.append("ERROR: No job information found<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Generate Job Data Report</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("No job or optimizing job data was found in folder " + folderName + '.' + EOL); return; } } // Determine whether we know which report generator to use. ReportGenerator reportGenerator = null; if (reportGenerators.length == 1) { reportGenerator = reportGenerators[0].newInstance(); } else { String generatorName = request.getParameter(Constants.SERVLET_PARAM_REPORT_GENERATOR); if ((generatorName != null) && (generatorName.length() > 0)) { for (int i=0; i < reportGenerators.length; i++) { if (generatorName.equals(reportGenerators[i].getClass().getName())) { reportGenerator = reportGenerators[i].newInstance(); break; } } } } if (reportGenerator == null) { // We need to provide a form that allows the user to select the report // generator. htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Generate Job Data Report</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Please select the report generator to use." + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">"); 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); for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + EOL); } for (int i=0; i < optimizingJobIDs.length; i++) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobIDs[i]) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_REPORT_GENERATOR + "\">"); for (int i=0; i < reportGenerators.length; i++) { htmlBody.append(" <OPTION VALUE=\"" + reportGenerators[i].getClass().getName() + "\">" + reportGenerators[i].getReportGeneratorName() + EOL); } htmlBody.append(" </SELECT>"); htmlBody.append(" <BR><BR>"); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Continue\">" + EOL); htmlBody.append("</FORM>"); return; } // Determine whether the user has submitted the form to configure the // report parameters. Parameter[] params = reportGenerator.newInstance(). getReportParameterStubs().getParameters(); String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr != null) && (confirmStr.length() > 0)) { boolean configValid = true; 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("Invalid value for parameter \"" + params[i].getDisplayName() + "\" -- " + ive.getMessage() + "<BR>" + EOL); configValid = false; } } if (configValid) { reportGenerator.initializeReporter(new ParameterList(params)); for (int i=0; i < jobIDs.length; i++) { try { Job job = configDB.getJob(jobIDs[i]); reportGenerator.addJobReport(job); } catch (Exception e) { // We should probably display an error page here, but since it // should be very rare, just log a message and continue. slamdServer.logMessage(Constants.LOG_LEVEL_JOB_PROCESSING, "Unable to retrieve job " + jobIDs[i] + " to include in generated report"); } } for (int i=0; i < optimizingJobIDs.length; i++) { try { OptimizingJob optimizingJob = getOptimizingJob(optimizingJobIDs[i]); reportGenerator.addOptimizingJobReport(optimizingJob); } catch (Exception e) { // We should probably display an error page here, but since it // should be very rare, just log a message and continue. slamdServer.logMessage(Constants.LOG_LEVEL_JOB_PROCESSING, "Unable to retrieve optimizing job " + optimizingJobIDs[i] + " to include in generated report"); } } requestInfo.generateHTML = false; reportGenerator.generateReport(requestInfo); return; } } // Display the form that allows the user to customize the report // that will be generated. htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Generate Job Data Report</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Please indicate how the report should be generated." + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\">"); 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_REPORT_GENERATOR, reportGenerator.getClass().getName()) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_CONFIRMED, "1") + EOL); for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + EOL); } for (int i=0; i < optimizingJobIDs.length; i++) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobIDs[i]) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); for (int i=0; i < params.length; i++) { htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + params[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + params[i].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=\"Continue\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>"); } /** * Handles all processing necessary to perform operations on multiple jobs at * the same time. * * @param requestInfo The state information for this request. */ static void handleMassOperation(RequestInfo requestInfo) { HttpServletRequest request = requestInfo.request; // Get the job IDs of the jobs on which to perform the operation. String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); // Determine which mass operation the user wishes to perform. String opString = request.getParameter(Constants.SERVLET_PARAM_SUBMIT); if (opString == null) { return; } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_SELECT_ALL) || opString.equalsIgnoreCase(Constants.SUBMIT_STRING_DESELECT_ALL)) { handleViewJob(requestInfo, request.getParameter(Constants.SERVLET_PARAM_VIEW_CATEGORY), null, null); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_CANCEL)) { handleMassCancel(requestInfo, jobIDs); } else if (opString.equalsIgnoreCase( Constants.SUBMIT_STRING_CANCEL_AND_DELETE)) { handleMassCancelAndDelete(requestInfo, jobIDs); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_CLONE)) { handleMassClone(requestInfo, jobIDs); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_COMPARE)) { handleMassCompare(requestInfo, jobIDs); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_DELETE)) { handleMassDelete(requestInfo, jobIDs); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_DISABLE)) { handleMassDisable(requestInfo, jobIDs); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_ENABLE)) { handleMassEnable(requestInfo, jobIDs); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_EXPORT)) { handleMassExport(requestInfo, jobIDs); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_CREATE_FOLDER)) { handleCreateFolder(requestInfo); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_DELETE_FOLDER)) { handleDeleteFolder(requestInfo); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_MOVE)) { handleMoveJobs(requestInfo); } else if (opString.equalsIgnoreCase( Constants.SUBMIT_STRING_ADD_TO_VIRTUAL_FOLDER)) { handleAddToVirtualFolder(requestInfo); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_PUBLISH_JOBS)) { handleMassPublish(requestInfo, true); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_DEPUBLISH_JOBS)) { handleMassPublish(requestInfo, false); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_GENERATE_REPORT)) { handleGenerateReport(requestInfo); } } /** * Handles the work of cancelling multiple jobs. * * @param requestInfo The state information for this request. * @param jobIDs The job IDs of the jobs to cancel. */ static void handleMassCancel(RequestInfo requestInfo, String[] jobIDs) { logMessage(requestInfo, "In handleMassCancel()"); // 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 have permission to cancel jobs to access this section. if (! requestInfo.mayCancelJob) { logMessage(requestInfo, "No mayCancelJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "cancel jobs."); return; } String category = request.getParameter(Constants.SERVLET_PARAM_VIEW_CATEGORY); // Make sure that at least one job ID was specified. If not, then print an // error message and view the appropriate set of jobs. if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("No jobs specified to cancel.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); return; } // See if the user has provided confirmation. If so, then cancel the jobs // or don't based on the results of the confirmation. If no confirmation // has been provided, then request it. 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 Selected Jobs</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to cancel the selected " + "jobs?" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + EOL); for (int i=0; i < jobIDs.length; i++) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, jobIDs[i], jobIDs[i]); htmlBody.append(" <LI>" + link + "</LI>" + EOL); } htmlBody.append("</UL>" + 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_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_CANCEL) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIEW_CATEGORY, category) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + 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")) { for (int i=0; i < jobIDs.length; i++) { scheduler.cancelJob(jobIDs[i], false); infoMessage.append("Requested cancel for job " + jobIDs[i] + ".<BR>" + EOL); } infoMessage.append("It may take several seconds for all jobs to be " + "cancelled.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); } else { infoMessage.append("No jobs were cancelled.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); } } /** * Handles the work of cancelling multiple jobs and removing them from SLAMD * entirely. * * @param requestInfo The state information for this request. * @param jobIDs The job IDs of the jobs to cancel. */ static void handleMassCancelAndDelete(RequestInfo requestInfo, String[] jobIDs) { logMessage(requestInfo, "In handleMassCancelAndDelete()"); // 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 have permission to cancel and delete jobs to access this // section. if (! requestInfo.mayCancelJob) { logMessage(requestInfo, "No mayCancelJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "cancel jobs."); return; } else if (! requestInfo.mayDeleteJob) { logMessage(requestInfo, "No mayDeleteJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "delete jobs."); return; } String category = request.getParameter(Constants.SERVLET_PARAM_VIEW_CATEGORY); // Make sure that at least one job ID was specified. If not, then print an // error message and view the appropriate set of jobs. if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("No jobs specified to cancel and delete.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); return; } // See if any of the jobs are no longer running or are associated with // optimizing jobs. If so, then remove them from the list of jobs on which // we will operate. ArrayList<String> idList = new ArrayList<String>(jobIDs.length); for (int i=0; i < jobIDs.length; i++) { Job job = scheduler.getPendingJob(jobIDs[i]); if (job == null) { infoMessage.append("Not going to cancel and delete job " + jobIDs[i] + " because it is no longer in the pending jobs " + "queue.<BR>" + EOL); } else if (job.getOptimizingJobID() != null) { infoMessage.append("Not going to cancel and delete job " + jobIDs[i] + " because it is associated with an optimizing " + "job.<BR>" + EOL); } else { idList.add(jobIDs[i]); } } jobIDs = new String[idList.size()]; idList.toArray(jobIDs); if (jobIDs.length == 0) { infoMessage.append("No jobs left to cancel and delete.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); return; } // See if the user has provided confirmation. If so, then cancel the jobs // or don't based on the results of the confirmation. If no confirmation // has been provided, then request it. 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 and Delete Selected Jobs</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to cancel and delete the " + "selected jobs?" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + EOL); for (int i=0; i < jobIDs.length; i++) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, jobIDs[i], jobIDs[i]); htmlBody.append(" <LI>" + link + "</LI>" + EOL); } htmlBody.append("</UL>" + 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_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_CANCEL_AND_DELETE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIEW_CATEGORY, category) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + 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")) { for (int i=0; i < jobIDs.length; i++) { scheduler.cancelAndDeleteJob(jobIDs[i]); infoMessage.append("Requested cancel and delete for job " + jobIDs[i] + ".<BR>" + EOL); } handleViewJob(requestInfo, category, null, null); } else { infoMessage.append("No jobs were cancelled.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); } } /** * Handles the work of cloning multiple jobs. * * @param requestInfo The state information for this request. * @param jobIDs The job IDs of the jobs to clone. */ static void handleMassClone(RequestInfo requestInfo, String[] jobIDs) { logMessage(requestInfo, "In handleMassClone()"); // The user must have permission to schedule jobs to access this section. if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "clone 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; String category = request.getParameter(Constants.SERVLET_PARAM_VIEW_CATEGORY); // Make sure that at least one job ID was specified. If not, then print an // error message and view the appropriate set of jobs. if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("No jobs specified to clone.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); return; } // See if the user has provided confirmation. If so, then clone the jobs // or don't based on the results of the confirmation. If no confirmation // has been provided, then request it. 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 + "\">Clone Selected Jobs</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to clone the selected " + "jobs?" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + EOL); for (int i=0; i < jobIDs.length; i++) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, jobIDs[i], jobIDs[i]); htmlBody.append(" <LI>" + link + "</LI>" + EOL); } htmlBody.append("</UL>" + 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_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_CLONE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIEW_CATEGORY, category) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } try { JobFolder[] folders = configDB.getFolders(); if ((folders != null) && (folders.length > 0)) { String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if (folderName == null) { folderName = ""; } htmlBody.append(" Place jobs in folder " + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_JOB_FOLDER + "\">" + EOL); htmlBody.append(" <OPTION VALUE=\"\">Unclassified" + EOL); for (int i=0; i < folders.length; i++) { htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + '"'); if (folderName.equals(folders[i].getFolderName())) { htmlBody.append(" SELECTED"); } htmlBody.append("> " + folders[i].getFolderName() + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" <BR>" + EOL); } else { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, "") + EOL); } } catch (DatabaseException de) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, "") + EOL); } htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_MAKE_INTERDEPENDENT + "\">" + EOL); htmlBody.append(" Make Jobs Interdependent" + EOL); htmlBody.append(" <BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_DISABLED + "\" CHECKED>" + EOL); htmlBody.append(" Make Jobs Disabled" + 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); } else if (confirmStr.equalsIgnoreCase("yes")) { boolean makeInterDependent = false; boolean makeDisabled = false; String folderName = null; String dependentID = null; String dependStr = request.getParameter( Constants.SERVLET_PARAM_JOB_MAKE_INTERDEPENDENT); if (dependStr != null) { makeInterDependent = (dependStr.equalsIgnoreCase("true") || dependStr.equalsIgnoreCase("yes") || dependStr.equalsIgnoreCase("on") || dependStr.equalsIgnoreCase("1")); } String disabledStr = request.getParameter(Constants.SERVLET_PARAM_JOB_DISABLED); if (disabledStr != null) { makeDisabled = (disabledStr.equalsIgnoreCase("true") || disabledStr.equalsIgnoreCase("yes") || disabledStr.equalsIgnoreCase("on") || disabledStr.equalsIgnoreCase("1")); } folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if ((folderName == null) || (folderName.length() == 0)) { folderName = null; } for (int i=0; i < jobIDs.length; i++) { Job j = null; try { j = configDB.getJob(jobIDs[i]); if (j == null) { infoMessage.append("Unable to clone job " + jobIDs[i] + ": Job not found.<BR>" + EOL); continue; } } catch (Exception e) { infoMessage.append("Unable to clone job " + jobIDs[i] + ": " + e + "<BR>" + EOL); continue; } try { Job newJob = new Job(slamdServer, j.getJobClassName(), j.getNumberOfClients(), j.getThreadsPerClient(), j.getThreadStartupDelay(), new Date(), null, j.getDuration(), j.getCollectionInterval(), j.getParameterList(), j.displayInReadOnlyMode()); if (makeDisabled) { newJob.setJobState(Constants.JOB_STATE_DISABLED); } newJob.setJobDescription(j.getJobDescription()); newJob.setWaitForClients(j.waitForClients()); newJob.setRequestedClients(j.getRequestedClients()); newJob.setResourceMonitorClients(j.getResourceMonitorClients()); newJob.setJobComments(j.getJobComments()); if (dependentID != null) { newJob.setDependencies(new String[] { dependentID }); } // Normally, this wouldn't be required, but we'll do it anyway because // some jobs can do sneaky things in the validateJobInfo() method. try { JobClass jobClass = newJob.getJobClass(); jobClass.validateJobInfo(newJob.getNumberOfClients(), newJob.getThreadsPerClient(), newJob.getThreadStartupDelay(), newJob.getStartTime(), newJob.getStopTime(), newJob.getDuration(), newJob.getCollectionInterval(), newJob.getParameterList()); } catch (InvalidValueException ive) { infoMessage.append("WARNING: validateJobInfo failed when " + "cloning job " + j.getJobID() + ": " + ive.getMessage() + "<BR>" + EOL); } String newJobID = scheduler.scheduleJob(newJob, folderName); infoMessage.append("Successfully scheduled job " + newJobID + " for execution.<BR>" + EOL); if (makeInterDependent) { dependentID = newJobID; } } catch (Exception e) { infoMessage.append("Unable to clone job " + jobIDs[i] + ": " + e + "<BR>" + EOL); } } if (makeDisabled) { infoMessage.append("Note that all cloned jobs are currently disabled " + "so that they may be edited as necessary.<BR>" + EOL); } handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_PENDING, null, null); } else { infoMessage.append("No jobs were cloned.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); } } /** * Handles the work of comparing multiple jobs. * * @param requestInfo The state information for this request. * @param jobIDs The job IDs of the jobs to compare. */ static void handleMassCompare(RequestInfo requestInfo, String[] jobIDs) { logMessage(requestInfo, "In handleMassCompare()"); // The user must have permission to view jobs to access 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; String category = request.getParameter(Constants.SERVLET_PARAM_VIEW_CATEGORY); // Make sure that at least two job IDs were specified. If not, then print // an appropriate error message and go back to viewing the completed jobs. if ((jobIDs == null) || (jobIDs.length < 2)) { infoMessage.append("You must specify at least two jobs of the same " + "type to be compared.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); return; } // Retrieve all of the jobs and make sure that they are all of the same // type. ArrayList<Job> jobList = new ArrayList<Job>(); String jobClass = null; for (int i=0; i < jobIDs.length; i++) { Job job = null; try { job = configDB.getJob(jobIDs[i]); if (job == null) { infoMessage.append("Unable to retrieve job " + jobIDs[i] + " -- job not found.<BR>" + EOL); } else { // Make sure that the job is of the same type as all other jobs in the // selection. if (jobClass == null) { jobClass = job.getJobClassName(); } else { if (! jobClass.equals(job.getJobClassName())) { infoMessage.append("Skipping job " + jobIDs[i] + " because it is not of the same type as the " + " first job selected (" + jobClass + ").<BR>" + EOL); continue; } } // Make sure that the job has statistics available. if (! job.hasStats()) { infoMessage.append("Skipping job " + jobIDs[i] + " because it does not have any statistics " + "available.<BR>" + EOL); continue; } jobList.add(job); } } catch (Exception e) { infoMessage.append("Unable to retrieve job " + jobIDs[i] + " -- " + e + "<BR>" + EOL); } } // Make sure that at least two jobs were placed in the job list. if (jobList.size() < 2) { infoMessage.append("Unable to perform the requested comparison because " + "there were not at least two jobs meeting the " + "necessary criteria.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); return; } // Sort the job information based on the actual start times for the jobs. // Since there should not be that many jobs to compare, and since it is // likely that they will already be sorted anyway, then a selection sort // should be the fastest and simplest way to do it. long[] startTimes = new long[jobList.size()]; Job[] jobs = new Job[jobList.size()]; for (int i=0; i < jobs.length; i++) { jobs[i] = jobList.get(i); startTimes[i] = jobs[i].getActualStartTime().getTime(); } for (int i=0; i < jobs.length; i++) { int slot = -1; long minStartTime = startTimes[i]; for (int j=i+1; j < jobs.length; j++) { if (startTimes[j] < minStartTime) { slot = j; minStartTime = startTimes[j]; } } if (slot > 0) { Job tempJob = jobs[slot]; long tempStartTime = startTimes[slot]; jobs[slot] = jobs[i]; startTimes[slot] = startTimes[i]; jobs[i] = tempJob; startTimes[i] = tempStartTime; } } // Get the names of the stat trackers that will be available for comparison. // For now, this will only be the stat trackers available in the first job // in the list of selected jobs. Although it is possible that the different // jobs selected will have different sets of statistics, that introduces too // much complexity into this code for the current version. String[] trackerNames = jobs[0].getStatTrackerNames(); // Determine how the comparison should be done. It can either be a trend // comparison (where each job counts as one data point) or a side-by-side // comparison (where the jobs are compared across their entire durations). String confirmedStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmedStr != null) && confirmedStr.equals(Constants.CONFIG_VALUE_FALSE)) { String trackerName = request.getParameter(Constants.SERVLET_PARAM_STAT_TRACKER); StatTracker infoTracker = jobs[0].getStatTrackers(trackerName)[0]; int graphWidth = defaultGraphWidth; try { graphWidth = Integer.parseInt(request.getParameter( Constants.SERVLET_PARAM_GRAPH_WIDTH)); } catch (Exception e) {} int graphHeight = defaultGraphHeight; try { graphHeight = Integer.parseInt(request.getParameter( Constants.SERVLET_PARAM_GRAPH_HEIGHT)); } catch (Exception e) {} htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Compare " + trackerName + " for Multiple \"" + jobs[0].getJobName() + "\" 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, Constants.SERVLET_SECTION_JOB_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_COMPARE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_CONFIRMED, Constants.CONFIG_VALUE_FALSE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_USE_REQUEST_PARAMS, Constants.CONFIG_VALUE_TRUE) + EOL); String hideStr = (graphInNewWindow ? Constants.CONFIG_VALUE_TRUE : Constants.CONFIG_VALUE_FALSE); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HIDE_SIDEBAR, hideStr) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } for (int i=0; i < jobs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobs[i].getJobID()) + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Graph Width</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_GRAPH_WIDTH + "\" VALUE=\"" + graphWidth + "\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Graph Height</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_GRAPH_HEIGHT + "\" VALUE=\"" + graphHeight + "\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Statistic to Compare</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_STAT_TRACKER + "\">" + EOL); for (int i=0; i < trackerNames.length; i++) { if (trackerName.equalsIgnoreCase(trackerNames[i])) { htmlBody.append(" <OPTION SELECTED VALUE=\"" + trackerNames[i] + "\">" + trackerNames[i] + EOL); } else { htmlBody.append(" <OPTION VALUE=\"" + trackerNames[i] + "\">" + trackerNames[i] + EOL); } } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); Parameter[] params = infoTracker.getGraphParameterStubs(jobs).clone().getParameters(); String useRequestValuesStr = request.getParameter(Constants.SERVLET_PARAM_USE_REQUEST_PARAMS); boolean useRequestValues = ((useRequestValuesStr != null) && (useRequestValuesStr.equals(Constants.CONFIG_VALUE_TRUE))); for (int i=0; i < params.length; i++) { if (useRequestValues) { try { String[] values = request.getParameterValues( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + params[i].getName()); params[i].htmlInputFormToValue(values); } catch (InvalidValueException ive) {} } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + params[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + params[i].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 COLSPAN=\"3\"><INPUT TYPE=\"SUBMIT\" " + "VALUE=\"Compare\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); // 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_GRAPH + '&' + Constants.SERVLET_PARAM_GRAPH_WIDTH + '=' + graphWidth + '&' + Constants.SERVLET_PARAM_GRAPH_HEIGHT + '=' + graphHeight + '&' + Constants.SERVLET_PARAM_STAT_TRACKER + '=' + URLEncoder.encode(trackerName, "UTF-8"); for (int i=0; i < jobIDs.length; i++) { imageURI += '&' + Constants.SERVLET_PARAM_JOB_ID + '=' + jobIDs[i]; } for (int i=0; i < params.length; i++) { imageURI += '&' + Constants.SERVLET_PARAM_JOB_PARAM_PREFIX + params[i].getName() + '=' + params[i].getValueString(); } htmlBody.append("<IMG SRC=\"" + imageURI.replace(' ', '+') + "\" WIDTH=\"" + graphWidth + "\" HEIGHT=\"" + graphHeight + "\" ALT=\"Graph of Results for Job " + "Comparison\">" + EOL); } catch (Exception e) { slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(e)); } } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Compare Multiple \"" + jobs[0].getJobName() + "\" Jobs</SPAN>" + EOL); htmlBody.append("<BR><BR>" + 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_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_COMPARE) + EOL); // Why is this set to "false"? It's a subtle difference, but it's used // in the previous section when assigning values to the parameters for the // stat tracker. If the value is set to "true", then the values of those // parameters will be set from the request parameters. If it's set to // something else, then the default values will be used. htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_CONFIRMED, Constants.CONFIG_VALUE_FALSE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_USE_REQUEST_PARAMS, Constants.CONFIG_VALUE_FALSE) + EOL); String hideStr = (graphInNewWindow ? Constants.CONFIG_VALUE_TRUE : Constants.CONFIG_VALUE_FALSE); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HIDE_SIDEBAR, hideStr) + 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(" <TABLE BORDER=\"0\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Statistic to Graph</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_STAT_TRACKER + "\">" + EOL); for (int i=0; i < trackerNames.length; i++) { htmlBody.append(" <OPTION VALUE=\"" + trackerNames[i] + "\">" + trackerNames[i] + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" VALUE=\"Graph\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR>" + EOL); boolean oneFound = false; boolean twoFound = false; for (int i=0; i < trackerNames.length; i++) { StatTracker[] trackers = jobs[0].getStatTrackers(trackerNames[i]); if ((trackers != null) && (trackers.length > 0) && trackers[0].isSearchable()) { if (oneFound) { twoFound = true; break; } else { oneFound = true; } } } if (twoFound) { 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_OVERLAY) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HIDE_SIDEBAR, hideStr) + 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=\"Graph Overlaid Statistics\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR>" + EOL); } for (int i=0; i < trackerNames.length; i++) { htmlBody.append("<B>" + trackerNames[i] + "</B><BR>" + EOL); htmlBody.append("<TABLE BORDER=\"1\">" + EOL); boolean labelsDisplayed = false; for (int j=0; j < jobs.length; j++) { StatTracker[] trackers = jobs[j].getStatTrackers(trackerNames[i]); if ((trackers != null) && (trackers.length > 0)) { StatTracker tracker = trackers[0].newInstance(); tracker.aggregate(trackers); if (! labelsDisplayed) { String[] labels = tracker.getSummaryLabels(); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><B>Job ID</B></TD>" + EOL); htmlBody.append(" <TD><B>Job Description</B></TD>" + EOL); for (int k=0; k < labels.length; k++) { htmlBody.append(" <TD><B>" + labels[k] + "</B></TD>" + EOL); } htmlBody.append(" </TR>" + EOL); labelsDisplayed = true; } htmlBody.append(" <TR>" + EOL); String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, jobs[j].getJobID(), jobs[j].getJobID()); htmlBody.append(" <TD>" + link + "</TD>" + EOL); htmlBody.append(" <TD>" + jobs[j].getJobDescription() + "</TD>" + EOL); String[] data = tracker.getSummaryData(); for (int k=0; k < data.length; k++) { htmlBody.append(" <TD>" + data[k] + "</TD>" + EOL); } htmlBody.append(" </TR>" + EOL); } } htmlBody.append("</TABLE>" + EOL); htmlBody.append("<BR><BR>" + EOL); } } } /** * Handles the work of deleting multiple jobs. * * @param requestInfo The state information for this request. * @param jobIDs The job IDs of the jobs to delete. */ static void handleMassDelete(RequestInfo requestInfo, String[] jobIDs) { logMessage(requestInfo, "In handleMassDelete()"); // The user must have permission to delete jobs to access this section. 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 infoMessage = requestInfo.infoMessage; StringBuilder htmlBody = requestInfo.htmlBody; String category = request.getParameter(Constants.SERVLET_PARAM_VIEW_CATEGORY); // Make sure that at least one job ID was specified. If not, then print an // error message and view the appropriate set of jobs. if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("No jobs specified to delete.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); return; } // See if the user has provided confirmation. If so, then delete the jobs // or don't based on the results of the confirmation. If no confirmation // has been provided, then request it. 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 + "\">Delete Selected Jobs</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to delete the selected " + "jobs?" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + EOL); for (int i=0; i < jobIDs.length; i++) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, jobIDs[i], jobIDs[i]); htmlBody.append(" <LI>" + link + "</LI>" + EOL); } htmlBody.append("</UL>" + 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_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_DELETE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIEW_CATEGORY, category) + EOL); String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if ((folderName != null) && (folderName.length() > 0)) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); } for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + 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")) { for (int i=0; i < jobIDs.length; i++) { Job job = null; try { job = configDB.getJob(jobIDs[i]); } catch (Exception e) {} if ((job != null) && (job.getOptimizingJobID() != null)) { OptimizingJob optimizingJob = null; try { optimizingJob = getOptimizingJob(job.getOptimizingJobID()); if (optimizingJob != null) { infoMessage.append("Not removing job " + jobIDs[i] + " because it is associated with optimizing " + "job " + job.getOptimizingJobID() + "<BR>" + EOL); continue; } } catch (Exception e) {} } try { configDB.removeJob(jobIDs[i]); infoMessage.append("Deleted job " + jobIDs[i] + ".<BR>" + EOL); } catch (DatabaseException de) { infoMessage.append("Unable to delete job " + jobIDs[i] + ": " + de + "<BR>" + EOL); } } handleViewJob(requestInfo, category, null, null); } else { infoMessage.append("No jobs were deleted.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); } } /** * Handles the work of disabling multiple jobs. * * @param requestInfo The state information for this request. * @param jobIDs The job IDs of the jobs to disable. */ static void handleMassDisable(RequestInfo requestInfo, String[] jobIDs) { logMessage(requestInfo, "In handleMassDisable()"); // The user must have permission to schedule jobs to access this section. if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "disable 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; String category = request.getParameter(Constants.SERVLET_PARAM_VIEW_CATEGORY); // Make sure that at least one job ID was specified. If not, then print an // error message and view the appropriate set of jobs. if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("No jobs specified to disable.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); return; } // See if the user has provided confirmation. If so, then disable the jobs // or don't based on the results of the confirmation. If no confirmation // has been provided, then request it. 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 Selected Jobs</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to disable the selected " + "jobs?" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + EOL); for (int i=0; i < jobIDs.length; i++) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, jobIDs[i], jobIDs[i]); htmlBody.append(" <LI>" + link + "</LI>" + EOL); } htmlBody.append("</UL>" + 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_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_DISABLE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIEW_CATEGORY, category) + EOL); for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + 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")) { for (int i=0; i < jobIDs.length; i++) { try { scheduler.disableJob(jobIDs[i]); infoMessage.append("Disabled job " + jobIDs[i] + ".<BR>" + EOL); } catch (SLAMDServerException sse) { infoMessage.append("Unable to disable job " + jobIDs[i] + ": " + sse + "<BR>" + EOL); } } handleViewJob(requestInfo, category, null, null); } else { infoMessage.append("No jobs were disabled.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); } } /** * Handles the work of enabling multiple jobs. * * @param requestInfo The state information for this request. * @param jobIDs The job IDs of the jobs to enable. */ static void handleMassEnable(RequestInfo requestInfo, String[] jobIDs) { logMessage(requestInfo, "In handleMassEnable()"); // The user must have permission to schedule jobs to access this section. if (! requestInfo.mayScheduleJob) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "enable 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; String category = request.getParameter(Constants.SERVLET_PARAM_VIEW_CATEGORY); // Make sure that at least one job ID was specified. If not, then print an // error message and view the appropriate set of jobs. if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("No jobs specified to enable.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); return; } // See if the user has provided confirmation. If so, then enable the jobs // or don't based on the results of the confirmation. If no confirmation // has been provided, then request it. 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 Selected Jobs</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to enable the selected " + "jobs?" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + EOL); for (int i=0; i < jobIDs.length; i++) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_GENERIC, Constants.SERVLET_PARAM_JOB_ID, jobIDs[i], jobIDs[i]); htmlBody.append(" <LI>" + link + "</LI>" + EOL); } htmlBody.append("</UL>" + 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_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_ENABLE) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_VIEW_CATEGORY, category) + EOL); for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + 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")) { for (int i=0; i < jobIDs.length; i++) { try { scheduler.enableJob(jobIDs[i]); infoMessage.append("Enabled job " + jobIDs[i] + ".<BR>" + EOL); } catch (SLAMDServerException sse) { infoMessage.append("Unable to enable job " + jobIDs[i] + ": " + sse + "<BR>" + EOL); } } handleViewJob(requestInfo, category, null, null); } else { infoMessage.append("No jobs were enabled.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); } } /** * Handles the work of exporting information about multiple jobs. * * @param requestInfo The state information for this request. * @param jobIDs The job IDs of the jobs to export. */ static void handleMassExport(RequestInfo requestInfo, String[] jobIDs) { logMessage(requestInfo, "In handleMassExport()"); // The user must have permission to export jobs to access this section. if (! requestInfo.mayExportJobData) { logMessage(requestInfo, "No mayViewJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "export 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; String category = request.getParameter(Constants.SERVLET_PARAM_VIEW_CATEGORY); // Make sure that at least one job ID was specified. If not, then print // an appropriate error message and go back to viewing the completed jobs. if ((jobIDs == null) || (jobIDs.length < 1)) { infoMessage.append("You must specify at least one job to export.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); return; } // Retrieve all of the jobs and see if they are all of the same type. If // so, then we'll be able to be pretty specific about the kinds of data // that can be exported. Otherwise, it will only be possible to choose // what gets exported in a more generic manner. ArrayList<ArrayList<Job>> jobTypeList = new ArrayList<ArrayList<Job>>(); ArrayList<String> jobIDList = new ArrayList<String>(); for (int i=0; i < jobIDs.length; i++) { Job job = null; try { job = configDB.getJob(jobIDs[i]); if (job == null) { infoMessage.append("Unable to retrieve job " + jobIDs[i] + " -- job not found.<BR>" + EOL); } else { // Make sure that the job has statistics available. if (! job.hasStats()) { infoMessage.append("Skipping job " + jobIDs[i] + " because it does not have any statistics " + "available.<BR>" + EOL); continue; } // Get the job type for this job and see if it is the same as any // of the other jobs that we have already seen. jobIDList.add(jobIDs[i]); boolean categorized = false; for (int j=0; j < jobTypeList.size(); j++) { ArrayList<Job> jobList = jobTypeList.get(j); Job job2 = jobList.get(0); if (job2.getJobClassName().equals(job.getJobClassName())) { jobList.add(job); categorized = true; break; } } if (! categorized) { ArrayList<Job> jobList = new ArrayList<Job>(); jobList.add(job); jobTypeList.add(jobList); } } } catch (Exception e) { infoMessage.append("Unable to retrieve job " + jobIDs[i] + " -- " + e + "<BR>" + EOL); } } // Make sure that at least one job was placed in the job list. if (jobTypeList.isEmpty()) { infoMessage.append("Unable to perform the requested comparison because " + "there was not at least one job meeting the " + "necessary criteria.<BR>" + EOL); handleViewJob(requestInfo, category, null, null); return; } jobIDs = new String[jobIDList.size()]; jobIDList.toArray(jobIDs); // Sort the job information based on the actual start times for the jobs. // Since there should not be that many jobs to compare, and since it is // likely that they will already be sorted anyway, then a selection sort // should be the fastest and simplest way to do it. for (int i=0; i < jobTypeList.size(); i++) { ArrayList<Job> jobList = jobTypeList.get(i); long[] startTimes = new long[jobList.size()]; Job[] jobs = new Job[jobList.size()]; for (int j=0; j < jobs.length; j++) { jobs[j] = jobList.get(j); startTimes[j] = jobs[j].getActualStartTime().getTime(); } for (int j=0; j < jobs.length; j++) { int slot = -1; long minStartTime = startTimes[j]; for (int k=j+1; k < jobs.length; k++) { if (startTimes[k] < minStartTime) { slot = k; minStartTime = startTimes[k]; } } if (slot > 0) { Job tempJob = jobs[slot]; long tempStartTime = startTimes[slot]; jobs[slot] = jobs[j]; startTimes[slot] = startTimes[j]; jobs[j] = tempJob; startTimes[j] = tempStartTime; } } jobList.clear(); for (int j=0; j < jobs.length; j++) { jobList.add(jobs[j]); } } // Determine whether the user has chosen the kinds of information to be // exported. String confirmedStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmedStr != null) && confirmedStr.equals(Constants.CONFIG_VALUE_TRUE)) { // Determine the kinds of information that will be included in the output. String value = request.getParameter(Constants.SERVLET_PARAM_EXPORT_JOB_ID); boolean includeJobID = (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))); value = request.getParameter(Constants.SERVLET_PARAM_INCLUDE_LABELS); boolean includeLabels = (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))); value = request.getParameter(Constants.SERVLET_PARAM_EXPORT_DESCRIPTION); boolean includeDescription = (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))); value = request.getParameter(Constants.SERVLET_PARAM_EXPORT_START_TIME); boolean includeStartTime = (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))); value = request.getParameter(Constants.SERVLET_PARAM_EXPORT_STOP_TIME); boolean includeStopTime = (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))); value = request.getParameter(Constants.SERVLET_PARAM_EXPORT_DURATION); boolean includeDuration = (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))); value = request.getParameter(Constants.SERVLET_PARAM_EXPORT_CLIENTS); boolean includeClients = (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))); value = request.getParameter(Constants.SERVLET_PARAM_EXPORT_THREADS); boolean includeThreads = (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))); value = request.getParameter(Constants.SERVLET_PARAM_EXPORT_INTERVAL); boolean includeInterval = (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))); value = request.getParameter(Constants.SERVLET_PARAM_EXPORT_PARAMETERS); boolean includeAllParams = (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))); value = request.getParameter(Constants.SERVLET_PARAM_EXPORT_STATISTICS); boolean includeAllStats = (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))); ArrayList<Parameter> includeParameters = new ArrayList<Parameter>(); ArrayList<StatTracker> includeStats = new ArrayList<StatTracker>(); if (jobTypeList.size() == 1) { ArrayList<Job> jobList = jobTypeList.get(0); Job job = jobList.get(0); Parameter[] stubs = job.getParameterStubs().getParameters(); for (int i=0; i < stubs.length; i++) { value = request.getParameter( Constants.SERVLET_PARAM_EXPORT_PARAM_PREFIX + stubs[i].getName()); if (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))) { includeParameters.add(stubs[i]); } } String[] trackerNames = job.getStatTrackerNames(); for (int i=0; i < trackerNames.length; i++) { value = request.getParameter(Constants.SERVLET_PARAM_EXPORT_STAT_PREFIX + trackerNames[i]); if (! ((value == null) || value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("off"))) { // There must be at least one job with this stat tracker in order to // export this information. for (int j=0; j < jobList.size(); j++) { StatTracker[] trackers = jobList.get(j).getStatTrackers(trackerNames[i]); if ((trackers != null) && (trackers.length > 0)) { includeStats.add(trackers[0]); break; } } } } } // Get the writer to use to send data to the client. PrintWriter writer = null; 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; } // Indicate that the output from this will not be HTML. requestInfo.generateHTML = false; requestInfo.response.setContentType("application/x-slamd-job-export"); requestInfo.response.addHeader("Content-Disposition", "filename=\"slamd_job_export_data.txt\""); // Iterate through all the different kinds of jobs to include in the // export. for (int i=0; i < jobTypeList.size(); i++) { // Get the job information as an array. ArrayList<Job> jobList = jobTypeList.get(i); Job[] jobs = new Job[jobList.size()]; jobList.toArray(jobs); // If there are multiple types of jobs to retrieve, then get the types // of parameters to include for this particular job type. if (includeAllParams && (jobTypeList.size() > 1)) { includeParameters.clear(); Parameter[] stubs = jobs[0].getParameterStubs().getParameters(); for (int j=0; j < stubs.length; j++) { if (! (stubs[j] instanceof PlaceholderParameter)) { includeParameters.add(stubs[j]); } } } // If there are multiple types of jobs to retrieve, then get the types // of statistics to include for this particular job type. if (includeAllStats && (jobTypeList.size() > 1)) { includeStats.clear(); String[] trackerNames = jobs[0].getStatTrackerNames(); for (int j=0; j < trackerNames.length; j++) { for (int k=0; k < jobs.length; k++) { StatTracker[] trackers = jobs[k].getStatTrackers(trackerNames[j]); if ((trackers != null) && (trackers.length > 0)) { includeStats.add(trackers[0]); break; } } } } // If labels are to be included in the export, then send them out. if (includeLabels) { writer.println(jobs[0].getJobName() + " Job Data"); if (includeJobID) { writer.print("Job ID\t"); } if (includeDescription) { writer.print("Description\t"); } if (includeStartTime) { writer.print("Start Time\t"); } if (includeStopTime) { writer.print("Stop Time\t"); } if (includeDuration) { writer.print("Duration\t"); } if (includeClients) { writer.print("Number of Clients\t"); } if (includeThreads) { writer.print("Threads per Client\t"); } if (includeInterval) { writer.print("Collection Interval\t"); } for (int j=0; j < includeParameters.size(); j++) { Parameter p = includeParameters.get(i); writer.print(p.getDisplayName() + '\t'); } for (int j=0; j < includeStats.size(); j++) { StatTracker tracker = includeStats.get(j); String[] trackerLabels = tracker.getSummaryLabels(); for (int k=0; k < trackerLabels.length; k++) { writer.print(trackerLabels[k] + '\t'); } } writer.println(); } // Write out the requested information for each job. for (int j=0; j < jobs.length; j++) { if (includeJobID) { writer.print(jobs[j].getJobID() + '\t'); } if (includeDescription) { writer.print(jobs[j].getJobDescription() + '\t'); } if (includeStartTime) { String formattedTime = displayDateFormat.format(jobs[j].getActualStartTime()); writer.print(formattedTime + '\t'); } if (includeStopTime) { String formattedTime = displayDateFormat.format(jobs[j].getActualStopTime()); writer.print(formattedTime + '\t'); } if (includeDuration) { writer.print(jobs[j].getActualDuration() + "\t"); } if (includeClients) { writer.print(jobs[j].getNumberOfClients() + "\t"); } if (includeThreads) { writer.print(jobs[j].getThreadsPerClient() + "\t"); } if (includeInterval) { writer.print(jobs[j].getCollectionInterval() + "\t"); } for (int k=0; k < includeParameters.size(); k++) { Parameter p = includeParameters.get(k); Parameter q = jobs[i].getParameterList().getParameter(p.getName()); if (q == null) { writer.print("\t"); } else { writer.print(q.getValueString() + '\t'); } } for (int k=0; k < includeStats.size(); k++) { StatTracker tracker = includeStats.get(k); StatTracker[] trackers = jobs[j].getStatTrackers(tracker.getDisplayName()); if ((trackers == null) || (trackers.length == 0)) { for (int l=0; l < tracker.getSummaryLabels().length; l++) { writer.print("\t"); } } else { try { StatTracker t = trackers[0].newInstance(); t.aggregate(trackers); String[] values = t.getSummaryData(); for (int l=0; l < values.length; l++) { writer.print(values[l] + '\t'); } } catch (Exception e) { for (int l=0; l < tracker.getSummaryLabels().length; l++) { writer.print("\t"); } } } } writer.println(); } writer.println(); } } else { if (jobTypeList.size() == 1) { ArrayList<Job> jobList = jobTypeList.get(0); Job job = jobList.get(0); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Export Multiple \"" + job.getJobName() + "\" Jobs</SPAN>" + EOL); } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Export Multiple SLAMD Jobs</SPAN>" + EOL); } htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Please select the information that should be included " + "in the job data export." + EOL); if (jobTypeList.size() > 1) { htmlBody.append("Note that because multiple job types were selected, " + "it is not possible to choose the individual " + "parameter and statistic types that can be exported." + EOL); htmlBody.append("Therefore, it is only possible to indicate whether " + "to include all or no parameter information, and all " + "or no statistical information." + EOL); } htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ACTION=\"" + servletBaseURI + "\" CLASS=\"" + Constants.STYLE_MAIN_FORM + "\">" + 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); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_CONFIRMED, Constants.CONFIG_VALUE_TRUE) + EOL); for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <B>Job Schedule Information to Export</B><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_JOB_ID + "\" CHECKED>Job ID<BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_DESCRIPTION + "\" CHECKED>Job Description<BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_START_TIME + "\">Job Start Time<BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_STOP_TIME + "\">Job Stop Time<BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_DURATION + "\">Job Duration<BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_CLIENTS + "\">Number of Clients<BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_THREADS + "\">Number of Threads per Client<BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_INTERVAL + "\">Statistics Collection Interval<BR>" + EOL); htmlBody.append(" <BR><BR>" + EOL); htmlBody.append(" <B>Job Parameter Information to Export</B><BR>" + EOL); if (jobTypeList.size() == 1) { ArrayList<Job> jobList = jobTypeList.get(0); Job job = jobList.get(0); Parameter[] stubs = job.getParameterStubs().getParameters(); for (int i=0; i < stubs.length; i++) { if (! (stubs[i] instanceof PlaceholderParameter)) { htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_PARAM_PREFIX + stubs[i].getName() + "\">" + stubs[i].getDisplayName() + "<BR>" + EOL); } } } else { htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_PARAMETERS + "\">Export all parameters<BR>" + EOL); } htmlBody.append(" <BR><BR>" + EOL); htmlBody.append(" <B>Statistical Information to Export</B><BR>" + EOL); if (jobTypeList.size() == 1) { ArrayList<Job> jobList = jobTypeList.get(0); Job job = jobList.get(0); String[] trackerNames = job.getStatTrackerNames(); for (int i=0; i < trackerNames.length; i++) { htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_STAT_PREFIX + trackerNames[i] + "\" CHECKED>" + trackerNames[i] + "<BR>" + EOL); } } else { htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_STATISTICS + "\" CHECKED>Export all statistics<BR>" + EOL); } htmlBody.append(" <BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_INCLUDE_LABELS + "\" CHECKED>Include Labels in Exported Data<BR>" + EOL); htmlBody.append(" <BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Export Data\"><BR>" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles the work of publishing or de-publishing one or more jobs for * display in restricted read-only mode. * * @param requestInfo The state information for this request. * @param displayInReadOnlyMode Indicates whether the specified jobs should * be published or de-published. */ static void handleMassPublish(RequestInfo requestInfo, boolean displayInReadOnlyMode) { logMessage(requestInfo, "In handleMassPublish()"); // The user must have permission to manage folders to access this section. if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "manage job folders."); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; StringBuilder infoMessage = requestInfo.infoMessage; // Get the job IDs of the jobs to publish or de-publish. String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("No action was taken because no jobs were selected." + "<BR>" + EOL); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); return; } // Perform the update and create an info message with the updated status. for (int i=0; i < jobIDs.length; i++) { try { Job job = configDB.getJob(jobIDs[i]); job.setDisplayInReadOnlyMode(displayInReadOnlyMode); configDB.writeJob(job); infoMessage.append("Successfully updated job " + jobIDs[i] + "<BR>" + EOL); } catch (Exception e) { infoMessage.append("Unable to update job " + jobIDs[i] + ": " + e.getMessage() + "<BR>" + EOL); } } handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } /** * Handles all processing required to create a new job folder. * * @param requestInfo The state information for this request. */ static void handleCreateFolder(RequestInfo requestInfo) { logMessage(requestInfo, "In handleCreateFolder()"); // The user must have permission to manage folders to access this section. if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "create a new folder."); 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; // Get the folder name. String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if (((folderName != null) && (folderName.length() == 0))) { folderName = null; } // Determine whether to publish this folder in restricted read-only mode. 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")); } String createString = "Create Folder"; String cancelString = "Cancel"; // See if the user has actually made a selection. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((folderName != null) && (confirmStr != null) && (confirmStr.equalsIgnoreCase(createString))) { // The user has confirmed that the new folder should be created. try { JobFolder folder = new JobFolder(folderName, displayInReadOnlyMode, false, null, null, null, null, null, null, null); configDB.writeFolder(folder); infoMessage.append("Successfully created job folder " + folderName + ".<BR>" + EOL); } catch (DatabaseException de) { requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, de.getMessage()); infoMessage.append("ERROR: Unable to create job folder " + folderName + " -- " + de + "<BR>" + EOL); } handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } else if ((confirmStr != null) && confirmStr.equalsIgnoreCase(cancelString)) { // The folder creation has been cancelled. infoMessage.append("No job folder was created.<BR>" + EOL); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } else { // Display a form that allows the user to create a new job folder. htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Create a New Job Folder</SPAN>" + 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_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_CREATE_FOLDER) + 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><SPAN CLASS=\"" + Constants.STYLE_FORM_CAPTION + "\">New Folder Name</SPAN></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_FOLDER + "\" SIZE=\"40\"></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(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"" + createString + "\">" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"" + cancelString + "\">" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles all processing required to remove a job folder. * * @param requestInfo The state information for this request. */ static void handleDeleteFolder(RequestInfo requestInfo) { logMessage(requestInfo, "In handleDeleteFolder()"); // The user must have permission to schedule jobs to access this section. if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "delete job folders."); 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; // Get the folder name. String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if (((folderName != null) && (folderName.length() == 0))) { folderName = null; } else if ((folderName != null) && folderName.equals(Constants.FOLDER_NAME_UNCLASSIFIED)) { infoMessage.append("You cannot delete the " + Constants.FOLDER_NAME_UNCLASSIFIED + " job folder.<BR>" + EOL); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, Constants.FOLDER_NAME_UNCLASSIFIED, null); return; } String deleteString = "Delete Folder"; String cancelString = "Cancel"; // See if the user has actually made a selection. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((folderName != null) && (confirmStr != null) && (confirmStr.equalsIgnoreCase(deleteString))) { // The user has confirmed that the new folder should be created. // Determine whether to delete the folder contents as well. boolean deleteContents = false; String deleteContentsStr = request.getParameter(Constants.SERVLET_PARAM_DELETE_FOLDER_CONTENTS); if (deleteContentsStr != null) { deleteContents = (deleteContentsStr.equalsIgnoreCase("true") || deleteContentsStr.equalsIgnoreCase("yes") || deleteContentsStr.equalsIgnoreCase("on") || deleteContentsStr.equalsIgnoreCase("1")); } try { configDB.removeFolder(folderName, deleteContents); infoMessage.append("Successfully deleted job folder " + folderName + ".<BR>" + EOL); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, Constants.FOLDER_NAME_UNCLASSIFIED, null); } catch (DatabaseException de) { String message = "Unable to delete job folder " + folderName + " -- " + de.getMessage(); infoMessage.append("ERROR: " + message + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, message); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } } else if ((folderName != null) && (confirmStr != null) && (confirmStr.equalsIgnoreCase(cancelString))) { // The folder creation has been cancelled. infoMessage.append("No job folder was deleted.<BR>" + EOL); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } else { // Get the list of available job folders. JobFolder[] folders = null; try { folders = configDB.getFolders(); } catch (DatabaseException de) { infoMessage.append("ERROR: Could not retrieve the list of job " + "folders -- " + de + "<BR>" + EOL); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); return; } if ((folders == null) || (folders.length <= 1)) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Delete a Job Folder</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("No custom job folders have been defined in the " + "SLAMD server." + EOL); return; } // Display a form that allows the user to delete a job folder. htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Delete a Job Folder</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Please choose the job folder to delete." + EOL); htmlBody.append("Note that only empty folders may be removed." + EOL); htmlBody.append("To remove a folder that is not empty, first delete " + "or move any jobs contained in that folder." + 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_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_DELETE_FOLDER) + 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>Folder to Delete</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 (folders[i].getFolderName().equals( Constants.FOLDER_NAME_UNCLASSIFIED)) { continue; } htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + "\">" + folders[i].getFolderName() + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Delete Folder Contents</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_DELETE_FOLDER_CONTENTS + "\"></TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"" + deleteString + "\">" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"" + cancelString + "\">" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles all processing required to move one or more jobs to a specified * job folder. * * @param requestInfo The state information for this request. */ static void handleMoveJobs(RequestInfo requestInfo) { logMessage(requestInfo, "In handleMoveJobs()"); // The user must have permission to schedule jobs to access this section. if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "move 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; // Get the job IDs of the jobs to move. If there were none, then display // an error message. String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("ERROR: No jobs selected to move.<BR>" + EOL); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); return; } // Get the name of the folder into which the jobs are to be moved. String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if ((folderName != null) && (folderName.length() == 0)) { folderName = null; } String moveStr = "Move Jobs"; String cancelStr = "Cancel"; String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); // See if the user has confirmed that the job information should be moved. if ((folderName != null) && (confirmStr != null) && (confirmStr.equalsIgnoreCase(moveStr))) { // The user wants to move the jobs, so do it. for (int i=0; i < jobIDs.length; i++) { try { configDB.moveJob(jobIDs[i], folderName); infoMessage.append("Successfully moved job " + jobIDs[i] + "<BR>" + EOL); } catch (DatabaseException de) { infoMessage.append("ERROR while moving job " + jobIDs[i] + ": " + de + "<BR>" + EOL); } } handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } else if ((folderName != null) && (confirmStr != null) && (confirmStr.equalsIgnoreCase(cancelStr))) { infoMessage.append("The selected jobs were not moved.<BR>" + EOL); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); } else { // Get the list of available job folders. JobFolder[] folders = null; try { folders = configDB.getFolders(); } catch (DatabaseException de) { infoMessage.append("ERROR: Could not retrieve the list of job " + "folders -- " + de + "<BR>" + EOL); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); return; } if (folders.length == 0) { infoMessage.append("ERROR: There are no custom folders defined.<BR>" + EOL); handleViewJob(requestInfo, Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED, null, null); return; } // Display a form that allows the user to choose the new folder. htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Move Jobs</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Please specify the new folder for the following jobs." + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + EOL); for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" <LI>" + jobIDs[i] + "</LI>" + EOL); } htmlBody.append("</UL>" + EOL); htmlBody.append("<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_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_MOVE) + EOL); for (int i=0; i < jobIDs.length; i++) { htmlBody.append(' ' + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + 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><SPAN CLASS=\"" + Constants.STYLE_FORM_CAPTION + "\">New Folder Name</SPAN></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++) { htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + "\">" + folders[i].getFolderName() + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"" + moveStr + "\">" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"" + cancelStr + "\">" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" </TABLE>" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles the work of adding a set of jobs to a virtual job folder. * * @param requestInfo The state information for this request. */ static void handleAddToVirtualFolder(RequestInfo requestInfo) { logMessage(requestInfo, "In handleAddToVirtualFolder()"); // The user must have permission to schedule jobs to do anything in this // section. if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayScheduleJob permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "modify virtual job folders"); 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 at least one job ID was provided. If not, then display // an error. String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_JOB_ID); if ((jobIDs == null) || (jobIDs.length == 0)) { infoMessage.append("ERROR: No jobs specified<BR>" + EOL); htmlBody.append("You must specify at least one job to be added to a " + "virtual folder." + EOL); return; } // See if a folder name was provided. If so, then try to add the specified // jobs to the folder. If not, then prompt the user for a folder name. String folderName = request.getParameter(Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER); if ((folderName != null) && folderName.equals(Constants.FOLDER_NAME_CREATE_NEW_FOLDER)) { folderName = request.getParameter(Constants.SERVLET_PARAM_NEW_FOLDER_NAME); } if ((folderName != null) && (folderName.length() > 0)) { // Add the specified list of job IDs to the virtual folder, or create a // new folder if necessary. try { boolean created = false; JobFolder folder = configDB.getVirtualFolder(folderName); if (folder == null) { folder = new JobFolder(folderName, false, true, null, null, null, jobIDs, null, null, null); created = true; } else { for (int i=0; i < jobIDs.length; i++) { folder.addJobID(jobIDs[i]); } } configDB.writeVirtualFolder(folder); if (created) { infoMessage.append("Successfully created virtual job folder \"" + folderName + "\"<BR>" + EOL); } else { infoMessage.append("Successfully updated virtual job folder \"" + folderName + "\"<BR>" + EOL); } } catch (Exception e) { infoMessage.append("Unable to update virtual job folder \"" + folderName + "\" -- " + e.getMessage() + "<BR>" + EOL); } handleViewVirtualFolder(requestInfo, folderName); return; } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Add Jobs to a Virtual Folder</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); // Get the list of virtual job folders that are defined in the SLAMD // server. JobFolder[] folders; try { folders = configDB.getVirtualFolders(); } catch (DatabaseException de) { infoMessage.append("ERROR: Unable to retrieve the list of virtual " + "job folders -- " + de.getMessage() + "<BR>" + EOL); htmlBody.append("An error occurred while attempting to retrieve the " + "list of virtual job folders that have been defined " + "in the SLAMD server." + EOL); return; } htmlBody.append("Choose the virtual folder to which the jobs are to be " + "added, or choose to create a new virtual job folder" + 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_MASS_OP) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_ADD_TO_VIRTUAL_FOLDER) + EOL); for (int i=0; i < jobIDs.length; i++) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_ID, jobIDs[i]) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } if ((folders != null) && (folders.length > 0)) { htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER + "\">" + EOL); htmlBody.append(" <OPTION VALUE=\"" + Constants.FOLDER_NAME_CREATE_NEW_FOLDER + "\">" + Constants.FOLDER_NAME_CREATE_NEW_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>" + EOL); } else { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_VIRTUAL_JOB_FOLDER, Constants.FOLDER_NAME_CREATE_NEW_FOLDER) + EOL); htmlBody.append(" No virtual job folders have been defined in " + "the SLAMD server.<BR>" + EOL); } htmlBody.append(" New Virtual Folder Name: " + EOL); htmlBody.append(" <INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_NEW_FOLDER_NAME + "\" SIZE=\"40\">" + EOL); htmlBody.append(" <BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Add Jobs\">" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles the work of performing some operation on multiple optimizing jobs * at the same time. * * @param requestInfo The state information for this request. */ static void handleMassOptimizing(RequestInfo requestInfo) { HttpServletRequest request = requestInfo.request; // Get the job IDs of the optimizing jobs on which to perform the operation. String[] jobIDs = request.getParameterValues(Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID); // Determine which mass operation the user wishes to perform. String opString = request.getParameter(Constants.SERVLET_PARAM_SUBMIT); if (opString == null) { return; } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_SELECT_ALL) || opString.equalsIgnoreCase(Constants.SUBMIT_STRING_DESELECT_ALL)) { handleViewOptimizing(requestInfo, true); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_DELETE)) { handleMassOptimizingDelete(requestInfo, jobIDs); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_MOVE)) { handleMassOptimizingMove(requestInfo, jobIDs); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_PUBLISH_JOBS)) { handleMassOptimizingPublish(requestInfo, jobIDs); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_DEPUBLISH_JOBS)) { handleMassOptimizingDepublish(requestInfo, jobIDs); } else if (opString.equalsIgnoreCase(Constants.SUBMIT_STRING_GENERATE_REPORT)) { handleGenerateReport(requestInfo); } } /** * Handles the work of deleting multiple optimizing jobs at the same time. * * @param requestInfo The state information for this request. * @param optimizingJobIDs The job IDs of the optimizing jobs to be * deleted. */ static void handleMassOptimizingDelete(RequestInfo requestInfo, String[] optimizingJobIDs) { logMessage(requestInfo, "In handleMassOptimizingDelete()"); // The user must have permission to delete jobs to access this section. 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 variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder infoMessage = requestInfo.infoMessage; StringBuilder htmlBody = requestInfo.htmlBody; // Make sure that at least one job ID was specified. If not, then print an // error message and view the appropriate set of jobs. if ((optimizingJobIDs == null) || (optimizingJobIDs.length == 0)) { infoMessage.append("No optimizing jobs specified to delete.<BR>" + EOL); handleViewOptimizing(requestInfo, true); return; } // See if the user has provided confirmation. If so, then delete the jobs // or don't based on the results of the confirmation. If no confirmation // has been provided, then request it. 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 + "\">Delete Selected Optimizing Jobs</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure that you want to delete the selected " + "optimizing jobs?" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + EOL); for (int i=0; i < optimizingJobIDs.length; i++) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING, Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobIDs[i], optimizingJobIDs[i]); htmlBody.append(" <LI>" + link + "</LI>" + EOL); } htmlBody.append("</UL>" + 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_MASS_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_DELETE) + EOL); String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); if (folderName != null) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_FOLDER, folderName) + EOL); } for (int i=0; i < optimizingJobIDs.length; i++) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobIDs[i]) + 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 the optimizing jobs" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append(" <TABLE BORDER=\"0\" CELLPADDING=\"5\">" + 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")) { for (int i=0; i < optimizingJobIDs.length; i++) { 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(optimizingJobIDs[i]); if (optimizingJob == null) { infoMessage.append("ERROR: Unable to retrieve optimizing job " + optimizingJobIDs[i] + "<BR>" + EOL); handleViewOptimizing(requestInfo, true); return; } Job[] iterations = optimizingJob.getAssociatedJobs(); if ((iterations != null) && (iterations.length > 0)) { for (int j=0; j < iterations.length; j++) { try { configDB.removeJob(iterations[j].getJobID()); } catch (Exception e) { infoMessage.append("Unable to remove optimizing job " + "iteration " + iterations[j].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(optimizingJobIDs[i]); infoMessage.append("Deleted optimizing job " + optimizingJobIDs[i] + ".<BR>" + EOL); } catch (Exception e) { infoMessage.append("Unable to delete optimizing job " + optimizingJobIDs[i] + ": " + e + "<BR>" + EOL); } } handleViewOptimizing(requestInfo, true); } else { infoMessage.append("No optimizing jobs were deleted.<BR>" + EOL); handleViewOptimizing(requestInfo, true); } } /** * Handles the work of moving multiple optimizing jobs. * * @param requestInfo The state information for this request. * @param optimizingJobIDs The job IDs of the optimizing jobs to be moved. */ static void handleMassOptimizingMove(RequestInfo requestInfo, String[] optimizingJobIDs) { logMessage(requestInfo, "In handleMassOptimizingMove()"); // The user must have permission to manage folders to access this section. 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 variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder infoMessage = requestInfo.infoMessage; StringBuilder htmlBody = requestInfo.htmlBody; // Make sure that at least one job ID was specified. If not, then print an // error message and view the appropriate set of jobs. if ((optimizingJobIDs == null) || (optimizingJobIDs.length == 0)) { infoMessage.append("No optimizing jobs specified to move.<BR>" + EOL); handleViewOptimizing(requestInfo, true); return; } // See if the user has provided confirmation. If so, then delete the jobs // or don't based on the results of the confirmation. If no confirmation // has been provided, then request it. String confirmStr = request.getParameter(Constants.SERVLET_PARAM_CONFIRMED); if ((confirmStr == null) || ((! confirmStr.equalsIgnoreCase("Move Jobs")) && (! confirmStr.equalsIgnoreCase("Cancel")))) { // Get the set of job folders defined in the configuration directory. If // there are none, then return an error. JobFolder[] folders = null; String failReason = "No job folders have been created."; try { folders = configDB.getFolders(); } catch (DatabaseException de) { failReason = de.getMessage(); } if ((folders == null) || (folders.length == 0)) { infoMessage.append("Unable to move the selected optimizing jobs: " + failReason + "<BR>" + EOL); handleViewOptimizing(requestInfo, true); return; } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Move Selected Optimizing Jobs</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Please specify the destination folder for the " + "optimizing jobs" + EOL); htmlBody.append("<BR>" + EOL); htmlBody.append("<UL>" + EOL); for (int i=0; i < optimizingJobIDs.length; i++) { String link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING, Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobIDs[i], optimizingJobIDs[i]); htmlBody.append(" <LI>" + link + "</LI>" + EOL); } htmlBody.append("</UL>" + 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_MASS_OPTIMIZING) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_SUBMIT, Constants.SUBMIT_STRING_MOVE) + EOL); for (int i=0; i < optimizingJobIDs.length; i++) { htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID, optimizingJobIDs[i]) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\" CELLPADDING=\"5\">" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>Destination 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++) { htmlBody.append(" <OPTION VALUE=\"" + folders[i].getFolderName() + "\">" + folders[i].getFolderName() + EOL); } htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_OPTIMIZING_JOB_INCLUDE_ITERATIONS + "\" CHECKED></TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>Move all iterations of the optimizing " + "jobs</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD><INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_CONFIRMED + "\" VALUE=\"Move Jobs\"></TD>" + EOL); htmlBody.append(" <TD> </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); } else if (confirmStr.equalsIgnoreCase("Move Jobs")) { String folderName = request.getParameter(Constants.SERVLET_PARAM_JOB_FOLDER); for (int i=0; i < optimizingJobIDs.length; i++) { 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(optimizingJobIDs[i]); if (optimizingJob == null) { infoMessage.append("ERROR: Unable to retrieve optimizing job " + optimizingJobIDs[i] + "<BR>" + EOL); handleViewOptimizing(requestInfo, true); return; } Job[] iterations = optimizingJob.getAssociatedJobs(); if ((iterations != null) && (iterations.length > 0)) { for (int j=0; j < iterations.length; j++) { try { configDB.moveJob(iterations[j].getJobID(), folderName); } catch (Exception e) { infoMessage.append("Unable to move optimizing job " + "iteration " + iterations[j].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(optimizingJobIDs[i], folderName); infoMessage.append("Moved optimizing job " + optimizingJobIDs[i] + ".<BR>" + EOL); } catch (Exception e) { infoMessage.append("Unable to move optimizing job " + optimizingJobIDs[i] + ": " + e + "<BR>" + EOL); } } handleViewOptimizing(requestInfo, true); } else { infoMessage.append("No optimizing jobs were moved.<BR>" + EOL); handleViewOptimizing(requestInfo, true); } } /** * Handles the work of publishing information about multiple optimizing jobs. * * @param requestInfo The state information for this request. * @param optimizingJobIDs The job IDs of the optimizing jobs to be * published. */ static void handleMassOptimizingPublish(RequestInfo requestInfo, String[] optimizingJobIDs) { logMessage(requestInfo, "In handleMassOptimizingPublish()"); // The user must have permission to manage folders to access this section. if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "publish job information."); return; } // Get the important state variables for this request. StringBuilder infoMessage = requestInfo.infoMessage; // Make sure that at least one job ID was specified. If not, then print an // error message and view the appropriate set of jobs. if ((optimizingJobIDs == null) || (optimizingJobIDs.length == 0)) { infoMessage.append("No optimizing jobs specified to publish.<BR>" + EOL); handleViewOptimizing(requestInfo, true); return; } // Iterate through the jobs and mark each for publication. for (int i=0; i < optimizingJobIDs.length; i++) { try { OptimizingJob optimizingJob = getOptimizingJob(optimizingJobIDs[i]); optimizingJob.setDisplayInReadOnlyMode(true); configDB.writeOptimizingJob(optimizingJob); infoMessage.append("Marked optimizing job " + optimizingJobIDs[i] + " for publication.<BR>" + EOL); } catch (Exception e) { infoMessage.append("Unable to publish optimizing job " + optimizingJobIDs[i] + ": " + e + "<BR>" + EOL); } } handleViewOptimizing(requestInfo, true); } /** * Handles the work of de-publishing information about multiple optimizing * jobs. * * @param requestInfo The state information for this request. * @param optimizingJobIDs The job IDs of the optimizing jobs to be * de-published. */ static void handleMassOptimizingDepublish(RequestInfo requestInfo, String[] optimizingJobIDs) { logMessage(requestInfo, "In handleMassOptimizingPublish()"); // The user must have permission to manage folders to access this section. if (! requestInfo.mayManageFolders) { logMessage(requestInfo, "No mayManageFolders permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "de-publish job information."); return; } // Get the important state variables for this request. StringBuilder infoMessage = requestInfo.infoMessage; // Make sure that at least one job ID was specified. If not, then print an // error message and view the appropriate set of jobs. if ((optimizingJobIDs == null) || (optimizingJobIDs.length == 0)) { infoMessage.append("No optimizing jobs specified to de-publish.<BR>" + EOL); handleViewOptimizing(requestInfo, true); return; } // Iterate through the jobs and mark each for de-publication. for (int i=0; i < optimizingJobIDs.length; i++) { try { OptimizingJob optimizingJob = getOptimizingJob(optimizingJobIDs[i]); optimizingJob.setDisplayInReadOnlyMode(false); configDB.writeOptimizingJob(optimizingJob); infoMessage.append("Marked optimizing job " + optimizingJobIDs[i] + " for de-publication.<BR>" + EOL); } catch (Exception e) { infoMessage.append("Unable to de-publish optimizing job " + optimizingJobIDs[i] + ": " + e + "<BR>" + EOL); } } handleViewOptimizing(requestInfo, true); } /** * Handles all processing required to import data into the SLAMD server. * * @param requestInfo The state information for this request. */ static void handleDataImport(RequestInfo requestInfo) { logMessage(requestInfo, "In handleDataImport()"); // The user must have export job data permission to see anything here. if (! requestInfo.mayExportJobData) { logMessage(requestInfo, "No mayExportJobData permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "import job data"); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; HttpServletResponse response = requestInfo.response; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // See if the user has told us where the import file is. If so, then // process it. If not, then ask them for the location. String importFile = request.getParameter(Constants.SERVLET_PARAM_DATA_IMPORT_FILE); if ((importFile == null) || (importFile.length() == 0)) { // We don't know where the import file is. Ask the user. htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Import Job Data</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Please provide the absolute path (on the SLAMD server " + "system) to the location of the file containing the " + "data to import." + 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_IMPORT_JOB_DATA) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" Import File: " + 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=\"Import Data\">" + EOL); htmlBody.append("</FORM>" + EOL); } else { // We have the import file, so we can process it. However, we have to do // some trickery here in order to give the user feedback in real-time so // they can see that the import actually is going on. Therefore, we will // generate all the HTML ourselves, including the header, the sidebar, and // the copyright notice. PrintWriter writer = null; try { writer = response.getWriter(); } catch (IOException ioe) { infoMessage.append("Unable to obtain output writer -- " + ioe + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Import Failed</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("An error occurred that prevented the import from " + "being processed successfully."); return; } requestInfo.generateHTML = false; response.setContentType("text/html"); // Generate the HTML header and print it out. Then replace the HTML // body with an empty string buffer. writer.println(generateHTMLHeader(requestInfo)); writer.flush(); // Hand the import off to the config handler to process it. FileInputStream inputStream = null; try { writer.println("<!-- START IMPORT -->"); inputStream = new FileInputStream(importFile); configDB.importFolderData(inputStream, writer, true); writer.println("<!-- END IMPORT -->"); } catch (Exception e) { writer.println("<!-- END IMPORT -->"); writer.println("<!-- IMPORT ERROR: " + JobClass.stackTraceToString(e) + " -->"); writer.println("Unexpected error processing import file: " + JobClass.stackTraceToString(e)); writer.flush(); try { inputStream.close(); } catch (Exception e2) {} } // Generate the copyright notice and print it out. writer.println(generateHTMLFooter(requestInfo)); writer.flush(); } } /** * Handles all processing required to export data from the SLAMD server. * * @param requestInfo The state information for this request. */ static void handleDataExport(RequestInfo requestInfo) { logMessage(requestInfo, "In handleDataExport()"); // The user must have export job data permission to see anything here. if (! requestInfo.mayExportJobData) { logMessage(requestInfo, "No mayExportJobData permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "export job data"); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; HttpServletResponse response = requestInfo.response; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // See if the user has selected which information to export. String submitStr = request.getParameter(Constants.SERVLET_PARAM_SUBMIT); if ((submitStr != null) && submitStr.equals(Constants.SUBMIT_STRING_EXPORT)) { // The user wants to actually export the data. Figure out what that // includes and do the export. boolean exportAll = false; String exportChoice = request.getParameter(Constants.SERVLET_PARAM_EXPORT_CHOICE); if ((exportChoice != null) && exportChoice.equals(Constants.EXPORT_CHOICE_ALL)) { exportAll = true; } ArrayList<String> realList = new ArrayList<String>(); ArrayList<String> virtualList = new ArrayList<String>(); ArrayList<String> jobGroupList = new ArrayList<String>(); if (! exportAll) { String[] realArray = request.getParameterValues( Constants.SERVLET_PARAM_EXPORT_REAL_FOLDER); for (int i=0; ((realArray != null) && (i < realArray.length)); i++) { realList.add(realArray[i]); } String[] virtualArray = request.getParameterValues( Constants.SERVLET_PARAM_EXPORT_VIRTUAL_FOLDER); for (int i=0; ((virtualArray != null) && (i < virtualArray.length)); i++) { virtualList.add(virtualArray[i]); } String[] jobGroupArray = request.getParameterValues( Constants.SERVLET_PARAM_EXPORT_JOB_GROUP); for (int i=0; ((jobGroupArray != null) && (i < jobGroupArray.length)); i++) { jobGroupList.add(jobGroupArray[i]); } } else { try { JobFolder[] realFolders = configDB.getFolders(); JobFolder[] virtualFolders = configDB.getVirtualFolders(); JobGroup[] jobGroups = configDB.getSummaryJobGroups(); for (int i=0; i < realFolders.length; i++) { realList.add(realFolders[i].getFolderName()); } for (int i=0; i < virtualFolders.length; i++) { virtualList.add(virtualFolders[i].getFolderName()); } for (int i=0; i < jobGroups.length; i++) { jobGroupList.add(jobGroups[i].getName()); } } catch (DatabaseException de) { infoMessage.append("Unable to retrieve the list of available " + "folders -- " + de + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Export Failed</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("An error occurred that prevented the export from " + "being processed successfully."); return; } } OutputStream outputStream; try { outputStream = response.getOutputStream(); } catch (IOException ioe) { infoMessage.append("Unable to obtain output writer -- " + ioe + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Export Failed</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("An error occurred that prevented the export from " + "being processed successfully."); return; } // From this point on, we are committed to actually generating the output // file. If an error occurs, then there's not much that can be done // about it. We'll log it to the SLAMD log but we don't really get // much requestInfo.generateHTML = false; requestInfo.response.setContentType("application/x-slamd-data-export"); requestInfo.response.addHeader("Content-Disposition", "filename=\"slamd_data_export_data." + dateFormat.format(new Date()) + '"'); String[] realFolderNames = new String[realList.size()]; realList.toArray(realFolderNames); String[] virtualFolderNames = new String[virtualList.size()]; virtualList.toArray(virtualFolderNames); String[] jobGroupNames = new String[jobGroupList.size()]; jobGroupList.toArray(jobGroupNames); try { configDB.exportFolderData(realFolderNames, virtualFolderNames, jobGroupNames, outputStream); } catch (Exception e) { slamdServer.logMessage(Constants.LOG_LEVEL_ANY, "Export of SLAMD server data failed: " + e); slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(e)); } } else if ((submitStr != null) && submitStr.equals(Constants.SUBMIT_STRING_CANCEL)) { // The user cancelled the export. infoMessage.append("Job data export cancelled<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Export Cancelled</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("The job data export was cancelled."); } else { // The user has not yet specified what to export. Show them a form to // allow them to choose what they want included. htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Export Job Data</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Choose which information you wish to export"); 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_EXPORT_JOB_DATA) + EOL); if (requestInfo.debugHTML) { htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_EXPORT_CHOICE + "\">" + EOL); htmlBody.append(" <OPTION VALUE=\"" + Constants.EXPORT_CHOICE_ALL + "\">" + Constants.EXPORT_CHOICE_ALL + EOL); htmlBody.append(" <OPTION VALUE=\"" + Constants.EXPORT_CHOICE_SELECTED + "\">" + Constants.EXPORT_CHOICE_SELECTED + EOL); htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" <BR><BR>" + EOL); try { JobFolder[] realFolders = configDB.getFolders(); for (int i=0; i < realFolders.length; i++) { htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_REAL_FOLDER + "\" VALUE=\"" + realFolders[i].getFolderName() + "\">Real Job Folder \"" + realFolders[i].getFolderName() + "\"<BR>" + EOL); } } catch (DatabaseException de) { infoMessage.append("ERROR: Unable to retrieve the list of defined " + "real job folders -- " + de + "<BR>" + EOL); } try { JobFolder[] virtualFolders = configDB.getVirtualFolders(); for (int i=0; i < virtualFolders.length; i++) { htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_VIRTUAL_FOLDER + "\" VALUE=\"" + virtualFolders[i].getFolderName() + "\">Virtual Job Folder \"" + virtualFolders[i].getFolderName() + "\"<BR>" + EOL); } } catch (DatabaseException de) { infoMessage.append("ERROR: Unable to retrieve the list of defined " + "virtual job folders -- " + de + "<BR>" + EOL); } try { JobGroup[] jobGroups = configDB.getSummaryJobGroups(); for (int i=0; i < jobGroups.length; i++) { htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_EXPORT_JOB_GROUP + "\" VALUE=\"" + jobGroups[i].getName() + "\">Job Group \"" + jobGroups[i].getName() + "\"<BR>" + EOL); } } catch (DatabaseException de) { infoMessage.append("ERROR: Unable to retrieve the list of defined " + "job groups -- " + de + "<BR>" + EOL); } htmlBody.append(" <BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_EXPORT + "\">" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" NAME=\"" + Constants.SERVLET_PARAM_SUBMIT + "\" VALUE=\"" + Constants.SUBMIT_STRING_CANCEL + "\">" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles all processing require to migrate job data from a SLAMD 1.x-style * configuration directory into the new configuration database. * * @param requestInfo The state information for this request. */ static void handleMigrateData(RequestInfo requestInfo) { logMessage(requestInfo, "In handleMigrateData()"); // The user must have export permission to see anything here. if (! requestInfo.mayExportJobData) { logMessage(requestInfo, "No mayExportJobData permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "migrate job data."); } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; HttpServletResponse response = requestInfo.response; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; // Create parameters that may be used to specify information about the // directory server from which to migrate the data. BooleanParameter useSSLParameter = new BooleanParameter("use_ssl", "Use SSL", "Indicates whether to use SSL to communicate " + "with the directory server.", false); IntegerParameter portParameter = new IntegerParameter("ldap_port", "Directory Server Port", "The port of the directory server containing " + "the data to be migrated.", true, 389, true, 1, true, 65535); PasswordParameter bindPWParameter = new PasswordParameter("bind_pw", "Bind Password", "The password to use to bind to the directory " + "server.", true, ""); StringParameter addressParameter = new StringParameter("ldap_host", "Directory Server Address", "The address of the directory server containing " + "the data to be migrated.", true, ""); StringParameter baseDNParameter = new StringParameter("base_dn", "Configuration Base DN", "The DN of the entry that serves as the base " + "for the SLAMD configuration data in the " + "directory server.", true, ""); StringParameter bindDNParameter = new StringParameter("bind_dn", "Bind DN", "The DN to use to bind to the directory server.", true, ""); Parameter[] dsParams = new Parameter[] { addressParameter, portParameter, useSSLParameter, bindDNParameter, bindPWParameter, baseDNParameter }; // See if we have an adequate configuration for the directory server. boolean validDSConfig = true; String submitStr = request.getParameter(Constants.SERVLET_PARAM_SERVER_INFO_SUBMITTED); if ((submitStr == null) || (submitStr.length() == 0)) { validDSConfig = false; } else { for (int i=0; i < dsParams.length; i++) { try { dsParams[i].htmlInputFormToValue(request); } catch (Exception e) { infoMessage.append("Invalid value for " + dsParams[i].getDisplayName() + ": " + e.getMessage() + "<BR>" + EOL); validDSConfig = false; } } } // If we think that a valid directory configuration was provided, then try // to use it to get a list of all the folders in the directory server. DSMigrator migrator = null; String[] folderNames = null; if (validDSConfig) { try { migrator = new DSMigrator(slamdServer, addressParameter.getStringValue(), portParameter.getIntValue(), useSSLParameter.getBooleanValue(), bindDNParameter.getStringValue(), bindPWParameter.getStringValue(), baseDNParameter.getStringValue()); folderNames = migrator.getFolderNames(); } catch (LDAPException le) { infoMessage.append("Unable to obtain a list of job folders from the " + "configuration directory using the provided " + "settings: LDAP Result code " + le.getLDAPResultCode() + " (" + le + ")<BR>" + EOL); validDSConfig = false; } catch (Exception e) { infoMessage.append("Unable to obtain a list of job folders from the " + "configuration directory using the provided " + "settings: " + e.getMessage() + "<BR>" + EOL); validDSConfig = false; } } // If we don't have a valid directory configuration, then prompt the user to // provide one. if (! validDSConfig) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Migrate Data from Configuration Directory</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Please provide the following information about the " + "SLAMD 1.x configuration directory containing the " + "data to migrate to the current configuration database:" + 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_MIGRATE) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_SERVER_INFO_SUBMITTED, "1") + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" <TABLE BORDER=\"0\">" + EOL); for (int i=0; i < dsParams.length; i++) { String star; if (dsParams[i].isRequired()) { star = "<SPAN CLASS=\"" + Constants.STYLE_WARNING_TEXT + "\">*</SPAN>"; } else { star = ""; } htmlBody.append(" <TR>" + EOL); htmlBody.append(" <TD>" + dsParams[i].getDisplayName() + star + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + dsParams[i].getHTMLInputForm( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append(" </TABLE>" + EOL); htmlBody.append(" <BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Next >\">" + EOL); htmlBody.append("</FORM>" + EOL); return; } // Check to see if the user has specified which folders to migrate. If so, // then try to perform the migration. String migrateFoldersStr = request.getParameter(Constants.SERVLET_PARAM_MIGRATE_FOLDERS); if ((migrateFoldersStr != null) && (migrateFoldersStr.length() > 0)) { String[] migrateFolders; if (migrateFoldersStr.equals(Constants.MIGRATE_FOLDERS_ALL)) { migrateFolders = folderNames; } else if (migrateFoldersStr.equals(Constants.MIGRATE_FOLDERS_SELECTED)) { migrateFolders = request.getParameterValues(Constants.SERVLET_PARAM_JOB_FOLDER); } else { migrateFolders = new String[0]; } if ((migrateFolders != null) && (migrateFolders.length > 0)) { // At this point, we're going to commit to the migration. In order to // be more interactive, we'll use a print writer to send data directly // to the browser rather than batching it all up and sending it as one // blob. requestInfo.generateHTML = false; PrintWriter writer = null; try { writer = response.getWriter(); } catch (Exception e) {} writer.println(generateHTMLHeader(requestInfo)); writer.println("<!-- START INFO MESSAGE -->" + EOL); writer.println(generateWarning(requestInfo.infoMessage.toString())); writer.println("<!-- END INFO MESSAGE -->" + EOL + EOL); writer.println("<!-- START MAIN BODY -->" + EOL); writer.println("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Migrate Data from Configuration Directory</SPAN>"); writer.println("<BR><BR>" + EOL); writer.println("Beginning data migration from directory server " + addressParameter.getStringValue() + ':' + portParameter.getIntValue() + '.'); writer.println("This may take some time to complete."); writer.println("<BR><BR"); boolean completeSuccess = true; for (int i=0; i < migrateFolders.length; i++) { writer.println("<B><FONT SIZE=\"+1\">Beginning Migration for " + "Folder " + migrateFolders[i] + "</FONT></B>"); writer.println("<BR>"); writer.flush(); writer.println("<PRE>"); boolean successful = migrator.migrateJobFolder(migrateFolders[i], writer); if (! successful) { completeSuccess = false; } writer.println("</PRE>"); writer.println("All processing complete for folder " + migrateFolders[i] + '.'); if (! successful) { writer.println("<BR>"); writer.println("<SPAN CLASS=\"" + Constants.STYLE_WARNING_TEXT + "\">One or more errors occurred while processing " + "this folder</SPAN>"); } writer.println("<BR><BR>"); writer.flush(); } writer.println("<BR><BR>"); writer.println("The migration process is complete."); if (completeSuccess) { writer.println("There were no errors encountered during the " + "migration process."); } else { writer.println("One or more errors were encountered during the " + "migration."); writer.println("Check the above messages for details about the " + "failure(s) that occurred."); } writer.println("<!-- END MAIN BODY -->" + EOL + EOL); writer.println(generateHTMLFooter(requestInfo)); writer.flush(); return; } } // Display a form to the user that can be used to select which data should // be migrated from the specified directory server. htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Migrate Data from Configuration Directory</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Please select the data to migrate from the directory " + "server:" + 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_MIGRATE) + EOL); htmlBody.append(" " + generateHidden( Constants.SERVLET_PARAM_SERVER_INFO_SUBMITTED, "1") + EOL); for (int i=0; i < dsParams.length; i++) { htmlBody.append(" " + dsParams[i].generateHidden( Constants.SERVLET_PARAM_JOB_PARAM_PREFIX) + EOL); } if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" Folder(s) to Migrate:" + EOL); htmlBody.append(" <SELECT NAME=\"" + Constants.SERVLET_PARAM_MIGRATE_FOLDERS + "\">" + EOL); htmlBody.append(" <OPTION VALUE=\"" + Constants.MIGRATE_FOLDERS_SELECTED + "\">" + Constants.MIGRATE_FOLDERS_SELECTED + EOL); htmlBody.append(" <OPTION VALUE=\"" + Constants.MIGRATE_FOLDERS_ALL + "\">" + Constants.MIGRATE_FOLDERS_ALL + EOL); htmlBody.append(" </SELECT>" + EOL); htmlBody.append(" <BR>"); for (int i=0; i < folderNames.length; i++) { htmlBody.append(" <INPUT TYPE=\"CHECKBOX\" NAME=\"" + Constants.SERVLET_PARAM_JOB_FOLDER + "\" VALUE=\"" + folderNames[i] + "\">" + folderNames[i] + "<BR>" + EOL); } htmlBody.append(" <BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Start Migration\">" + EOL); htmlBody.append("</FORM>" + EOL); } /** * Handles all processing required to allow the user to view the set of job * classes that have been defined in the SLAMD server, or to view detailed * information about a particular job class. * * @param requestInfo The state information for this request. */ static void handleViewJobClass(RequestInfo requestInfo) { logMessage(requestInfo, "In handleViewJobClass()"); // The user must have at least view job class permission to access anything // in this section. if (! requestInfo.mayViewJobClass) { logMessage(requestInfo, "No mayViewJobClass permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "view job class information"); return; } // Get the important state variables for this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; // If a job class name has been specified, then view information for that // class. Otherwise, let the user choose which class to view String jobClassName = request.getParameter(Constants.SERVLET_PARAM_JOB_CLASS); if ((jobClassName != null) && (jobClassName.length() > 0)) { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Job Class <CODE>" + jobClassName + "</CODE></SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); JobClass jobClass = slamdServer.getJobClass(jobClassName); if (jobClass == null) { htmlBody.append("Job class " + jobClassName + " is not defined in the SLAMD server" + EOL); return; } else { if (requestInfo.mayDeleteJobClass) { 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_CLASS) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_CLASS, jobClassName) + 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("<BR>" + EOL); htmlBody.append("<B>Job Class Information</B><BR>" + EOL); htmlBody.append("<TABLE WIDTH=\"100%\" CELLSPACING=\"0\" " + "BORDER=\"0\">" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Class Name</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + jobClassName + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_B + "\">" + EOL); htmlBody.append(" <TD>Job Name</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + jobClass.getJobName() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append(" <TR CLASS=\"" + Constants.STYLE_JOB_SUMMARY_LINE_A + "\">" + EOL); htmlBody.append(" <TD>Description</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); htmlBody.append(" <TD>" + EOL); for (int i=0; i < jobClass.getLongDescription().length; i++) { if (i > 0) { htmlBody.append(" <BR>" + EOL); } htmlBody.append(" " + jobClass.getLongDescription()[i] + EOL); } htmlBody.append(" </TD>" + EOL); htmlBody.append(" </TR>" + EOL); htmlBody.append("</TABLE>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<B>Parameter Information</B>" + EOL); htmlBody.append("<TABLE WIDTH=\"100%\" CELLSPACING=\"0\" " + "BORDER=\"0\">" + EOL); Parameter[] params = jobClass.getParameterStubs().clone().getParameters(); for (int i=0; ((params != null) && (i < params.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); } htmlBody.append(" <TD>" + params[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" <TD> </TD>" + EOL); String description = replaceText(params[i].getDescription(), "\r\n", "<BR>"); description = replaceText(description, "\n", "<BR>"); description = replaceText(description, "\t", "      " + "  "); htmlBody.append(" <TD>" + description + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append("</TABLE>" + EOL); } StatTracker[] statTrackerStubs = jobClass.getStatTrackerStubs("", "", 1); if ((statTrackerStubs != null) && (statTrackerStubs.length > 0)) { htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<B>Statistics Collected</B>" + EOL); htmlBody.append("<TABLE WIDTH=\"100%\" CELLSPACING=\"0\" " + "BORDER=\"0\">" + EOL); for (int i=0; i < statTrackerStubs.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); } htmlBody.append(" <TD>" + statTrackerStubs[i].getDisplayName() + "</TD>" + EOL); htmlBody.append(" </TR>" + EOL); } htmlBody.append("</TABLE>" + EOL); } } else { htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Defined Job Classes</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); JobClass[][] categorizedClasses = slamdServer.getCategorizedJobClasses(); if ((categorizedClasses == null) || (categorizedClasses.length == 0)) { htmlBody.append("There are currently no job classes defined in the " + "SLAMD server"); } else { htmlBody.append("The following job classes have been defined in the " + "SLAMD server:" + 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 link = generateLink(requestInfo, Constants.SERVLET_SECTION_JOB, Constants.SERVLET_SECTION_JOB_VIEW_CLASSES, Constants.SERVLET_PARAM_JOB_CLASS, categorizedClasses[i][j].getClass().getName(), categorizedClasses[i][j].getJobName()); htmlBody.append(" <LI>" + link + " (" + categorizedClasses[i][j].getClass().getName() + ")</LI>" + EOL); } htmlBody.append("</UL>" + EOL); htmlBody.append("<BR>" + EOL); } } } } /** * Handles the work required to add a new job class definition to the SLAMD * server. * * @param requestInfo The state information for this request. */ static void handleAddJobClass(RequestInfo requestInfo) { logMessage(requestInfo, "In handleAddJobClass()"); // The user must have the add job class permission to see anything here if (! requestInfo.mayAddJobClass) { logMessage(requestInfo, "No mayAddJobClass permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "define new job classes in the SLAMD server."); 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 a job class name has been specified. If so, then try to add it // to the server. If not, then let the user specify the class name. String jobClassName = request.getParameter(Constants.SERVLET_PARAM_JOB_CLASS); if ((jobClassName != null) && (jobClassName.length() > 0)) { try { JobClass jobClass = slamdServer.loadJobClass(jobClassName); if (jobClass instanceof UnknownJobClass) { throw new SLAMDException("Unknown, missing, or invalid job class " + jobClassName); } slamdServer.addJobClass(jobClass); infoMessage.append("Successfully added the job class definition " + "to the SLAMD server.<BR>" + EOL); handleViewJobClass(requestInfo); return; } catch (SLAMDException se) { infoMessage.append(se.getMessage() + "<BR>" + EOL); requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, se.getMessage()); } } htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Define a New Job Class</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Enter the fully-qualified name of the job class to " + "define in the server." + 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_ADD_CLASS) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" Job Class Name: " + EOL); htmlBody.append(" <INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_CLASS + "\" SIZE=\"40\">" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Add Job Class\">" + EOL); htmlBody.append("</FORM>" + EOL); } /** * Handles the work required to install an uploaded job pack. * * @param requestInfo The state information for this request. */ static void handleInstallJobPack(RequestInfo requestInfo) { logMessage(requestInfo, "In handleInstallJobPack()"); // The user must have the add job class permission to see anything here if (! requestInfo.mayAddJobClass) { logMessage(requestInfo, "No mayAddJobClass permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "define new job classes in the SLAMD server."); return; } // Get the important variables used in this request. HttpServletRequest request = requestInfo.request; String servletBaseURI = requestInfo.servletBaseURI; StringBuilder htmlBody = requestInfo.htmlBody; StringBuilder infoMessage = requestInfo.infoMessage; String filePath = request.getParameter(Constants.SERVLET_PARAM_JOB_PACK_PATH); // Determine whether the request contains uploaded file data. if (FileUpload.isMultipartContent(request)) { // This request contains the file data, so process it. JobPack jobPack = new JobPack(requestInfo); try { jobPack.processJobPack(); infoMessage.append("Successfully installed the job pack.<BR>" + EOL); } catch (SLAMDServerException sse) { infoMessage.append("Error installing job pack -- " + sse.getMessage() + ".<BR>" + EOL); } } else if ((filePath != null) && (filePath.length() > 0)) { // This request contains the path to the job pack on the server's // filesystem, so process it. JobPack jobPack = new JobPack(requestInfo, filePath); try { jobPack.processJobPack(); infoMessage.append("Successfully installed the job pack.<BR>" + EOL); } catch (SLAMDServerException sse) { requestInfo.response.addHeader(Constants.RESPONSE_HEADER_ERROR_MESSAGE, sse.getMessage()); infoMessage.append("Error installing job pack -- " + sse.getMessage() + ".<BR>" + EOL); } } else { // The request does not contain the file data, so present a form to allow // the user to upload it. htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Install a New Job Pack</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Install a job pack file uploaded through the browser." + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("<FORM METHOD=\"POST\" ENCTYPE=\"multipart/form-data\" " + "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_INSTALL_JOB_PACK) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" Job Pack File: " + EOL); htmlBody.append(" <INPUT TYPE=\"FILE\" NAME=\"" + Constants.SERVLET_PARAM_JOB_PACK_FILE + "\">" + EOL); htmlBody.append(" <BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Install Job Pack\">" + EOL); htmlBody.append("</FORM>" + EOL); htmlBody.append("<BR><BR><HR><BR>" + EOL); htmlBody.append("Install a job pack file on the server's filesystem." + 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_INSTALL_JOB_PACK) + EOL); if (requestInfo.debugHTML) { htmlBody.append(generateHidden(Constants.SERVLET_PARAM_HTML_DEBUG, "1") + EOL); } htmlBody.append(" Job Pack File Path: " + EOL); htmlBody.append(" <INPUT TYPE=\"TEXT\" NAME=\"" + Constants.SERVLET_PARAM_JOB_PACK_PATH + "\" SIZE=\"40\">" + EOL); htmlBody.append(" <BR>" + EOL); htmlBody.append(" <INPUT TYPE=\"SUBMIT\" VALUE=\"Install Job Pack\">" + EOL); htmlBody.append("</FORM>" + EOL); } } /** * Handles the work required to remove a job class definition from the SLAMD * server, including obtaining confirmation that the user really wants to * remove the definition. * * @param requestInfo The state information for this request. */ static void handleDeleteJobClass(RequestInfo requestInfo) { logMessage(requestInfo, "In handleDeleteJobClass()"); // The user must have the delete job class permission to see anything here if (! requestInfo.mayDeleteJobClass) { logMessage(requestInfo, "No mayDeleteJobClass permission granted"); generateAccessDeniedBody(requestInfo, "You do not have permission to " + "remove job class definitions from the SLAMD " + "server."); 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 a class name was specified. If not, then just display an // error message. String jobClassName = request.getParameter(Constants.SERVLET_PARAM_JOB_CLASS); if ((jobClassName == null) || (jobClassName.length() == 0)) { infoMessage.append("ERROR: No job class name specified.<BR>" + EOL); return; } // Make sure that it is a class that is defined in the SLAMD server. JobClass jobClass = slamdServer.getJobClass(jobClassName); if (jobClass == null) { infoMessage.append("ERROR: Job class " + jobClassName + "is not defined in the SLAMD server.<BR>" + EOL); return; } // If confirmation has not been provided, then request it. If it has been // provided, then remove the job class definition. 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 + "\">Delete Job Class Definition</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("Are you sure you want to remove job class <CODE>" + jobClassName + "</CODE> from the SLAMD server?" + 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_DELETE_CLASS) + EOL); htmlBody.append(" " + generateHidden(Constants.SERVLET_PARAM_JOB_CLASS, jobClassName) + 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 { slamdServer.removeJobClass(jobClass); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Delete Successful</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("The definition for job class " + jobClassName + " was successfully removed from the SLAMD server." + EOL); } catch (SLAMDServerException sse) { infoMessage.append("ERROR: Could not remove job class " + jobClassName + " -- " + sse.getMessage() + "<BR>" + EOL); htmlBody.append("<SPAN CLASS=\"" + Constants.STYLE_MAIN_HEADER + "\">Delete Failed</SPAN>" + EOL); htmlBody.append("<BR><BR>" + EOL); htmlBody.append("The definition for job class " + jobClassName + " could not be removed from the SLAMD server." + EOL); htmlBody.append("See the above error message for additional " + "information" + EOL); } } else { infoMessage.append("Job Class " + jobClassName + " was not removed from the SLAMD server.<BR>" + EOL); handleViewJobClass(requestInfo); } } /** * Generates page content based on an MD5-digest of the query string. * * @param requestInfo The state information for this request. * @param digestString The base64-encoded MD5 digest of the query string to * use to generate the page. */ static void generatePageFromMD5(RequestInfo requestInfo, String digestString) { try { String dataFile = Constants.MD5_CONTENT_BASE_PATH + '/' + digestString; InputStream inputStream = slamdServer.getClass().getClassLoader(). getResourceAsStream(dataFile); byte[] salt = { 0, 0, 0, 0, 0, 0, 0, 0 }; char[] queryChars = requestInfo.request.getQueryString().toCharArray(); int iterations = 1000; String cipherName = "PBEWithMD5AndDES"; StringBuilder htmlBody = requestInfo.htmlBody; AlgorithmParameters algorithmParams = AlgorithmParameters.getInstance(cipherName); algorithmParams.init(new PBEParameterSpec(salt, iterations)); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(cipherName); SecretKey key = keyFactory.generateSecret(new PBEKeySpec(queryChars)); Cipher cipher = Cipher.getInstance(cipherName); cipher.init(Cipher.DECRYPT_MODE, key, algorithmParams); int bytesIn; int bytesOut; byte[] inBuffer = new byte[4096]; byte[] outBuffer = new byte[8192]; while ((bytesIn = inputStream.read(inBuffer)) > 0) { bytesOut = cipher.update(inBuffer, 0, bytesIn, outBuffer); htmlBody.append(new String(outBuffer, 0, bytesOut)); } htmlBody.append(new String(cipher.doFinal())); inputStream.close(); } catch (Exception e) { requestInfo.htmlBody.append(JobClass.stackTraceToString(e)); } } /** * Generates the HTML header that will be used for almost all pages generated * by this administrative interface. It will include the header text at the * top and the navigation sidebar on the left. * * @param requestInfo The state information for this request. * * @return The generated HTML header. */ static String generateHTMLHeader(RequestInfo requestInfo) { StringBuilder html = new StringBuilder(); // Generate the DTD header. All HTML generated should be compliant to the // HTML 4.01 specification. html.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 " + "Transitional//EN\">" + EOL); html.append(EOL); html.append("<HTML>" + EOL); html.append(" <HEAD>" + EOL); html.append(" <TITLE>" + generatePageTitle(requestInfo) + "</TITLE>" + EOL); html.append(" <META HTTP-EQUIV=\"Content-Type\" " + "CONTENT=\"text/html; charset=utf-8\">" + EOL); html.append(getStyleSheet() + EOL); html.append(getAddedHeaderLines() + EOL); html.append(" </HEAD>"); html.append(EOL); html.append(" <BODY>" + EOL); html.append(EOL); html.append("<!-- requestID " + requestInfo.requestID + " -->" + EOL); html.append("<!-- section " + requestInfo.section + " -->" + EOL); html.append("<!-- subsection " + requestInfo.subsection + " -->" + EOL); html.append(debugRequestInfo(requestInfo)); if (requestInfo.debugHTML) { html.append(requestInfo.debugInfo.toString()); } html.append(EOL); html.append(" <TABLE BORDER=\"0\" WIDTH=\"100%\" CELLPADDING=\"5\">" + EOL); html.append(" <TR>" + EOL); html.append(" <TD WIDTH=\"15%\" VALIGN=\"TOP\">" + EOL); html.append("<!-- START SIDE NAVIGATION BAR -->" + EOL); html.append(generateSideBar(requestInfo)); html.append("<!-- END SIDE NAVIGATION BAR -->" + EOL); html.append(" </TD>" + EOL); html.append(EOL); html.append(" <TD WIDTH=\"85%\" VALIGN=\"TOP\">" + EOL); html.append("<!-- START PAGE HEADER -->" + EOL); html.append(getHeader(requestInfo)); html.append("<!-- END PAGE HEADER -->" + EOL); html.append(EOL); return html.toString(); } /** * Generates the HTML header that will be used for special content that should * not include either the header text or the navigation sidebar (e.g., help * pages). * * @param requestInfo The state information for this request. * * @return The generated HTML header. */ static String generateHTMLHeaderWithoutSidebar(RequestInfo requestInfo) { StringBuilder html = new StringBuilder(); // Generate the DTD header. All HTML generated should be compliant to the // HTML 4.01 specification. html.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 " + "Transitional//EN\">" + EOL); html.append(EOL); html.append("<HTML>" + EOL); html.append(" <HEAD>" + EOL); html.append(" <TITLE>" + generatePageTitle(requestInfo) + "</TITLE>" + EOL); html.append(" <META HTTP-EQUIV=\"Content-Type\" " + "CONTENT=\"text/html; charset=utf-8\">" + EOL); html.append(getStyleSheet() + EOL); html.append(getAddedHeaderLines() + EOL); html.append(" </HEAD>"); html.append(EOL); html.append(debugRequestInfo(requestInfo)); if (requestInfo.debugHTML) { html.append(requestInfo.debugInfo.toString()); } html.append(" <BODY>" + EOL); html.append(" <TABLE BORDER=\"0\" WIDTH=\"100%\" CELLPADDING=\"5\">" + EOL); html.append(" <TR>" + EOL); html.append(" <TD WIDTH=\"100%\" VALIGN=\"TOP\">" + EOL); return html.toString(); } /** * Retrieves the style sheet data that should be used for the servlet. * * @return The style sheet data that should be used for the servlet. */ static String getStyleSheet() { if (styleSheet == null) { if (configDB == null) { styleSheet = Constants.STYLE_SHEET_DATA; } else { styleSheet = configDB.getConfigParameter(Constants.PARAM_STYLE_SHEET); if ((styleSheet == null) || (styleSheet.length() == 0)) { styleSheet = Constants.STYLE_SHEET_DATA; } } } return styleSheet; } /** * Retrieves the set of lines that should be added to the HTML header. * * @return The set of lines that should be added to the HTML header. */ static String getAddedHeaderLines() { if (addedHeaderLines == null) { if (configDB == null) { addedHeaderLines = ""; } else { addedHeaderLines = configDB.getConfigParameter(Constants.PARAM_ADD_TO_HTML_HEADER); if ((addedHeaderLines == null) || (addedHeaderLines.length() == 0)) { addedHeaderLines = ""; } } } return addedHeaderLines; } /** * Retrieves the header that should be used at the top of generated pages. * * @param requestInfo The state information for this request. * * @return The header that should be used at the top of generated pages. */ static String getHeader(RequestInfo requestInfo) { if (pageHeader == null) { if (configDB == null) { pageHeader = parseHeader(requestInfo, Constants.DEFAULT_PAGE_HEADER); } else { String headerText = configDB.getConfigParameter(Constants.PARAM_PAGE_HEADER); if ((headerText == null) || (headerText.length() == 0)) { headerText = Constants.DEFAULT_PAGE_HEADER; } pageHeader = parseHeader(requestInfo, headerText); } } return pageHeader; } /** * Parses the provided header text to replace embedded tags with the * appropriate values. * * @param requestInfo The state information for this request. * @param headerText The header text to be parsed. * * @return The parsed header text. */ static String parseHeader(RequestInfo requestInfo, String headerText) { int pos; while ((pos = headerText.indexOf(Constants.HEADER_TAG_SLAMD_LOGO)) >= 0) { String preText = headerText.substring(0, pos); String postText = headerText.substring(pos+Constants.HEADER_TAG_SLAMD_LOGO.length()); headerText = preText + "<IMG SRC=\"" + requestInfo.servletBaseURI + '?' + Constants.SERVLET_PARAM_SECTION + '=' + Constants.SERVLET_SECTION_SLAMD_LOGO + "\" ALT=\"SLAMD Logo\">" + postText; } while ((pos = headerText.indexOf(Constants.HEADER_TAG_SLAMD_VERSION)) >= 0) { String preText = headerText.substring(0, pos); String postText = headerText.substring(pos+ Constants.HEADER_TAG_SLAMD_VERSION.length()); headerText = preText + "Version " + DynamicConstants.SLAMD_VERSION + postText; } while ((pos = headerText.indexOf( Constants.HEADER_TAG_SLAMD_UNOFFICIAL_BUILD_ID)) >= 0) { String preText = headerText.substring(0, pos); String postText = headerText.substring(pos+ Constants.HEADER_TAG_SLAMD_UNOFFICIAL_BUILD_ID.length()); if (DynamicConstants.OFFICIAL_BUILD) { headerText = preText + postText; } else { headerText = preText + "Unofficial Build " + DynamicConstants.BUILD_DATE + postText; } } while ((pos = headerText.indexOf( Constants.HEADER_TAG_SLAMD_UNOFFICIAL_BUILD)) >= 0) { String preText = headerText.substring(0, pos); String postText = headerText.substring(pos+ Constants.HEADER_TAG_SLAMD_UNOFFICIAL_BUILD.length()); if (DynamicConstants.OFFICIAL_BUILD) { headerText = preText + postText; } else { headerText = preText + "Unofficial Build" + postText; } } while ((pos = headerText.indexOf( Constants.HEADER_TAG_SLAMD_BUILD_DATE)) >= 0) { String preText = headerText.substring(0, pos); String postText = headerText.substring(pos+ Constants.HEADER_TAG_SLAMD_BUILD_DATE.length()); headerText = preText + DynamicConstants.BUILD_DATE + postText; } while ((pos = headerText.indexOf( Constants.HEADER_TAG_SLAMD_MAJOR_VERSION)) >= 0) { String preText = headerText.substring(0, pos); String postText = headerText.substring(pos+ Constants.HEADER_TAG_SLAMD_MAJOR_VERSION.length()); headerText = preText + DynamicConstants.MAJOR_VERSION + postText; } while ((pos = headerText.indexOf( Constants.HEADER_TAG_SLAMD_MINOR_VERSION)) >= 0) { String preText = headerText.substring(0, pos); String postText = headerText.substring(pos+ Constants.HEADER_TAG_SLAMD_MINOR_VERSION.length()); headerText = preText + DynamicConstants.MINOR_VERSION + postText; } while ((pos = headerText.indexOf( Constants.HEADER_TAG_SLAMD_POINT_VERSION)) >= 0) { String preText = headerText.substring(0, pos); String postText = headerText.substring(pos+ Constants.HEADER_TAG_SLAMD_POINT_VERSION.length()); headerText = preText + DynamicConstants.POINT_VERSION + postText; } return headerText; } /** * Generates an appropriate title for the page being displayed. The * determination will be based on state information contained in the provided * request. * * @param requestInfo The state information for this request. * * @return The page title that should be used for the current page. */ static String generatePageTitle(RequestInfo requestInfo) { String pageTitle = "SLAMD Distributed Load Generation Engine"; String section = requestInfo.section; String subsection = requestInfo.subsection; if (section.equals(Constants.SERVLET_SECTION_CONFIG)) { if (subsection.equals(Constants.SERVLET_SECTION_CONFIG_SERVLET)) { pageTitle = "Manage Initialization Parameters - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_CONFIG_ACCESS)) { pageTitle = "Manage Access Control - " + pageTitle; } else { pageTitle = "Manage SLAMD Configuration - " + pageTitle; } } else if (section.equals(Constants.SERVLET_SECTION_STATUS)) { pageTitle = "SLAMD Server Status - " + pageTitle; } else if (section.equals(Constants.SERVLET_SECTION_JOB)) { if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_PENDING) || subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_RUNNING) || subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_COMPLETED) || subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_GENERIC)) { pageTitle = "View Job Information - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_SEARCH)) { pageTitle = "Search for Job Information - " + pageTitle; } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_VIEW_REAL)) { pageTitle = "Manage Real Job Folders - " + pageTitle; } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_VIEW_VIRTUAL)) { pageTitle = "Manage Virtual Job Folders - " + pageTitle; } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_FOLDER_DESCRIPTION)) { pageTitle = "Edit Folder Description - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_STATS)) { pageTitle = "View Job Statistics - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_SAVE_STATS)) { pageTitle = "Save Job Statistics - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_GRAPH) || subsection.equals(Constants.SERVLET_SECTION_JOB_GRAPH) || subsection.equals(Constants.SERVLET_SECTION_JOB_OVERLAY) || subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_OVERLAY)) { pageTitle = "Graph Job Statistics - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_SCHEDULE)) { pageTitle = "Schedule a New Job - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_CLONE)) { pageTitle = "Clone a Scheduled Job - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_EDIT)) { pageTitle = "Edit a Scheduled Job - " + pageTitle; } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_EDIT_COMMENTS)) { pageTitle = "Edit Job Comments - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_CANCEL)) { pageTitle = "Cancel a Scheduled Job - " + pageTitle; } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_CANCEL_AND_DELETE)) { pageTitle = "Cancel and Delete a Scheduled Job - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_DELETE)) { pageTitle = "Delete Job Information - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_DISABLE)) { pageTitle = "Disable a Scheduled Job - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_ENABLE)) { pageTitle = "Enable a Scheduled Job - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_MASS_OP) || subsection.equals(Constants.SERVLET_SECTION_JOB_MASS_OPTIMIZING)) { String submitStr = requestInfo.request.getParameter(Constants.SERVLET_PARAM_SUBMIT); if (submitStr.equals(Constants.SUBMIT_STRING_ADD_TO_VIRTUAL_FOLDER)) { pageTitle = "Add Jobs to a Virtual Job Folder - " + pageTitle; } else if (submitStr.equals(Constants.SUBMIT_STRING_CANCEL)) { pageTitle = "Cancel Scheduled Jobs - " + pageTitle; } else if (submitStr.equals(Constants.SUBMIT_STRING_CANCEL_AND_DELETE)) { pageTitle = "Cancel and Delete Scheduled Jobs - " + pageTitle; } else if (submitStr.equals(Constants.SUBMIT_STRING_CLONE)) { pageTitle = "Clone Scheduled Jobs Information - " + pageTitle; } else if (submitStr.equals(Constants.SUBMIT_STRING_COMPARE)) { pageTitle = "Compare Scheduled Jobs - " + pageTitle; } else if (submitStr.equals(Constants.SUBMIT_STRING_CREATE_FOLDER)) { pageTitle = "Create a New Job Folder - " + pageTitle; } else if (submitStr.equals(Constants.SUBMIT_STRING_DELETE)) { pageTitle = "Delete Scheduled Jobs - " + pageTitle; } else if (submitStr.equals(Constants.SUBMIT_STRING_DELETE_FOLDER)) { pageTitle = "Delete a Job Folder - " + pageTitle; } else if (submitStr.equals(Constants.SUBMIT_STRING_DISABLE)) { pageTitle = "Disable Scheduled Jobs - " + pageTitle; } else if (submitStr.equals(Constants.SUBMIT_STRING_ENABLE)) { pageTitle = "Enable Scheduled Jobs - " + pageTitle; } else if (submitStr.equals(Constants.SUBMIT_STRING_EXPORT)) { pageTitle = "Export Job Information - " + pageTitle; } else if (submitStr.equals(Constants.SUBMIT_STRING_MOVE)) { pageTitle = "Move Job Information - " + pageTitle; } else if (submitStr.equals( Constants.SUBMIT_STRING_REMOVE_FROM_VIRTUAL_FOLDER)) { pageTitle = "Remove Jobs from a Virtual Job Folder - " + pageTitle; } } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_OPTIMIZE)) { pageTitle = "Optimize Job Results - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_OPTIMIZE_HELP)) { pageTitle = "Optimize Job Results Help - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING)) { pageTitle = "View Optimizing Job - " + pageTitle; } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_CANCEL_OPTIMIZING)) { pageTitle = "Cancel Optimizing Job - " + pageTitle; } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_CLONE_OPTIMIZING)) { pageTitle = "Clone Optimizing Job - " + pageTitle; } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_DELETE_OPTIMIZING)) { pageTitle = "Delete Optimizing Job - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_MOVE_OPTIMIZING)) { pageTitle = "Move Optimizing Job - " + pageTitle; } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_VIEW_CLASSES)) { pageTitle = "Defined Job Classes - " + pageTitle; } else if (subsection.equals(Constants.SERVLET_SECTION_JOB_ADD_CLASS)) { pageTitle = "Define a New Job Class - " + pageTitle; } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_DELETE_CLASS)) { pageTitle = "Remove a Defined Job Class - " + pageTitle; } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_INSTALL_JOB_PACK)) { pageTitle = "Install a Job Pack - " + pageTitle; } else if (subsection.equals( Constants.SERVLET_SECTION_JOB_SCHEDULE_HELP)) { pageTitle = "Help on Job Parameters - " + pageTitle; } else { pageTitle = "SLAMD Job Information - " + pageTitle; } } if (includeAddressInPageTitle) { pageTitle = requestInfo.request.getServerName() + " - " + pageTitle; } return pageTitle; } /** * Replaces all occurrences of a given substring with another substring in the * provided string. * * @param s The string in which to perform the replace. * @param find The substring to find in the provided string. * @param replace The text to use in place of the specified substring. * * @return The updated string. */ static String replaceText(String s, String find, String replace) { int pos = s.indexOf(find); while (pos >= 0) { s = s.substring(0, pos) + replace + s.substring(pos+find.length()); pos = s.indexOf(find, pos+replace.length()); } return s; } /** * Writes the specified message to the SLAMD server log with the appropriate * admin interface log level. The request ID will be prepended to the * message. * * @param requestInfo The state information for this request. * @param message The message to be written to the SLAMD log file. */ static void logMessage(RequestInfo requestInfo, String message) { if (slamdServer != null) { slamdServer.logMessage(Constants.LOG_LEVEL_ADMIN, requestInfo.requestID + " - " + message); } if (requestInfo.debugInfo != null) { requestInfo.debugInfo.append("<!-- " + message + " -->" + EOL); } } /** * Retrieves the class path for this servlet. * * @return The class path for this servlet. */ public static String getClassPath() { return classPath; } /** * Retrieves the path to the WEB-INF directory for the admin interface. * * @return The path to the WEB-INF directory for the admin interface. */ public static String getWebInfPath() { return webInfBasePath; } /** * Converts breaks the provided string into an array of lines. * * @param stringValue The string to be broken into a line array. * * @return The string array converted to an array of lines. */ static String[] stringToLineArray(String stringValue) { ArrayList<String> lineList = new ArrayList<String>(); if (stringValue != null) { StringTokenizer tokenizer = new StringTokenizer(stringValue, "\r\n"); while (tokenizer.hasMoreTokens()) { lineList.add(tokenizer.nextToken()); } } String[] lineArray = new String[lineList.size()]; lineList.toArray(lineArray); return lineArray; } }