From f709e4eeb31d7f224ca848f95a37756414ce7158 Mon Sep 17 00:00:00 2001 From: John Buck Date: Mon, 3 Jun 2024 15:55:44 -0400 Subject: [PATCH 01/10] i_232 Submit judges' solutions with tracking results Start with the code that @lane55 wrote last year and bring it up-to-date for the latest develop. Still needs a lot of polishing. --- src/edu/csus/ecs/pc2/list/ListUtilities.java | 166 ++++ .../pc2/list/SubmissionSampleLocation.java | 46 + .../ecs/pc2/list/SubmissionSolutionList.java | 130 +++ src/edu/csus/ecs/pc2/ui/FrameUtilities.java | 94 ++ .../csus/ecs/pc2/ui/ISelectedListsSetter.java | 22 + src/edu/csus/ecs/pc2/ui/JListFrame.java | 66 ++ src/edu/csus/ecs/pc2/ui/JListPane.java | 164 ++++ .../csus/ecs/pc2/ui/SubmitSampleRunsPane.java | 877 ++++++++++++++++++ .../ecs/pc2/ui/SubmitSubmissionsPane.java | 2 +- .../csus/ecs/pc2/ui/server/ServerView.java | 4 + 10 files changed, 1570 insertions(+), 1 deletion(-) create mode 100644 src/edu/csus/ecs/pc2/list/ListUtilities.java create mode 100644 src/edu/csus/ecs/pc2/list/SubmissionSampleLocation.java create mode 100644 src/edu/csus/ecs/pc2/list/SubmissionSolutionList.java create mode 100644 src/edu/csus/ecs/pc2/ui/ISelectedListsSetter.java create mode 100644 src/edu/csus/ecs/pc2/ui/JListFrame.java create mode 100644 src/edu/csus/ecs/pc2/ui/JListPane.java create mode 100644 src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java diff --git a/src/edu/csus/ecs/pc2/list/ListUtilities.java b/src/edu/csus/ecs/pc2/list/ListUtilities.java new file mode 100644 index 000000000..e982bd6ee --- /dev/null +++ b/src/edu/csus/ecs/pc2/list/ListUtilities.java @@ -0,0 +1,166 @@ +// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +package edu.csus.ecs.pc2.list; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import edu.csus.ecs.pc2.core.LanguageUtilities; +import edu.csus.ecs.pc2.core.model.IInternalContest; +import edu.csus.ecs.pc2.core.model.Language; +import edu.csus.ecs.pc2.core.model.Problem; +import edu.csus.ecs.pc2.imports.ccs.IContestLoader; +import edu.csus.ecs.pc2.validator.clicsValidator.ClicsValidator; + +/** + * A set of utilities that operate on lists. + * + * @author Douglas A. Lane + * + */ +public class ListUtilities { + + /** + * Returns list of files that match the SubmissionSolutionList (judging types location/list) + * + * @param files list of files to be filtered + * @param submissionList a class that manages a number of SubmissionSampleLocation + * @return + */ + public static List filterByJudgingTypes(List files, SubmissionSolutionList submissionSolutionList) { + + List newFileList = new ArrayList(); + + for (File file : files) { + submissionSolutionList.forEach((subSol) -> { + if (file.getAbsolutePath().contains(File.separator + subSol.getShortDirectoryName() + File.separator)) { + newFileList.add(file); + } + }); + } + + return newFileList; + } + + /** + * Returns list of all files under dir path. + * + * @param dirName location to fetch files from + * @return list of files in and under dirName + */ + // TODO REFACTOR replace findAll from QuickSubmitter with this method. + public static List findAllFiles(String dirName) { + + List files = new ArrayList<>(); + + File dir = new File(dirName); + File[] entries = dir.listFiles(); + + if (entries == null) { + return files; + } + + for (File f : entries) { + if (f.isDirectory()) { + List subList = findAllFiles(f.getAbsolutePath()); + files.addAll(subList); + } else { + files.add(f); + } + } + + return files; + } + + /** + * Get all CDP judge's sample submission filenames. + * + * Example files under config\sumit\submissions + * + * @param mycontest + * @param directoryName CDP config/ dir or CDP base directory + * @return list of judges sample submissions + */ + // TODO REFACTOR remove getAllCDPsubmissionFileNames from QuickSubmitter + public static List getAllJudgeSampleSubmissionFilenamesFromCDP(IInternalContest mycontest, String directoryName) { + + Problem[] problems = mycontest.getProblems(); + List files = new ArrayList<>(); + + String configDir = directoryName + File.separator + IContestLoader.CONFIG_DIRNAME; + if (new File(configDir).isDirectory()) { + directoryName = configDir; + } + + for (Problem problem : problems) { + + // config\sumit\submissions\accepted\ISumit.java + String probSubmissionDir = directoryName + File.separator + problem.getShortName() + File.separator + + IContestLoader.SUBMISSIONS_DIRNAME; + files.addAll(findAllFiles(probSubmissionDir)); + + } + + return files; + } + + /** + * Find files (in CDP) that contain one of the Problems in the list. + * + */ + public static List filterByProblems(List files, List selectedProblemList) { + + List newFileList = new ArrayList(); + + for (File file : files) { + selectedProblemList.forEach((prob) -> { + if (file.getAbsolutePath().contains(File.separator + prob.getShortName() + File.separator)) { + newFileList.add(file); + } + }); + } + + return newFileList; + + } + + /** + * Find all accepted/Yes filenames with "accepted" in file list. + * + * @param files list of files + * @return list of files that have a directory name of "accepted" embedded in their path. + */ + public static List filterYesJudgingType (List files) { + + List newFileList = new ArrayList(); + + for (File file : files) { + if (file.getAbsolutePath().contains(File.separator + ClicsValidator.CLICS_CORRECT_ANSWER_MSG + File.separator)) { + newFileList.add(file); + } + } + + return newFileList; + } + + public static List filterByLanguages(List files, IInternalContest contest, List selectedLanguageList) { + + List newFileList = new ArrayList(); + + for (File file : files) { + selectedLanguageList.forEach((lang) -> { + + // TODO match by extention + Language language = LanguageUtilities.matchFirstLanguage(contest, LanguageUtilities.getExtension(file.getName())); + + if (lang.getDisplayName().contentEquals(lang.getDisplayName())) { + newFileList.add(file); + } + }); + } + + return newFileList; + + } + +} diff --git a/src/edu/csus/ecs/pc2/list/SubmissionSampleLocation.java b/src/edu/csus/ecs/pc2/list/SubmissionSampleLocation.java new file mode 100644 index 000000000..c157676b1 --- /dev/null +++ b/src/edu/csus/ecs/pc2/list/SubmissionSampleLocation.java @@ -0,0 +1,46 @@ +// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +package edu.csus.ecs.pc2.list; + +/** + * A single entry of a judge's solution locations. + * + * @author Douglas A. Lane + */ +public class SubmissionSampleLocation implements Comparable { + private String title; + private String shortDirectoryName; + + /** + * A judges solution name and location. + * + * @param title title for directory, ex. Run Time Error + * @param shortDirectoryName base directory name, ex. run_time_error + */ + public SubmissionSampleLocation(String title, String shortDirectoryName) { + this.title = title; + this.shortDirectoryName = shortDirectoryName;; + } + + public String getTitle() { + return title; + } + + public String getShortDirectoryName() { + return shortDirectoryName; + } + + @Override + public String toString() { + if (title.length() > 0) { + return title + " ("+shortDirectoryName+")"; + } else { + return shortDirectoryName; + } + } + + @Override + public int compareTo(SubmissionSampleLocation o) { + return o.toString().compareTo(toString()); + } + +} diff --git a/src/edu/csus/ecs/pc2/list/SubmissionSolutionList.java b/src/edu/csus/ecs/pc2/list/SubmissionSolutionList.java new file mode 100644 index 000000000..303e5eacf --- /dev/null +++ b/src/edu/csus/ecs/pc2/list/SubmissionSolutionList.java @@ -0,0 +1,130 @@ +// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +package edu.csus.ecs.pc2.list; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; + +import edu.csus.ecs.pc2.imports.ccs.IContestLoader; + +/** + * List of judge's solutions + * + * @author Douglas A. Lane + * + */ +public class SubmissionSolutionList extends ArrayList { + + /** + * + */ + private static final long serialVersionUID = 6231245379952020474L; + + public SubmissionSolutionList() { + super(); + } + + public SubmissionSolutionList(File cdpPath) { + super(); + loadCDPSampleSubmissionList(cdpPath); + } + + + /** + * get all directories and child directories (recurses). + * + * @param directory + * @return list of directory names + */ + // TODO REFACTOR move to FileUtilities.getAllDirectoryEntries + public static List getAllDirectoryEntries(String directory) { + + ArrayList list = new ArrayList<>(); + + File[] files = new File(directory).listFiles(); + + if (files != null) { + + for (File entry : files) { + if (entry.isDirectory()) { + list.add(directory + File.separator + entry.getName()); + if (!(entry.getName().equals(".") || entry.getName().equals(".."))) { + list.addAll(getAllDirectoryEntries(directory + File.separator + entry.getName())); + } + } + } + } + + return list; + } + + + + /** + * Load Judge's samples judgement types + * @param cdpPath + * @throws IOException + */ + // TODO NOW use FileUtilities.getAllDirectoryEntries + private void loadCDPSampleSubmissionList(File cdpPath) { + + SortedMap uniqItems = new TreeMap(); + try { + List entries = getAllDirectoryEntries(cdpPath.getCanonicalPath()); + + String pat = IContestLoader.SUBMISSIONS_DIRNAME; + + for (String dirname : entries) { + try { + // pattern found in dirname but not at the end, eliminates submission at end of string + // only includes subdirectories under submissions/ and not the submissions directory + if (dirname.contains(pat) && dirname.lastIndexOf(pat) != dirname.length() - pat.length()){ + String baseName = new File (dirname).getName(); + SubmissionSampleLocation subLoc = new SubmissionSampleLocation("", baseName); + uniqItems.put(subLoc, subLoc.toString()); + } + } catch (Exception e) { + e.printStackTrace(); // debug 22 + return; // debug 22 + } + } + + } catch (Exception e) { + ; // ignore, do not load any items into list because no match + } + + Set keys = uniqItems.keySet(); + for (SubmissionSampleLocation submissionSampleLocation : keys) { + super.add(submissionSampleLocation); + } + + } + + public void loadDefaultList() { + + String[] initList = { + + "Bad Format ; badformat", // + "Run Time Error ; run_time_error", // + "Run Time Error ; runtime_error", // + "Security Violation ; security_violation", // + "Time Limit ; time_limit", // + "Time Limit Exceeded ; time_limit_exceeded", // + "Wrong Answer ; wrong_answer", // + "Wrong Answer ; wronganswer", // + + }; + + for (String entry : initList) { + String[] fields = entry.split(";"); + String title = fields[0].trim(); + String dirName = fields[1].trim(); + + super.add(new SubmissionSampleLocation(title, dirName)); + } + } +} diff --git a/src/edu/csus/ecs/pc2/ui/FrameUtilities.java b/src/edu/csus/ecs/pc2/ui/FrameUtilities.java index bdf7753e4..b4dca55f3 100644 --- a/src/edu/csus/ecs/pc2/ui/FrameUtilities.java +++ b/src/edu/csus/ecs/pc2/ui/FrameUtilities.java @@ -5,6 +5,14 @@ import java.awt.Dimension; import java.awt.Frame; import java.awt.Rectangle; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; + import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; @@ -24,6 +32,9 @@ import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.UIManager; +import javax.swing.Icon; +import javax.swing.JLabel; +import javax.swing.border.EmptyBorder; import edu.csus.ecs.pc2.VersionInfo; import edu.csus.ecs.pc2.core.Constants; @@ -32,6 +43,7 @@ import edu.csus.ecs.pc2.core.log.StaticLog; import edu.csus.ecs.pc2.core.model.IInternalContest; + /** * Methods to center frame, change cursor, etc.
* Contains method to change look and feel, set cursor state, center windows and a yes no dialog with cancel as default. @@ -558,4 +570,86 @@ public void run() { } }); } + private static Image getScaledImage(Image srcImg, int w, int h) { + BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = resizedImg.createGraphics(); + + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2.drawImage(srcImg, 0, 0, w, h, null); + g2.dispose(); + + return resizedImg; + } + + /** + * create a label with question mark and on click shows a message dialog. + * + * @param messageTitle dialog title + * @param messageLines dialog message lines + * @return @return a What's this? label. + */ + public static JLabel getWhatsThisLabel(String messageTitle, String[] messageLines) { + return getToolTipLabel("", "What's This? (click for additional information)", messageTitle, + String.join("\n", messageLines)); + } + + /** + * create a label with question mark and on click shows a message dialog. + * + * @param messageTitle dialog title + * @param message dialog message + * @return a What's this JLabel + */ + // TODO REFACTOR use a getWhatsThisLabel where other What's up labels, search for getIcon("OptionPane.questionIcon") + public static JLabel getWhatsThisLabel(String messageTitle, String message) { + return getToolTipLabel("", "What's This? (click for additional information)", messageTitle, + message); + } + + /** + * create a label with question mark and on click shows a message dialog. + * + * @param buttonName + * @param toolTip + * @param messageTitle + * @param messageLines + */ + public static JLabel getToolTipLabel(String buttonName, String toolTip, String messageTitle, + String[] messageLines) { + return getToolTipLabel(buttonName, toolTip, messageTitle, String.join("\n", messageLines)); + } + + /** + * create a label with question mark and on click shows a message dialog. + * + * @param buttonName name for button + * @param toolTip tooltip for button + * @param messageTitle + * @param message + */ + public static JLabel getToolTipLabel(String buttonName, String toolTip, String messageTitle, String message) { + + JLabel button = new JLabel(buttonName); + + Icon questionIcon = UIManager.getIcon("OptionPane.questionIcon"); + if (questionIcon == null || !(questionIcon instanceof ImageIcon)) { + // the current PLAF doesn't have an OptionPane.questionIcon that's an ImageIcon + + button.setForeground(Color.blue); + } else { + Image image = ((ImageIcon) questionIcon).getImage(); + button = new JLabel(new ImageIcon(getScaledImage(image, 20, 20))); + } + + button.setToolTipText(toolTip); + button.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + + JOptionPane.showMessageDialog(null, message, messageTitle, JOptionPane.INFORMATION_MESSAGE, null); + } + }); + button.setBorder(new EmptyBorder(0, 15, 0, 0)); + return button; + } } diff --git a/src/edu/csus/ecs/pc2/ui/ISelectedListsSetter.java b/src/edu/csus/ecs/pc2/ui/ISelectedListsSetter.java new file mode 100644 index 000000000..42b720f00 --- /dev/null +++ b/src/edu/csus/ecs/pc2/ui/ISelectedListsSetter.java @@ -0,0 +1,22 @@ +// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +package edu.csus.ecs.pc2.ui; + +import java.util.List; + +/** + * Interface for callbacks/observers. + * + * @author Douglas A. Lane + * + */ +public interface ISelectedListsSetter { + + /** + * Provide observers a list of selected values. + * + * @param selectedValuesList list of selected values + * @param selectedIndices list of selected indexes + */ + void setSelectedValuesList(List selectedValuesList, int[] selectedIndices); + +} diff --git a/src/edu/csus/ecs/pc2/ui/JListFrame.java b/src/edu/csus/ecs/pc2/ui/JListFrame.java new file mode 100644 index 000000000..9ada2d03a --- /dev/null +++ b/src/edu/csus/ecs/pc2/ui/JListFrame.java @@ -0,0 +1,66 @@ +// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +package edu.csus.ecs.pc2.ui; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.HeadlessException; +import java.util.Arrays; +import java.util.List; + +import javax.swing.JFrame; + +/** + * Generic List frame. + * + * @see JListPane + * + * + * @author Douglas A. Lane + */ +public class JListFrame extends JFrame { + /** + * + * + */ + private static final long serialVersionUID = -5073426131461967909L; + + private JListPane listPane; + + public JListFrame(String title, Object [] items, int[] selecteditems, ISelectedListsSetter selectedListsSetter) throws HeadlessException { + super(); + setMinimumSize(new Dimension(400, 400)); + setName("JListFrame"); + setTitle(title); + setPreferredSize(new Dimension(400, 400)); + + listPane = new JListPane(this, items, selecteditems, selectedListsSetter); + getContentPane().add(listPane, BorderLayout.CENTER); + FrameUtilities.centerFrame(this); + } + + /** + * Used for unit testing. + * + * @param args + */ + public static void main(String[] args) { + + + Object[] items2 = { "One", "Two", "Three", "Four" }; + + JListFrame f = new JListFrame("hi", items2, new int[0], new ISelectedListsSetter() { + + @Override + public void setSelectedValuesList(List selectedValuesList, int[] selectedIndices) { + for (Object object : selectedValuesList) { + System.out.println("values " + object.toString()); + } + System.out.println("ind " + Arrays.toString(selectedIndices)); + } + }); + f.setVisible(true); + } + + + +} diff --git a/src/edu/csus/ecs/pc2/ui/JListPane.java b/src/edu/csus/ecs/pc2/ui/JListPane.java new file mode 100644 index 000000000..569b82be8 --- /dev/null +++ b/src/edu/csus/ecs/pc2/ui/JListPane.java @@ -0,0 +1,164 @@ +// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +package edu.csus.ecs.pc2.ui; + +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; + +/** + * A Pane that presents the user with a list of items and provides a way to identify + * which list items are selected. On Update will return the selected items via + * the callback ISelectedListsSetter. + * + * Provides a way to show the user a list of items to select, then + * use ISelectedListsSetter to return the selected values to the calling method. + * + * As input takes a list of items and corresponding (if any) indexes of selected items. + * + * When a user selects items and clicks Update will call the ISelectedListsSetter with + * the item list and (new) list of selected indexes within that list. + * + * @author Douglas A. Lane + * + */ +// TODO NOW 232 fix bug where says there is a change, when not selection change has been made. +public class JListPane extends JPanePlugin { + /** + * + */ + private static final long serialVersionUID = -1383088589409036086L; + + @SuppressWarnings("rawtypes") + JList theList = new JList(); + + private JFrame parentFrame = null; + + private int[] holdSelectedIndexes = new int[0]; + + private ISelectedListsSetter selectedListsSetter; + + public JListPane() { + setLayout(new BorderLayout(0, 0)); + + JScrollPane scrollPane = new JScrollPane(); + add(scrollPane); + + scrollPane.setViewportView(theList); + + JPanel buttonPane = new JPanel(); + FlowLayout flowLayout = (FlowLayout) buttonPane.getLayout(); + flowLayout.setHgap(45); + add(buttonPane, BorderLayout.SOUTH); + + JButton saveButton = new JButton("Save"); + saveButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + saveAndClose(); + } + }); + buttonPane.add(saveButton); + + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + closeTheWindow(); + } + }); + buttonPane.add(cancelButton); + } + + /** + * Create a pane that has a list of objects. + * + * + * @param parentFrame parent frame for JPanel, used to close parent frame + * @param items list of items to display, must be at least one + * item + * @param selectedItemsIndexes selected items indexes + * @param selectedListsSetter must be not null, invoked if user saves + * selections/choices + */ + @SuppressWarnings("unchecked") + public JListPane(JFrame parentFrame, Object [] items, int[] selectedItemsIndexes, ISelectedListsSetter selectedListsSetter) { + this(); + + if (selectedListsSetter == null) { + throw new IllegalArgumentException("selectedListsSetter is null"); + } + if (parentFrame == null) { + throw new IllegalArgumentException("parentFrame is null"); + } + + if (items == null) { + throw new IllegalArgumentException("items is null"); + } + + if (items.length == 0) { + throw new IllegalArgumentException("No items in list"); + } + + this.parentFrame = parentFrame; + theList.removeAll(); + + theList.setListData(items); + + this.selectedListsSetter = selectedListsSetter; + + if (selectedItemsIndexes != null) { + holdSelectedIndexes = selectedItemsIndexes; + theList.setSelectedIndices(selectedItemsIndexes); + } + } + + @SuppressWarnings("unchecked") + protected void closeTheWindow() { + + if (isChanged()) { + + int result = FrameUtilities.yesNoCancelDialog(parentFrame, "Selection changed, save selection?", + "Save selection?"); + if (result == JOptionPane.YES_OPTION) { + selectedListsSetter.setSelectedValuesList(theList.getSelectedValuesList(), theList.getSelectedIndices()); + } + } + + if (parentFrame != null) { + parentFrame.setVisible(false); + parentFrame.dispose(); + } + } + + private boolean isChanged() { + int numSelected = theList.getModel().getSize(); + return numSelected != holdSelectedIndexes.length; + } + + @SuppressWarnings("unchecked") + protected void saveAndClose() { + + selectedListsSetter.setSelectedValuesList(theList.getSelectedValuesList(), theList.getSelectedIndices()); + + if (parentFrame != null) { + parentFrame.setVisible(false); + parentFrame.dispose(); + } + } + + @Override + public String getPluginTitle() { + return "generic JList picker"; + } + + public int[] getSelectedItemIndices() { + return theList.getSelectedIndices(); + } + +} diff --git a/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java b/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java new file mode 100644 index 000000000..b3f6db14d --- /dev/null +++ b/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java @@ -0,0 +1,877 @@ +// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +package edu.csus.ecs.pc2.ui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.logging.Level; + +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.border.TitledBorder; +import javax.swing.filechooser.FileFilter; + +import edu.csus.ecs.pc2.VersionInfo; +import edu.csus.ecs.pc2.core.ClipboardUtilities; +import edu.csus.ecs.pc2.core.FileUtilities; +import edu.csus.ecs.pc2.core.IInternalController; +import edu.csus.ecs.pc2.core.log.Log; +import edu.csus.ecs.pc2.core.model.ClientSettings; +import edu.csus.ecs.pc2.core.model.IInternalContest; +import edu.csus.ecs.pc2.core.model.Language; +import edu.csus.ecs.pc2.core.model.Problem; +import edu.csus.ecs.pc2.list.ListUtilities; +import edu.csus.ecs.pc2.list.SubmissionSampleLocation; +import edu.csus.ecs.pc2.list.SubmissionSolutionList; +import edu.csus.ecs.pc2.ui.team.QuickSubmitter; + +/** + * A UI that to submit files found in a CDP. + * + * + * @author Douglas A. Lane, PC^2 Team, pc2@ecs.csus.edu + */ +public class SubmitSampleRunsPane extends JPanePlugin { + + /** + * ClientSettings key for CDP Path + */ + private static final String CUSTOM_SUBMIT_SAMPLE_CDP_PATH = "CustomSubmitSampleCDPPath"; + + private static final long serialVersionUID = -8862440024499524533L; + + private JTextField cdpTextField; + + private JLabel messageLabel; + + private JCheckBox checkBoxSubmitYesSamples; + + private JCheckBox checkBoxSubmitFailingSamples; + + private QuickSubmitter submitter = new QuickSubmitter(); + + private JTextArea textArea; + + private SimpleDateFormat hhMMSSformatter = new SimpleDateFormat("hh:mm:ss"); + + private int linenumber = 0; + /** + * @wbp.nonvisual location=162,159 + */ + private final ButtonGroup judgingTypesButtonGroup = new ButtonGroup(); + + private final ButtonGroup problemsButtonGroup = new ButtonGroup(); + + private final ButtonGroup languagesButtonGroup = new ButtonGroup(); + + + /** + * List of selected solutions names and dirs. + */ + private SubmissionSolutionList submissionSolutionList = null; + + /** + * List of selected Problems. + * + */ + private List selectedProblemList = null; + + private List selectedLanguageList = null; + + private int[] selectedJudgingTypeIndexes; + + private int[] selectedProblemsIndexes; + + private int[] selectedLanguagesIndexes; + + private JLabel selectedNosLabel = new JLabel("None selected"); + + private JRadioButton submitAllJudgingTypesRadioButton = new JRadioButton("Submit All"); + + private JRadioButton submitSelectedJudgingTypeRadioButton = new JRadioButton("Submit Selected"); + + private JCheckBox checkBoxProblems = null; + + private JRadioButton selecteAllProblemsRadioButton = null; + private JRadioButton submitAllProblemsRadioButton; + + private JRadioButton submitSelectedProblems = null; + private JRadioButton submitSelectedProblemsRadioButton; + + private JLabel selectedProblemsLabel = null; + + private JButton selectProblemsButton = null; + + private JCheckBox checkBoxLanguage = null; + + private JRadioButton selecteAllLanguages = null; + private JRadioButton submitAllLanguagesRadioButton; + + private JRadioButton submitSelectedLanguages = null; + private JRadioButton submitSelectedLanguagesRadioButton; + + private JLabel selectedLanguagesLabel = null; + + private JButton selectLanguageButton = null; + + + private Log log; + + // TODO 232 remove debug22Flag + private boolean debug22Flag = false; + + // TODO On Admin update of Languages or Update of Problems - clear selected index arrays + + public SubmitSampleRunsPane() { + super(); + setLayout(new BorderLayout(0, 0)); + + JPanel centerPane = new JPanel(); + centerPane.setLayout(new BorderLayout()); + add(centerPane, BorderLayout.CENTER); + + JSplitPane splitPane = new JSplitPane(); + splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); + centerPane.add(splitPane, BorderLayout.CENTER); + + JPanel controlsPane = new JPanel(); + controlsPane.setPreferredSize(new Dimension(400, 400)); + + controlsPane.setLayout(null); + + JLabel cdpConfigDirLabel = new JLabel("CDP config dir"); + cdpConfigDirLabel.setToolTipText("CDP Location for sample source files"); + cdpConfigDirLabel.setHorizontalAlignment(SwingConstants.RIGHT); + cdpConfigDirLabel.setBounds(10, 60, 86, 14); + controlsPane.add(cdpConfigDirLabel); + + cdpTextField = new JTextField(); + cdpTextField.setFont(new Font("Tahoma", Font.PLAIN, 12)); + cdpTextField.setBounds(113, 54, 418, 27); + controlsPane.add(cdpTextField); + cdpTextField.setColumns(10); + + cdpTextField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyPressed(java.awt.event.KeyEvent e) { + if (e.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER) { + if (new File(cdpTextField.getText()).isDirectory()) { + updateCDPDirAndFields(cdpTextField.getText()); + } + } + + } + }); + + messageLabel = new JLabel("message label"); + messageLabel.setFont(new Font("Tahoma", Font.PLAIN, 14)); + messageLabel.setForeground(Color.RED); + messageLabel.setHorizontalAlignment(SwingConstants.CENTER); + messageLabel.setBounds(10, 11, 691, 32); + controlsPane.add(messageLabel); + + checkBoxSubmitYesSamples = new JCheckBox("Submit Yes Samples"); + checkBoxSubmitYesSamples.setSelected(true); + checkBoxSubmitYesSamples.setToolTipText("Only submit AC sample source"); + checkBoxSubmitYesSamples.setBounds(33, 102, 265, 23); + controlsPane.add(checkBoxSubmitYesSamples); + + JButton selectCDPButton = new JButton("..."); + selectCDPButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + selectNewCDP(); + } + }); + selectCDPButton.setToolTipText("Select a different CDP"); + selectCDPButton.setBounds(541, 56, 39, 23); + controlsPane.add(selectCDPButton); + + JPanel LogPanel = new JPanel(); + LogPanel.setSize(new Dimension(400, 400)); + LogPanel.setMinimumSize(new Dimension(400, 400)); + + LogPanel.setLayout(new BorderLayout(0, 0)); + + textArea = new JTextArea(); + textArea.setFont(new Font("Courier New", Font.PLAIN, 13)); + textArea.setSize(new Dimension(360, 360)); + JScrollPane scrollPane = new JScrollPane(textArea); + LogPanel.add(scrollPane, BorderLayout.CENTER); + + JPanel panel = new JPanel(); + panel.setPreferredSize(new Dimension(50, 50)); + FlowLayout flowLayout_1 = (FlowLayout) panel.getLayout(); + flowLayout_1.setHgap(45); + LogPanel.add(panel, BorderLayout.SOUTH); + + JButton clearTextAButton = new JButton("Clear"); + clearTextAButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + clearTextArea(); + } + + }); + panel.add(clearTextAButton); + + JButton copyButton = new JButton("Copy"); + copyButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + ClipboardUtilities.put(textArea.getText()); + } + }); + copyButton.setToolTipText("Copy text into clipboard"); + panel.add(copyButton); + + JPanel bottomPane = new JPanel(); + FlowLayout flowLayout = (FlowLayout) bottomPane.getLayout(); + flowLayout.setHgap(125); + add(bottomPane, BorderLayout.SOUTH); + + JButton submitRunButton = new JButton("Submit"); + submitRunButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + submitSelectedJudgesSolutions(); + } + }); + + JButton resetButton = new JButton("Reset"); + resetButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + resetFields(true); + } + }); + resetButton.setToolTipText("Reset back to default settings"); + bottomPane.add(resetButton); + submitRunButton.setToolTipText("Submit selected sample runs"); + bottomPane.add(submitRunButton); + +// centerPane2.add(controlsPane, BorderLayout.CENTER); + JScrollPane leftSide = new JScrollPane(controlsPane); + + JPanel submitNoSamplesPane = new JPanel(); + submitNoSamplesPane.setBorder(new TitledBorder(null, "", TitledBorder.LEADING, TitledBorder.TOP, null, null)); + FlowLayout fl_submitNoSamplesPane = (FlowLayout) submitNoSamplesPane.getLayout(); + fl_submitNoSamplesPane.setAlignment(FlowLayout.LEFT); + submitNoSamplesPane.setBounds(33, 131, 650, 32); + controlsPane.add(submitNoSamplesPane); + + checkBoxSubmitFailingSamples = new JCheckBox("Submit Failing Samples"); + checkBoxSubmitFailingSamples.setVerticalAlignment(SwingConstants.TOP); + submitNoSamplesPane.add(checkBoxSubmitFailingSamples); + checkBoxSubmitFailingSamples.setSelected(true); + checkBoxSubmitFailingSamples.setToolTipText("Submt all non-AC (Yes) submissions"); + + judgingTypesButtonGroup.add(submitAllJudgingTypesRadioButton); + submitAllJudgingTypesRadioButton.setSelected(true); + judgingTypesButtonGroup.add(submitSelectedJudgingTypeRadioButton); + + submitNoSamplesPane.add(submitAllJudgingTypesRadioButton); + submitNoSamplesPane.add(submitSelectedJudgingTypeRadioButton); + + leftSide.setPreferredSize(new Dimension(230, 230)); + leftSide.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + leftSide.setWheelScrollingEnabled(true); + splitPane.setLeftComponent(leftSide); + + // centerPane2.add(LogPanel, BorderLayout.SOUTH); + JScrollPane logScrollPanel = new JScrollPane(LogPanel); + logScrollPanel.setPreferredSize(new Dimension(60, 60)); + logScrollPanel.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + logScrollPanel.setWheelScrollingEnabled(true); + splitPane.setRightComponent(logScrollPanel); + + + selectedNosLabel.setToolTipText("None selected"); + selectedNosLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + showJudgementTypeList(); + } + }); + submitNoSamplesPane.add(selectedNosLabel); + JButton selectJudementTypesButton = new JButton("Select"); + selectJudementTypesButton.setToolTipText("Select Judgement Types"); + selectJudementTypesButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + showJudgementTypeList(); + } + }); + + submitNoSamplesPane.add(selectJudementTypesButton); + + JLabel lblNewLabel_2 = getWhatsThisOne(); + submitNoSamplesPane.add(lblNewLabel_2); + + JPanel submitNoSamplesPane_1 = new JPanel(); + FlowLayout flowLayout_2 = (FlowLayout) submitNoSamplesPane_1.getLayout(); + flowLayout_2.setAlignment(FlowLayout.LEFT); + submitNoSamplesPane_1.setBorder(new TitledBorder(null, "", TitledBorder.LEADING, TitledBorder.TOP, null, null)); + submitNoSamplesPane_1.setBounds(33, 161, 650, 32); + controlsPane.add(submitNoSamplesPane_1); + + checkBoxProblems = new JCheckBox("Problems"); + checkBoxProblems.setVerticalAlignment(SwingConstants.TOP); + checkBoxProblems.setToolTipText("Select Problems"); + checkBoxProblems.setSelected(true); + submitNoSamplesPane_1.add(checkBoxProblems); + + submitAllProblemsRadioButton = new JRadioButton("Submit All"); + submitAllProblemsRadioButton.setSelected(true); + submitNoSamplesPane_1.add(submitAllProblemsRadioButton); + + submitSelectedProblemsRadioButton = new JRadioButton("Submit Selected"); + submitNoSamplesPane_1.add(submitSelectedProblemsRadioButton); + + selectedProblemsLabel = new JLabel("None selected"); + selectedProblemsLabel.setToolTipText("None selected"); + submitNoSamplesPane_1.add(selectedProblemsLabel); + + selectProblemsButton = new JButton("Select"); + selectProblemsButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + showProblemList(); + } + }); + selectProblemsButton.setToolTipText("Select Problems"); + submitNoSamplesPane_1.add(selectProblemsButton); + + JPanel submitLanguages = new JPanel(); + FlowLayout fl_submitLanguages = (FlowLayout) submitLanguages.getLayout(); + fl_submitLanguages.setAlignment(FlowLayout.LEFT); + submitLanguages.setBorder(new TitledBorder(null, "", TitledBorder.LEADING, TitledBorder.TOP, null, null)); + submitLanguages.setBounds(33, 191, 650, 32); + controlsPane.add(submitLanguages); + + checkBoxLanguage = new JCheckBox("Languages"); + checkBoxLanguage.setVerticalAlignment(SwingConstants.TOP); + checkBoxLanguage.setToolTipText("Select Languages"); + checkBoxLanguage.setSelected(true); + submitLanguages.add(checkBoxLanguage); + + submitAllLanguagesRadioButton = new JRadioButton("Submit All Languages"); + submitAllLanguagesRadioButton.setSelected(true); + submitLanguages.add(submitAllLanguagesRadioButton); + + submitSelectedLanguagesRadioButton = new JRadioButton("Submit Selected"); + submitLanguages.add(submitSelectedLanguagesRadioButton); + + selectedLanguagesLabel = new JLabel("None selected Lang?"); + selectedLanguagesLabel.setToolTipText("None selected"); + submitLanguages.add(selectedLanguagesLabel); + + selectLanguageButton = new JButton("Select"); + selectLanguageButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + showLanguageList(); + } + }); + selectLanguageButton.setToolTipText("Select Problems"); + submitLanguages.add(selectLanguageButton); + + + languagesButtonGroup.add(submitAllLanguagesRadioButton); + languagesButtonGroup.add(submitSelectedLanguagesRadioButton); + + problemsButtonGroup.add(submitAllProblemsRadioButton); + problemsButtonGroup.add(submitSelectedProblemsRadioButton); + + VersionInfo info = new VersionInfo(); + String verstring = info.getBuildNumber() + " x " + info.getPC2Version(); + addLineToTextArea(verstring); + + + + } + + protected void showLanguageList() { + + // TODO 232 show language selection + + Language[] Languages = getContest().getLanguages(); + + if (Languages.length == 0) { + showMessage("No Languagess defined in contest"); + return; + } + + JListFrame selectLanguagessFrame = new JListFrame("Select Languages ", Languages, selectedLanguagesIndexes, new ISelectedListsSetter() { + + @Override + public void setSelectedValuesList(List selectedValuesList, int[] selectedIndices) { + selectedLanguagesIndexes = selectedIndices; + updateLanguagesLabel(selectedValuesList); + } + }); + selectLanguagessFrame.setVisible(true); + } + + + protected void showProblemList() { + + Problem[] problems = getContest().getProblems(); + + if (problems.length == 0) { + showMessage("No problems defined in contest"); + return; + } + + JListFrame selectProblemsFrame = new JListFrame("Select Problems ", problems, selectedProblemsIndexes, new ISelectedListsSetter() { + + @Override + public void setSelectedValuesList(List selectedValuesList, int[] selectedIndices) { + selectedProblemsIndexes = selectedIndices; + updateProblemsLabel(selectedValuesList); + } + }); + selectProblemsFrame.setVisible(true); + } + + protected void updateCDPDirAndFields(String cdpConfigDir) { + try { + File configFile = new File(cdpConfigDir); + String cdpRootDirectory = configFile.getAbsolutePath(); +// if (configFile.getAbsolutePath().endsWith(IContestLoader.CONFIG_DIRNAME)) { +// cdpRootDirectory = configFile.getParent(); +// } + + cdpTextField.setText(cdpRootDirectory); + updateClientCDPPath(cdpRootDirectory); + updateNosLabel(null); + } catch (Exception e) { + log.log(Level.WARNING, "Problem updating CDP Dir", e); + } + } + + /** + * Dialog with question mark ison for info on selecting judgement types. + * @return + */ + private JLabel getWhatsThisOne() { + + String[] messageLines = { + "Selecting judgement types", // + "", // + "Use Select button to select judgement types", // + }; + + return FrameUtilities.getWhatsThisLabel("Selecting judgement samples", messageLines); + } + + /** + * Repopulate submissionSolutionList. + * + * @return + */ + public SubmissionSolutionList getSubmissionSolutionList() { + String cdpPath = cdpTextField.getText(); + + SubmissionSolutionList list = new SubmissionSolutionList(new File(cdpPath)); + Collections.reverse(list); + submissionSolutionList = list; + + return submissionSolutionList; + } + + protected void showJudgementTypeList() { + + if (getSubmissionSolutionList() == null || getSubmissionSolutionList().size() == 0) { + showMessage("No submission judgement types found in dir: "+cdpTextField.getText()); + return; + } + + SubmissionSampleLocation[] listData = toArray(getSubmissionSolutionList()); + + JListFrame selectNoSolutionsFrame = new JListFrame("Select No/Failed Judges solutions", listData, selectedJudgingTypeIndexes, new ISelectedListsSetter() { + + @Override + public void setSelectedValuesList(List selectedValuesList, int[] selectedIndices) { + selectedJudgingTypeIndexes = selectedIndices; + updateNosLabel(selectedValuesList); + } + }); + selectNoSolutionsFrame.setVisible(true); + } + + private SubmissionSampleLocation[] toArray(SubmissionSolutionList list) { + return (SubmissionSampleLocation[]) list.toArray(new SubmissionSampleLocation[list.size()]); + } + + /** + * Update selected languages label and selected language list + * @param valuesList + */ + protected void updateLanguagesLabel(List valuesList) { + if (valuesList == null || valuesList.size() == 0) { + selectedLanguagesLabel.setText("None selected"); + selectedLanguagesLabel.setToolTipText("None selected"); + } else { + selectedLanguagesLabel.setText(valuesList.size()+" selected"); + selectedLanguagesLabel.setToolTipText(Arrays.toString(valuesList.toArray())); + + selectedLanguageList = new ArrayList(); + valuesList.forEach((lang) -> {selectedLanguageList.add((Language)lang);}); + } + } + + protected void updateProblemsLabel(List valuesList) { + + if (valuesList == null || valuesList.size() == 0) { + selectedProblemsLabel.setText("None selected"); + selectedProblemsLabel.setToolTipText("None selected"); + } else { + + selectedProblemsLabel.setText(valuesList.size()+" selected"); + selectedProblemsLabel.setToolTipText(Arrays.toString(valuesList.toArray())); + + selectedProblemList = new ArrayList(); + valuesList.forEach((prob) -> {selectedProblemList.add((Problem)prob);}); + } + } + + protected void updateNosLabel(List valuesList) { + + if (valuesList == null || valuesList.size() == 0) { + selectedNosLabel.setText("None selected"); + selectedNosLabel.setToolTipText("None selected"); + } else { + + selectedNosLabel.setText(valuesList.size() + " selected"); + selectedNosLabel.setToolTipText(Arrays.toString(valuesList.toArray())); + submissionSolutionList = new SubmissionSolutionList(); + + // update/load selected items into submissionSolutionList + valuesList.forEach((subSL) -> { + submissionSolutionList.add((SubmissionSampleLocation) subSL); + }); + + } + } + + protected void clearTextArea() { + textArea.selectAll(); + textArea.replaceSelection(""); + linenumber = 0; + } + + void addLineToTextArea(String s) { + + linenumber++; + String fmtLineNumber = String.format("%4d", linenumber); + + textArea.insert(fmtLineNumber + " " + hhMMSSformatter.format(new Date()) + " " + s + "\n", 0); +// textArea.append(s); + } + + protected void selectNewCDP() { + + File file = selectEntry("Select CDP"); + + File cdpDir = FileUtilities.findCDPConfigDirectory(file); + + if (cdpDir != null) { + updateCDPDirAndFields(cdpDir.getAbsolutePath()); + } else { + + int result = FrameUtilities.yesNoCancelDialog(this, + file.getAbsoluteFile() + " may not be a CDP directory, continue anyways?", "Select CDP"); + if (result == JOptionPane.YES_OPTION) { + updateCDPDirAndFields(file.getAbsolutePath()); + } + } + } + + /** + * Select yaml file/entry. + * + * @param dialogTitle + * @return + */ + protected File selectEntry(String dialogTitle) { + + JFileChooser chooser = new JFileChooser(cdpTextField.getText()); +// chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + FileFilter filterYAML = new FileNameExtensionFilter("YAML document (*.yaml)", "yaml"); + chooser.addChoosableFileFilter(filterYAML); + + chooser.setAcceptAllFileFilterUsed(false); + chooser.setFileFilter(filterYAML); + + int action = chooser.showOpenDialog(this); + chooser.setDialogTitle(dialogTitle); + + switch (action) { + case JFileChooser.APPROVE_OPTION: + File file = chooser.getSelectedFile(); + return file; + case JFileChooser.CANCEL_OPTION: + case JFileChooser.ERROR_OPTION: + default: + break; + } + return null; + + } + + void updateClientCDPPath(String path) { + ClientSettings settings = getContest().getClientSettings(); + if (settings == null) { + settings = new ClientSettings(getContest().getClientId()); + } + settings.put(CUSTOM_SUBMIT_SAMPLE_CDP_PATH, path); + + getController().updateClientSettings(settings); + } + + private void xlog(String string) { + System.out.println(string); + addLineToTextArea(string); + } + + protected String getClientCDPPath() { + + ClientSettings settings = getContest().getClientSettings(); + if (settings != null) { + String path = settings.getProperty(CUSTOM_SUBMIT_SAMPLE_CDP_PATH); + if (path != null) { + return path; + } + } + + return null; + } + + /** + * Reset fields back to default values + * + * @param usingGui + */ + protected void resetFields(boolean isUsingGui) { + + + selectedJudgingTypeIndexes = new int[0]; + selectedProblemsIndexes = new int[0]; + selectedLanguagesIndexes = new int[0]; + + checkBoxSubmitYesSamples.setSelected(true); + checkBoxSubmitFailingSamples.setSelected(true); + + checkBoxLanguage.setSelected(true); + checkBoxProblems.setSelected(true); + + submitAllJudgingTypesRadioButton.setSelected(true); + submitAllProblemsRadioButton.setSelected(true); + submitAllLanguagesRadioButton.setSelected(true); + + String cdpPath = getContest().getContestInformation().getJudgeCDPBasePath(); + + String clientPath = getClientCDPPath(); + + if (clientPath != null && isUsingGui) { + int result = FrameUtilities.yesNoCancelDialog(this, "Overwrite locally saved CDP path with this (default) " + cdpPath, + "Replace CDP Path?"); + if (result == JOptionPane.NO_OPTION) { + cdpPath = clientPath; + } + } + + cdpTextField.setText(cdpPath); + +// getController().updateClientSettings(settings);; + + } + + /** + * Submit sample solutions. + */ + protected void submitSelectedJudgesSolutions() { + showMessage(""); + + String warningMessage = verifyCDP (cdpTextField.getText()); + if (warningMessage != null) { + // let the user know that the CDP selected may not work + FrameUtilities.showMessage(this, "Trying to use an invalid CDP?", warningMessage); + } + + List allFiles = ListUtilities.getAllJudgeSampleSubmissionFilenamesFromCDP(getContest(), cdpTextField.getText()); + + if (allFiles.size() == 0) { + FrameUtilities.showMessage(this, "No Runs", "No Runs found under " + cdpTextField.getText()); + return; + } + + boolean submitYesSamples = checkBoxSubmitYesSamples.isSelected(); + boolean submitNoSamples = checkBoxSubmitFailingSamples.isSelected(); + + if (!submitYesSamples && !submitNoSamples) { + FrameUtilities.showMessage(this, "No Runs", "Select either Yes or Failed runs"); + return; + } + + List files = new ArrayList(); + + files = QuickSubmitter.filterRuns(allFiles, submitYesSamples, submitNoSamples); + + if (submitNoSamples && submitSelectedJudgingTypeRadioButton.isSelected()) { + if (submitSelectedJudgingTypeRadioButton.isSelected()) { + // if they selected the radio button for selected, they should select at least + if (selectedJudgingTypeIndexes == null || selectedJudgingTypeIndexes.length == 0) { + FrameUtilities.showMessage(this, "No Judging Types selected", "No Judging Types selected, select at least one"); + return; + } + + // fitler by judging type (accepted, wrong_answer, etc.) + files = ListUtilities.filterByJudgingTypes(files, submissionSolutionList); + } + } + + if (checkBoxProblems.isSelected() ) { + if (submitSelectedProblemsRadioButton.isSelected()) { + // submissions may be filtered by problem + + if (selectedProblemsIndexes == null || selectedProblemsIndexes.length == 0) { + FrameUtilities.showMessage(this, "No Problem selected", "No Problems selected, select at least one"); + return; + } + + // filter list by problem name + files = ListUtilities.filterByProblems (files, selectedProblemList); + + } + } + + if (checkBoxLanguage.isSelected()) { + // submissions may be filtered by language + + if (submitSelectedLanguagesRadioButton.isSelected()) { + if (selectedLanguagesIndexes == null || selectedLanguagesIndexes.length == 0) { + FrameUtilities.showMessage(this, "No Language selected", "No Languages selected, select at least one"); + return; + + } + + files = ListUtilities.filterByLanguages(files, getContest(), selectedLanguageList); + } + } + + + int count = 0; + for (File file : files) { + count++; + xlog("Will submit #" + count + " file =" + file.getAbsolutePath()); + } + + if (count == 0) { + showMessage("There are no CDP samples source files under " + cdpTextField.getText()); + return; + } + + int result = FrameUtilities.yesNoCancelDialog(this, "Submit " + files.size() + " sample submissions?", + "Submit CDP submissions"); + + if (result == JOptionPane.YES_OPTION) { + /** + * This will submit each file found + */ + submitter.sendSubmissions(files); + + showMessage("Submitted " + files.size() + " runs."); + } + + + } + + /** + * Check whether cdpDir and model match + * @param cdpDir base dir for CDP, parent dir for config/ dir + * @return null if no issues, else a warning message about a diffence between model and cdpDir + */ + private String verifyCDP(String cdpDir) { + // TODO 232 compare problems in CDP with problems in model + return null; + } + + /** + * Returns the list of filenames that end in extension + * + * @param files + * @param extension + * @return + */ + public static List filterSource(List files, String extension) { + + List list = new ArrayList(); + for (File file : files) { + if (file.getName().endsWith(extension)) { + list.add(file); + } + } + return list; + } + + @Override + public String getPluginTitle() { + return "Submitter Pane"; + } + + @Override + public void setContestAndController(IInternalContest inContest, IInternalController inController) { + super.setContestAndController(inContest, inController); + + resetFields(false); + + String cdpPath = getContest().getContestInformation().getJudgeCDPBasePath(); + String clientPath = getClientCDPPath(); + + if (clientPath != null) { + cdpPath = clientPath; + } + + xlog("CDP dir is now at " + cdpPath); + cdpTextField.setText(cdpPath); + + showMessage(""); + + submitter.setContestAndController(inContest, inController); + + + log = inController.getLog(); + + } + + public void showMessage(final String message) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + xlog(message); + messageLabel.setText(message); + messageLabel.setToolTipText(message); + } + }); + } + + +} // @jve:decl-index=0:visual-constraint="10,10" diff --git a/src/edu/csus/ecs/pc2/ui/SubmitSubmissionsPane.java b/src/edu/csus/ecs/pc2/ui/SubmitSubmissionsPane.java index 7ac40c735..ebe44a2df 100644 --- a/src/edu/csus/ecs/pc2/ui/SubmitSubmissionsPane.java +++ b/src/edu/csus/ecs/pc2/ui/SubmitSubmissionsPane.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2019 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.ui; import java.awt.Color; diff --git a/src/edu/csus/ecs/pc2/ui/server/ServerView.java b/src/edu/csus/ecs/pc2/ui/server/ServerView.java index 1aba3328e..11e215672 100644 --- a/src/edu/csus/ecs/pc2/ui/server/ServerView.java +++ b/src/edu/csus/ecs/pc2/ui/server/ServerView.java @@ -58,6 +58,7 @@ import edu.csus.ecs.pc2.ui.ProfilesPane; import edu.csus.ecs.pc2.ui.ReportPane; import edu.csus.ecs.pc2.ui.SitesPane; +import edu.csus.ecs.pc2.ui.SubmitSampleRunsPane; import edu.csus.ecs.pc2.ui.UIPlugin; import java.awt.Dimension; @@ -525,6 +526,9 @@ public void setContestAndController(IInternalContest inContest, IInternalControl if (Utilities.isDebugMode()) { try { + SubmitSampleRunsPane submitSampleRunsPane = new SubmitSampleRunsPane(); + addUIPlugin(getMainTabbedPane(), "Submit Samples", submitSampleRunsPane); + PacketMonitorPane packetMonitorPane = new PacketMonitorPane(); addUIPlugin(getMainTabbedPane(), "Packets", packetMonitorPane); From d406ed3474d671c06b5edf0b6b76c429aa323b71 Mon Sep 17 00:00:00 2001 From: John Buck Date: Wed, 12 Jun 2024 22:30:04 -0400 Subject: [PATCH 02/10] i_232 overhaul of @lane55 's code Added compare GUI to @lane55 's quick-judge submitter code. Refactored some classes he wrote. --- .../csus/ecs/pc2/core/LanguageUtilities.java | 52 +- src/edu/csus/ecs/pc2/core/model/Filter.java | 53 + src/edu/csus/ecs/pc2/core/model/Language.java | 47 + .../imports/ccs/ContestSnakeYAMLLoader.java | 6 +- .../ecs/pc2/imports/ccs/IContestLoader.java | 102 +- src/edu/csus/ecs/pc2/list/ListUtilities.java | 110 +- .../csus/ecs/pc2/list/SubmissionSample.java | 87 + .../pc2/list/SubmissionSampleLocation.java | 53 +- .../ecs/pc2/list/SubmissionSolutionList.java | 113 +- src/edu/csus/ecs/pc2/ui/EditFilterFrame.java | 61 +- src/edu/csus/ecs/pc2/ui/EditFilterPane.java | 92 ++ .../csus/ecs/pc2/ui/SubmitSampleRunsPane.java | 1449 ++++++++++------- .../ecs/pc2/ui/SubmitSubmissionsPane.java | 38 +- .../ecs/pc2/ui/admin/AdministratorView.java | 146 +- .../csus/ecs/pc2/ui/server/ServerView.java | 192 ++- .../csus/ecs/pc2/ui/team/QuickSubmitter.java | 118 +- 16 files changed, 1764 insertions(+), 955 deletions(-) create mode 100644 src/edu/csus/ecs/pc2/list/SubmissionSample.java diff --git a/src/edu/csus/ecs/pc2/core/LanguageUtilities.java b/src/edu/csus/ecs/pc2/core/LanguageUtilities.java index a73f1adbe..7f9d90867 100644 --- a/src/edu/csus/ecs/pc2/core/LanguageUtilities.java +++ b/src/edu/csus/ecs/pc2/core/LanguageUtilities.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.core; import edu.csus.ecs.pc2.core.model.IInternalContest; @@ -6,32 +6,15 @@ /** * Utility methods for languages - * + * * @author Douglas A. Lane */ public class LanguageUtilities { - - /** - * List of language extensions and their full or partial language display name - */ - public static final String[][] LANGUAGE_LIST = { // - { "java", "Java" }, // - { "kt", "Kotlin" }, // - { "cpp", "C++" }, // - { "cc", "C++" }, // - { "C", "C++" }, // - { "c++", "C++" }, // - { "py", "Python" }, // - { "cs", "Mono" }, // - { "pl", "Perl" }, // - // match c extension last, otherwisse would match C for C++ languages - { "c", "C" }, // - }; /** * get file extension. - * + * * @param filename * @return file extension if no period found returns null */ @@ -45,7 +28,7 @@ public static String getExtension(String filename) { /** * Match a contest Language for the input extension. - * + * * @param myContest contest model * @param filename base name file or full path name. * @return @@ -57,34 +40,17 @@ public static Language guessLanguage(IInternalContest myContest, String filename /** * Match a contest Language for the input extension. - * + * * @param inContest contest model * @param extension the extension without period, ex cpp * @return null if does not match any language title */ public static Language matchFirstLanguage(IInternalContest inContest, String extension) { - Language[] lang = inContest.getLanguages(); - - /** - * Partial or complete display name - */ - String displayName = extension; - - for (String[] row : LANGUAGE_LIST) { - String fileExtension = row[0]; - String dispName = row[1]; - - if (fileExtension.equals(extension)) { - displayName = dispName; - break; - } - } - - displayName = displayName.toLowerCase(); + Language[] allLangs = inContest.getLanguages(); - for (Language language : lang) { - if (language.getDisplayName().toLowerCase().indexOf(displayName) != -1) { - return language; + for(Language lang : allLangs) { + if(lang.getExtensions().contains(extension)) { + return(lang); } } return null; diff --git a/src/edu/csus/ecs/pc2/core/model/Filter.java b/src/edu/csus/ecs/pc2/core/model/Filter.java index 3b74f3146..639e2e69a 100644 --- a/src/edu/csus/ecs/pc2/core/model/Filter.java +++ b/src/edu/csus/ecs/pc2/core/model/Filter.java @@ -2,6 +2,7 @@ package edu.csus.ecs.pc2.core.model; import java.io.Serializable; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -183,6 +184,9 @@ public class Filter implements Serializable { private boolean filteringGroups = false; + private HashSet customItemHash = new HashSet(); + private boolean filteringCustom = false; + /** * filtering for this site only */ @@ -1033,6 +1037,21 @@ public ClientType.Type[] getClientTypes() { return elementIds; } + /** + * Get list of custom item objects + * + * @return list of objects + */ + public ArrayList getCustomList() { + ArrayList items = new ArrayList(); + + customItemHash.forEach((custItem) -> { + items.add(custItem); + }); + + return items; + } + public void setUsingRunStatesFilter(boolean turnOn) { filteringRunStates = turnOn; } @@ -1210,6 +1229,32 @@ public void clearClarificationStateList() { clarificationStateHash = new Hashtable(); } + /** + * + * @param o Object of the string to use to attempt the lookup in the hashset + * @return true of the string is in the custom item hashset + */ + public boolean matches(Object o) { + if(filteringCustom) { + return customItemHash.contains(o.toString()); + } + return(true); + } + + /** + * + * @param o adds the string value of o to the custom item hash + */ + public void addCustomItem(Object o) { + customItemHash.add(o.toString()); + filteringCustom = true; + } + + public void clearCustomItems() { + customItemHash.clear(); + filteringCustom = false; + } + @Override public String toString() { @@ -1297,6 +1342,14 @@ public void setFilteringAccounts(boolean filteringAccounts) { this.filteringAccounts = filteringAccounts; } + public boolean isFilteringCustom() { + return filteringCustom; + } + + public void setFilteringCustom(boolean filtCustom) { + filteringCustom = filtCustom; + } + public void setFilterOff() { filterEnabled = false; } diff --git a/src/edu/csus/ecs/pc2/core/model/Language.java b/src/edu/csus/ecs/pc2/core/model/Language.java index d33455fad..8fd3b939d 100644 --- a/src/edu/csus/ecs/pc2/core/model/Language.java +++ b/src/edu/csus/ecs/pc2/core/model/Language.java @@ -1,6 +1,8 @@ // Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.core.model; +import java.util.ArrayList; + import edu.csus.ecs.pc2.core.StringUtilities; import edu.csus.ecs.pc2.core.log.StaticLog; @@ -27,10 +29,15 @@ public class Language implements IElementObject { * ICPC contests. JB 03/20/2024 */ public static final String CLICS_LANGID_JAVA = "java"; + private static final String [] DEFAULT_EXT_JAVA = { "java" }; public static final String CLICS_LANGID_KOTLIN = "kotlin"; + private static final String [] DEFAULT_EXT_KOTLIN = { "kt" }; public static final String CLICS_LANGID_PYTHON3 = "python3"; + private static final String [] DEFAULT_EXT_PYTHON3 = { "py" }; public static final String CLICS_LANGID_C = "c"; + private static final String [] DEFAULT_EXT_C = { "c" }; public static final String CLICS_LANGID_CPP = "cpp"; + private static final String [] DEFAULT_EXT_CPP = { "cc", "cpp", "cxx", "c++" }; /** * Title for the Language. @@ -81,6 +88,8 @@ public class Language implements IElementObject { private String id = ""; + private ArrayList extensions = new ArrayList(); + public Language(String displayName) { super(); this.displayName = displayName; @@ -274,9 +283,47 @@ public boolean isUsingJudgeProgramExecuteCommandLine() { public void setID(String newId) { this.id = newId; + // set default extensions for the language based on its CLICS id + if(extensions.isEmpty()) { + String [] ext = null; + if(newId.equals(CLICS_LANGID_C)) { + ext = DEFAULT_EXT_C; + } else if(newId.equals(CLICS_LANGID_CPP)) { + ext = DEFAULT_EXT_CPP; + } else if(newId.equals(CLICS_LANGID_PYTHON3)) { + ext = DEFAULT_EXT_PYTHON3; + } else if(newId.equals(CLICS_LANGID_JAVA)) { + ext = DEFAULT_EXT_JAVA; + } else if(newId.equals(CLICS_LANGID_KOTLIN)) { + ext = DEFAULT_EXT_KOTLIN; + } + if(ext != null) { + copyExtensions(ext); + } + } } public String getID() { return id; } + + public void setExtensions(ArrayList exts) { + extensions.clear(); + extensions.addAll(exts); + } + + public ArrayList getExtensions() { + return(extensions); + } + + /** + * Utility method to convert between a string array and ArrayList + * + * @param exts array of strings to convert + */ + private void copyExtensions(String [] exts) { + for(String ext : exts) { + extensions.add(ext); + } + } } diff --git a/src/edu/csus/ecs/pc2/imports/ccs/ContestSnakeYAMLLoader.java b/src/edu/csus/ecs/pc2/imports/ccs/ContestSnakeYAMLLoader.java index eb1ddb349..51553af79 100644 --- a/src/edu/csus/ecs/pc2/imports/ccs/ContestSnakeYAMLLoader.java +++ b/src/edu/csus/ecs/pc2/imports/ccs/ContestSnakeYAMLLoader.java @@ -2018,11 +2018,15 @@ public Language[] getLanguages(String[] yamlLines) { language.setUsingJudgeProgramExecuteCommandLine(false); } - String clicsLanguageId = fetchValue(map, "clics-id"); + String clicsLanguageId = fetchValue(map, CLICS_LANG_ID); if (clicsLanguageId != null){ language.setID(clicsLanguageId); } + Object exts = fetchObjectValue(map, LANG_EXTENSIONS); + if(exts != null && exts instanceof ArrayList) { + language.setExtensions((ArrayList)exts); + } // SOMEDAY handle interpreted languages, seems it should be in the export if (valid(language, name)) { diff --git a/src/edu/csus/ecs/pc2/imports/ccs/IContestLoader.java b/src/edu/csus/ecs/pc2/imports/ccs/IContestLoader.java index ed07ac4af..2cc905732 100644 --- a/src/edu/csus/ecs/pc2/imports/ccs/IContestLoader.java +++ b/src/edu/csus/ecs/pc2/imports/ccs/IContestLoader.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.imports.ccs; import java.io.File; @@ -16,9 +16,9 @@ /** * Contest Loader interface and Constants. - * + * * Constants and methods used in loading YAML into contest/model. - * + * * @author Douglas A. Lane, PC^2 Team, pc2@ecs.csus.edu */ public interface IContestLoader { @@ -28,21 +28,21 @@ public interface IContestLoader { String DEFAULT_PROBLEM_YAML_FILENAME = "problem.yaml"; String DEFAULT_PROBLEM_SET_YAML_FILENAME = "problemset.yaml"; - + String DEFAULT_PROBLEM_LATEX_FILENAME = "problem.tex"; - + String DEFAULT_ENGLISH_PROBLEM_LATEX_FILENAME = "problem.en.tex"; String DEFAULT_SYSTEM_YAML_FILENAME = "system.yaml"; - + // CDP directories - + String SUBMISSIONS_DIRNAME = "submissions"; - + String CONFIG_DIRNAME = "config"; // Sandbox fields - + final String SANDBOX_PROGRAM_NAME_KEY = "sandbox-program-name"; final String SANDBOX_COMMAND_LINE_KEY = "sandbox-command-line"; @@ -70,33 +70,33 @@ public interface IContestLoader { // reading it from properties. It is here for completeness, and, it happens // to be a required value in the yaml, but we do not enforce that. final String CLICS_CONTEST_PENALTY_TIME = "penalty_time"; - + // Section Names - + String CONTEST_NAME_KEY = "name"; String SHORT_NAME_KEY = "short-name"; String CONTEST_START_TIME_KEY = "start-time"; - + String MAX_OUTPUT_SIZE_K_KEY = "max-output-size-K"; - + String CLICS_MAX_OUTPUT_KEY = "output"; - + String CLICS_TIME_MULTIPLIER_KEY = "time_multiplier"; - + String CLICS_TIME_SAFETY_MARGIN_KEY = "time_safety_margin"; - + final String OUTPUT_PRIVATE_SCORE_DIR_KEY = "output-private-score-dir"; final String OUTPUT_PUBLIC_SCORE_DIR_KEY = "output-public-score-dir"; String CONTEST_DURATION_KEY = "duration"; - + String AUTO_STOP_CLOCK_AT_END_KEY = "auto-stop-clock-at-end"; String SCOREBOARD_FREEZE_KEY = "scoreboard-freeze"; - + String SCOREBOARD_FREEZE_LENGTH_KEY = "scoreboard-freeze-length"; String LANGUAGE_KEY = "languages"; @@ -109,14 +109,14 @@ public interface IContestLoader { * Name for problem set in contest.yaml */ String PROBLEMS_KEY = "problemset"; - + /** * name for problem set in problemset.yaml */ String PROBLEMSET_PROBLEMS_KEY = "problems"; String MANUAL_REVIEW_KEY = "manual-review"; - + String COMPUTER_JUDGING_KEY = "computer-judged"; String ACCOUNTS_KEY = "accounts"; @@ -128,11 +128,11 @@ public interface IContestLoader { String JUDGE_CONFIG_PATH_KEY = "judge-config-path"; String TIMEOUT_KEY = "timeout"; - + final String MEMORY_LIMIT_IN_MEG_KEY = "memory-limit-in-Meg"; - + final String MEMORY_LIMIT_CLICS = "memory"; - + String LIMITS_KEY = "limits"; String PROBLEM_NAME_KEY = "title"; @@ -142,13 +142,13 @@ public interface IContestLoader { String AUTO_JUDGE_KEY = "auto-judging"; String CCS_TEST_MODE = "ccs-test-mode"; - + String LOAD_SAMPLE_JUDGES_DATA = "load-sample-judges-data"; - + String INPUT_KEY = "input"; String PROBLEM_LOAD_DATA_FILES_KEY = "load-data-files"; - + String GROUPS_KEY = "groups"; String DEFAULT_VALIDATOR_KEY = "default-validator"; @@ -156,13 +156,13 @@ public interface IContestLoader { String OVERRIDE_VALIDATOR_KEY = "override-validator"; String VALIDATOR_KEY = "validator"; - + String VALIDATOR_FLAGS_KEY = "validator_flags"; String USING_PC2_VALIDATOR = "use-internal-validator"; String SEND_PRELIMINARY_JUDGEMENT_KEY = "send-prelim-judgement"; - + String STOP_ON_FIRST_FAILED_TEST_CASE_KEY = "stop-on-first-failed-test-case"; String USE_JUDGE_COMMAND_KEY = "use-judge-cmd"; @@ -181,12 +181,16 @@ public interface IContestLoader { String READ_FROM_STDIN_KEY = "readFromSTDIN"; + String CLICS_LANG_ID = "clics-id"; + + String LANG_EXTENSIONS = "extensions"; + /** * output validators directory name. */ final String OUTPUT_VALIDATORS = "output_validators"; - + //keys for YAML entries specifying data for Input Validators: String INPUT_VALIDATOR_KEY = "input_validator"; //the section header for Input Validator info String DEFAULT_INPUT_VALIDATOR_KEY = "defaultInputValidator"; //the key for specifying the type of Input Validator selected by default @@ -197,7 +201,7 @@ public interface IContestLoader { // per problem problem.yaml settings String VALIDATION_TYPE = "validation"; - + String SHOW_OUTPUT_WINDOW = "showOutputWindow"; String SHOW_COMPARE_WINDOW = "showCompare"; @@ -209,13 +213,13 @@ public interface IContestLoader { String USING_CLICS_VALIDATOR = "use-clics-validator"; String USING_CUSTOM_VALIDATOR = "use-custom-validator"; - + String USE_CLICS_CUSTOM_VALIDATOR_INTERFACE = "use-clics-custom-validator-interface"; - + String PC2_EXEC_CMD = "execCmd"; - + String PC2_COMPILER_CMD = "compilerCmd"; - + String CCS_LAST_EVENT_ID_KEY = "ccs-last-event-id"; String CCS_PASSWORD_KEY = "ccs-password"; @@ -225,13 +229,13 @@ public interface IContestLoader { String CCS_URL_KEY = "ccs-url"; String SHADOW_MODE_KEY = "shadow-mode"; - + String ALLOW_MULTIPLE_TEAM_LOGINS_KEY = "allow-multiple-team-logins"; - + String LOAD_ACCOUNTS_FILE_KEY = "load-accounts-file"; /** - * + * * @see ScoreboardVariableReplacer#substituteDisplayNameVariables(String, IInternalContest, edu.csus.ecs.pc2.core.model.Account) */ String TEAM_SCOREBOARD_DISPLAY_FORMAT_STRING = "team-scoreboard-display-format-string"; @@ -242,18 +246,18 @@ public interface IContestLoader { /** * Load contest data from contest.yaml. - * + * * @param contest * @param directoryName * directory to load files from. * @return contest - * + * */ IInternalContest fromYaml(IInternalContest contest, String directoryName); /** * Load contest, optionally load problem data files. - * + * * @param contest * @param directoryName * directory to load files from. @@ -303,20 +307,20 @@ Problem[] getProblems(String[] yamlLines, int seconds, long maxOutputSizeInBytes /** * Are data file contents to ba loaded into configuration?. - * + * * @return true if data files are not external */ boolean isLoadProblemDataFiles(); /** * Load CCS data files, and validator into contest. - * + * * @param contest * @param dataFileBaseDirectory * the directory where the .in and .ans files are found. * @param problem * @param problemDataFiles - * + * */ Problem loadCCSProblemFiles(IInternalContest contest, String dataFileBaseDirectory, Problem problem, ProblemDataFiles problemDataFiles); @@ -337,7 +341,7 @@ Problem[] getProblems(String[] yamlLines, int seconds, long maxOutputSizeInBytes /** * Directory for judge's input/answer files. - * + * * @param yamlDirectory * directory where problem dir/files are located. * @param problem @@ -347,7 +351,7 @@ Problem[] getProblems(String[] yamlLines, int seconds, long maxOutputSizeInBytes /** * Return directory for judge's input/answer files. - * + * * @param yamlDirectory * directory where problem dir/files are located. * @param shortDirName @@ -363,20 +367,20 @@ Problem[] getProblems(String[] yamlLines, int seconds, long maxOutputSizeInBytes * Load contest with settings from file/CDP. * @param contest * @param entry can be CDP directory, contest.yaml file, or other initialize file. - * @throws Exception + * @throws Exception */ IInternalContest initializeContest (IInternalContest contest, File entry) throws Exception; /** * Locates the CDP config directory. - * + * * Attempts to find CDP config directory at: *
  • current directory *
  • parent directory *
  • samps/contests/ directory, ex "mini" finds samps/contests//config - * + * * If no directory found, returns null. - * + * * @param entry * a directory, filename or PC^2 sample CCS contest directory name. * @return null or the location of the CDP config/ directory. diff --git a/src/edu/csus/ecs/pc2/list/ListUtilities.java b/src/edu/csus/ecs/pc2/list/ListUtilities.java index e982bd6ee..faa5d5026 100644 --- a/src/edu/csus/ecs/pc2/list/ListUtilities.java +++ b/src/edu/csus/ecs/pc2/list/ListUtilities.java @@ -1,8 +1,9 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.list; import java.io.File; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import edu.csus.ecs.pc2.core.LanguageUtilities; @@ -14,7 +15,7 @@ /** * A set of utilities that operate on lists. - * + * * @author Douglas A. Lane * */ @@ -22,18 +23,18 @@ public class ListUtilities { /** * Returns list of files that match the SubmissionSolutionList (judging types location/list) - * + * * @param files list of files to be filtered - * @param submissionList a class that manages a number of SubmissionSampleLocation + * @param submissionSolutionList List of types to accept * @return */ - public static List filterByJudgingTypes(List files, SubmissionSolutionList submissionSolutionList) { + public static List filterByJudgingTypes(List files, List submissionSolutionList) { List newFileList = new ArrayList(); for (File file : files) { submissionSolutionList.forEach((subSol) -> { - if (file.getAbsolutePath().contains(File.separator + subSol.getShortDirectoryName() + File.separator)) { + if (file.getAbsolutePath().contains(File.separator + subSol + File.separator)) { newFileList.add(file); } }); @@ -41,10 +42,10 @@ public static List filterByJudgingTypes(List files, SubmissionSoluti return newFileList; } - + /** * Returns list of all files under dir path. - * + * * @param dirName location to fetch files from * @return list of files in and under dirName */ @@ -74,9 +75,9 @@ public static List findAllFiles(String dirName) { /** * Get all CDP judge's sample submission filenames. - * + * * Example files under config\sumit\submissions - * + * * @param mycontest * @param directoryName CDP config/ dir or CDP base directory * @return list of judges sample submissions @@ -86,7 +87,7 @@ public static List getAllJudgeSampleSubmissionFilenamesFromCDP(IInternalCo Problem[] problems = mycontest.getProblems(); List files = new ArrayList<>(); - + String configDir = directoryName + File.separator + IContestLoader.CONFIG_DIRNAME; if (new File(configDir).isDirectory()) { directoryName = configDir; @@ -101,15 +102,65 @@ public static List getAllJudgeSampleSubmissionFilenamesFromCDP(IInternalCo } + HashSet allExts = new HashSet(); + String ext, srcFile; + int ridx; + + // make up hashset of all language extensions + for(Language lang : mycontest.getLanguages()) { + allExts.addAll(lang.getExtensions()); + } + // Reverse scan for uninteresting files and remove them. + for(int i = files.size(); --i >= 0; ) { + srcFile = files.get(i).getName(); + ridx = srcFile.lastIndexOf('.'); + // if no extension on the file, or, it's not in our list of src extensions, drop the file. + if(ridx == -1 || !allExts.contains(srcFile.substring(ridx+1))) { + files.remove(i); + } + } + return files; } + /** + * Gets a list of all the different types of judges' submissions by scanning the submissions folder for + * each problem. ex. accepted, wrong_answer, time_limit_exceeded, other, run_time_exception, etc. + * To qualify as a valid type, the particular folder must contain at least one source file with a known + * extension for the configurationed languages. + * + * @param mycontest The contest + * @param directoryName Where to start looking (config folder) + * @return List of folder basenames + */ + public static List getAllCDPSubmissionTypes(IInternalContest mycontest, String directoryName) { + List files = getAllJudgeSampleSubmissionFilenamesFromCDP(mycontest, directoryName); + String srcName; + int idx; + ArrayList types = new ArrayList(); + HashSet uniqTypes = new HashSet(); + + for(File src : files ) { + srcName = src.getParent(); + idx = srcName.lastIndexOf(File.separator); + if(idx != -1) { + srcName = srcName.substring(idx+1); + } + if(!uniqTypes.contains(srcName)) { + types.add(srcName); + uniqTypes.add(srcName); + } + } + types.sort(null); + return(types); + } + /** * Find files (in CDP) that contain one of the Problems in the list. - * + * */ public static List filterByProblems(List files, List selectedProblemList) { - + List newFileList = new ArrayList(); for (File file : files) { @@ -123,15 +174,15 @@ public static List filterByProblems(List files, List select return newFileList; } - + /** - * Find all accepted/Yes filenames with "accepted" in file list. - * + * Find all accepted/Yes filenames with "accepted" in file list. + * * @param files list of files * @return list of files that have a directory name of "accepted" embedded in their path. */ public static List filterYesJudgingType (List files) { - + List newFileList = new ArrayList(); for (File file : files) { @@ -142,25 +193,26 @@ public static List filterYesJudgingType (List files) { return newFileList; } - + public static List filterByLanguages(List files, IInternalContest contest, List selectedLanguageList) { - + List newFileList = new ArrayList(); for (File file : files) { - selectedLanguageList.forEach((lang) -> { - - // TODO match by extention - Language language = LanguageUtilities.matchFirstLanguage(contest, LanguageUtilities.getExtension(file.getName())); - - if (lang.getDisplayName().contentEquals(lang.getDisplayName())) { - newFileList.add(file); - } - }); + Language language = LanguageUtilities.guessLanguage(contest, file.getName()); + + if(language != null) { + selectedLanguageList.forEach((lang) -> { + + // Should use clics_id, but, I suppose it may not be there - is it required? -- JB + if (lang.getDisplayName().contentEquals(language.getDisplayName())) { + newFileList.add(file); + } + }); + } } return newFileList; } - } diff --git a/src/edu/csus/ecs/pc2/list/SubmissionSample.java b/src/edu/csus/ecs/pc2/list/SubmissionSample.java new file mode 100644 index 000000000..5dedb8a6f --- /dev/null +++ b/src/edu/csus/ecs/pc2/list/SubmissionSample.java @@ -0,0 +1,87 @@ +package edu.csus.ecs.pc2.list; + +import java.io.File; + +import edu.csus.ecs.pc2.core.model.ElementId; +import edu.csus.ecs.pc2.core.model.Run; + +public class SubmissionSample { + + private ElementId elementId = null; + private String problemName = null; + private ElementId problem = null; + + private String languageName = null; + private ElementId language = null; + + private String sampleType = null; + + private File srcFile = null; + + private Run run = null; + + public SubmissionSample(String probShortName, ElementId prob, String langName, ElementId lang, String type, File srcFile) { + elementId = new ElementId(getClass().getName()); + problemName = probShortName; + problem = prob; + languageName = langName; + language = lang; + sampleType = type; + this.srcFile = srcFile; + } + + public ElementId getElementId() { + return(elementId); + } + + public void setRun(Run r) { + run = r; + } + + public Run getRun() { + return run; + } + + // JB this is wrong - needs fixing + public boolean isRunForSubmission(Run r) { + + if(srcFile != null) { + return(false); + } + return(false); + } + + public String getProblemName() { + return problemName; + } + + public ElementId getProblem() { + return problem; + } + + public String getLanguageName() { + return languageName; + } + + public ElementId getLanguage() { + return language; + } + + public String getSampleType() { + return sampleType; + } + + public File getSourceFile() { + return srcFile; + } + + @Override + public String toString() { + String str = getProblemName() + " (" + getSampleType() + ") Language: " + getLanguageName() + ": " + getSourceFile().getAbsolutePath(); + Run run = getRun(); + if(run != null) { + str = str + " (RunId " + run.getNumber() + ")"; + } + return(str); + } +} diff --git a/src/edu/csus/ecs/pc2/list/SubmissionSampleLocation.java b/src/edu/csus/ecs/pc2/list/SubmissionSampleLocation.java index c157676b1..5889550bc 100644 --- a/src/edu/csus/ecs/pc2/list/SubmissionSampleLocation.java +++ b/src/edu/csus/ecs/pc2/list/SubmissionSampleLocation.java @@ -1,41 +1,76 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.list; +import edu.csus.ecs.pc2.clics.CLICSJudgementType; + /** * A single entry of a judge's solution locations. - * + * * @author Douglas A. Lane */ public class SubmissionSampleLocation implements Comparable { + // These are the folders defined by the clics spec for the location of judge's submissions + // (Except for compile error - that is not in the clics spec) + public static final String CLICS_SUBMISSION_LOCATION_AC = "accepted"; + public static final String CLICS_SUBMISSION_LOCATION_WA = "wrong_answer"; + public static final String CLICS_SUBMISSION_LOCATION_RTE = "run_time_error"; + public static final String CLICS_SUBMISSION_LOCATION_TLE = "time_limit_exceeded"; + public static final String CLICS_SUBMISSION_LOCATION_CE = "compile_error"; + + public static final String [][] CLICS_SUBMISSION_TO_ACRONYM = { + { CLICS_SUBMISSION_LOCATION_AC, CLICSJudgementType.CLICS_BIG5.AC.toString() }, + { CLICS_SUBMISSION_LOCATION_WA, CLICSJudgementType.CLICS_BIG5.WA.toString() }, + { CLICS_SUBMISSION_LOCATION_RTE, CLICSJudgementType.CLICS_BIG5.RTE.toString() }, + { CLICS_SUBMISSION_LOCATION_TLE, CLICSJudgementType.CLICS_BIG5.TLE.toString() }, + { CLICS_SUBMISSION_LOCATION_CE, CLICSJudgementType.CLICS_BIG5.CE.toString() } + }; + private String title; private String shortDirectoryName; + private String clicsAcronym; /** * A judges solution name and location. - * + * * @param title title for directory, ex. Run Time Error * @param shortDirectoryName base directory name, ex. run_time_error + * @param clicsAcronym Big-5 acronym AC/WA/RTE/TLE/CE */ - public SubmissionSampleLocation(String title, String shortDirectoryName) { + public SubmissionSampleLocation(String title, String shortDirectoryName, String clicsAcronym) { this.title = title; - this.shortDirectoryName = shortDirectoryName;; + this.shortDirectoryName = shortDirectoryName; + if(clicsAcronym == null || clicsAcronym.isEmpty()) { + this.clicsAcronym = "NA"; + } else { + this.clicsAcronym = clicsAcronym; + } } - + public String getTitle() { return title; } - + public String getShortDirectoryName() { return shortDirectoryName; } + public String getCLICSAcronym() { + return clicsAcronym; + } + @Override public String toString() { + String strVal; + if (title.length() > 0) { - return title + " ("+shortDirectoryName+")"; + strVal = title + " ("+shortDirectoryName+")"; } else { - return shortDirectoryName; + strVal = shortDirectoryName; + } + if(!clicsAcronym.isEmpty()) { + strVal = strVal + " : " + clicsAcronym; } + return strVal; } @Override diff --git a/src/edu/csus/ecs/pc2/list/SubmissionSolutionList.java b/src/edu/csus/ecs/pc2/list/SubmissionSolutionList.java index 303e5eacf..cf49f21e8 100644 --- a/src/edu/csus/ecs/pc2/list/SubmissionSolutionList.java +++ b/src/edu/csus/ecs/pc2/list/SubmissionSolutionList.java @@ -1,42 +1,50 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.list; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Hashtable; import java.util.List; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; -import edu.csus.ecs.pc2.imports.ccs.IContestLoader; +import edu.csus.ecs.pc2.core.model.IInternalContest; /** * List of judge's solutions - * + * * @author Douglas A. Lane * */ public class SubmissionSolutionList extends ArrayList { /** - * + * */ private static final long serialVersionUID = 6231245379952020474L; - + + private Hashtable submissionDirectoryToAcronym = new Hashtable(); + public SubmissionSolutionList() { super(); + createSubmissionDirectoryMap(); } - - public SubmissionSolutionList(File cdpPath) { + + public SubmissionSolutionList(IInternalContest mycontest, String cdpPath) { super(); - loadCDPSampleSubmissionList(cdpPath); + createSubmissionDirectoryMap(); + loadCDPSampleSubmissionList(mycontest, cdpPath); + } + + private void createSubmissionDirectoryMap() { + // Create quick access to look up acronym for folder + for(String [] subFolderRow : SubmissionSampleLocation.CLICS_SUBMISSION_TO_ACRONYM) { + submissionDirectoryToAcronym.put(subFolderRow[0], subFolderRow[1]); + } } - /** * get all directories and child directories (recurses). - * + * * @param directory * @return list of directory names */ @@ -46,9 +54,9 @@ public static List getAllDirectoryEntries(String directory) { ArrayList list = new ArrayList<>(); File[] files = new File(directory).listFiles(); - + if (files != null) { - + for (File entry : files) { if (entry.isDirectory()) { list.add(directory + File.separator + entry.getName()); @@ -61,70 +69,31 @@ public static List getAllDirectoryEntries(String directory) { return list; } - + /** + * Lookup the CLICS Big5 acronum for a judge's submission folder + * + * @param dir the folder name + * @return the acronym, or null if the folder is non-standard + */ + public String getAcronymForSubmissionDirectory(String dir) { + if(submissionDirectoryToAcronym.containsKey(dir)) { + return submissionDirectoryToAcronym.get(dir); + } + return null; + } /** * Load Judge's samples judgement types * @param cdpPath - * @throws IOException + * @throws IOException */ // TODO NOW use FileUtilities.getAllDirectoryEntries - private void loadCDPSampleSubmissionList(File cdpPath) { - - SortedMap uniqItems = new TreeMap(); - try { - List entries = getAllDirectoryEntries(cdpPath.getCanonicalPath()); - - String pat = IContestLoader.SUBMISSIONS_DIRNAME; - - for (String dirname : entries) { - try { - // pattern found in dirname but not at the end, eliminates submission at end of string - // only includes subdirectories under submissions/ and not the submissions directory - if (dirname.contains(pat) && dirname.lastIndexOf(pat) != dirname.length() - pat.length()){ - String baseName = new File (dirname).getName(); - SubmissionSampleLocation subLoc = new SubmissionSampleLocation("", baseName); - uniqItems.put(subLoc, subLoc.toString()); - } - } catch (Exception e) { - e.printStackTrace(); // debug 22 - return; // debug 22 - } - } - - } catch (Exception e) { - ; // ignore, do not load any items into list because no match - } - - Set keys = uniqItems.keySet(); - for (SubmissionSampleLocation submissionSampleLocation : keys) { - super.add(submissionSampleLocation); - } - - } - - public void loadDefaultList() { - - String[] initList = { - - "Bad Format ; badformat", // - "Run Time Error ; run_time_error", // - "Run Time Error ; runtime_error", // - "Security Violation ; security_violation", // - "Time Limit ; time_limit", // - "Time Limit Exceeded ; time_limit_exceeded", // - "Wrong Answer ; wrong_answer", // - "Wrong Answer ; wronganswer", // - - }; - - for (String entry : initList) { - String[] fields = entry.split(";"); - String title = fields[0].trim(); - String dirName = fields[1].trim(); + private void loadCDPSampleSubmissionList(IInternalContest contest, String cdpPath) { - super.add(new SubmissionSampleLocation(title, dirName)); - } + List types = ListUtilities.getAllCDPSubmissionTypes(contest, cdpPath); + for(String type : types) { + super.add(new SubmissionSampleLocation("", type, getAcronymForSubmissionDirectory(type))); + } } } diff --git a/src/edu/csus/ecs/pc2/ui/EditFilterFrame.java b/src/edu/csus/ecs/pc2/ui/EditFilterFrame.java index cca71ebee..8952d79c4 100644 --- a/src/edu/csus/ecs/pc2/ui/EditFilterFrame.java +++ b/src/edu/csus/ecs/pc2/ui/EditFilterFrame.java @@ -5,6 +5,7 @@ import java.awt.FlowLayout; import java.awt.event.KeyEvent; import java.io.PrintWriter; +import java.util.ArrayList; import javax.swing.JButton; import javax.swing.JFrame; @@ -20,7 +21,7 @@ /** * Edit a filter. - * + * * @author pc2@ecs.csus.edu * @version $Id$ */ @@ -32,7 +33,7 @@ public class EditFilterFrame extends JFrame implements UIPlugin { // TODO on close button if they say yes, invoke callback. /** - * + * */ private static final long serialVersionUID = 6498270977601785261L; @@ -60,7 +61,7 @@ public class EditFilterFrame extends JFrame implements UIPlugin { /** * This method initializes - * + * */ public EditFilterFrame() { super(); @@ -68,7 +69,7 @@ public EditFilterFrame() { } /** - * + * * @param filter * @param title * @param refreshCallback @@ -96,7 +97,7 @@ private void initialize() { /** * This method initializes mainPane - * + * * @return javax.swing.JPanel */ private JPanel getMainPane() { @@ -111,7 +112,7 @@ private JPanel getMainPane() { /** * This method initializes buttonPane - * + * * @return javax.swing.JPanel */ private JPanel getButtonPane() { @@ -130,7 +131,7 @@ private JPanel getButtonPane() { /** * This method initializes saveButton - * + * * @return javax.swing.JButton */ private JButton getApplyButton() { @@ -140,6 +141,7 @@ private JButton getApplyButton() { applyButton.setToolTipText("Apply this filter to listbox"); applyButton.setMnemonic(java.awt.event.KeyEvent.VK_A); applyButton.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(java.awt.event.ActionEvent e) { updateFilter(editFilterPane.getFilter()); } @@ -187,7 +189,7 @@ protected void dumpFilter(Filter filter2) { /** * This method initializes closeButton - * + * * @return javax.swing.JButton */ private JButton getCloseButton() { @@ -197,6 +199,7 @@ private JButton getCloseButton() { closeButton.setToolTipText("Close this window"); closeButton.setMnemonic(java.awt.event.KeyEvent.VK_C); closeButton.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(java.awt.event.ActionEvent e) { checkForChangesAndExit(); } @@ -206,15 +209,15 @@ public void actionPerformed(java.awt.event.ActionEvent e) { } protected void checkForChangesAndExit() { - - // TODO check for changes in filter. - + + // TODO check for changes in filter. + setVisible(false); } /** * This method initializes editFilterPane - * + * * @return edu.csus.ecs.pc2.ui.EditFilterPane */ private EditFilterPane getEditFilterPane() { @@ -225,16 +228,18 @@ private EditFilterPane getEditFilterPane() { return editFilterPane; } + @Override public void setContestAndController(IInternalContest inContest, IInternalController inController) { this.contest = inContest; this.controller = inController; editFilterPane.setContestAndController(inContest, inController); editFilterPane.setFilter(filter); - + getReportButton().setVisible(Utilities.isDebugMode()); } + @Override public String getPluginTitle() { return "Edit Filter Frame"; } @@ -249,7 +254,7 @@ public void setFilter(Filter filter2) { /** * This method initializes okButton - * + * * @return javax.swing.JButton */ private JButton getOkButton() { @@ -258,6 +263,7 @@ private JButton getOkButton() { okButton.setText("Ok"); okButton.setMnemonic(java.awt.event.KeyEvent.VK_O); okButton.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(java.awt.event.ActionEvent e) { updateFilter(editFilterPane.getFilter()); setVisible(false); @@ -269,21 +275,37 @@ public void actionPerformed(java.awt.event.ActionEvent e) { /** * Show or hide list on edit filter frame. - * + * * @param listName * list to show or hide */ public void addList(ListNames listName) { editFilterPane.addList(listName); } - + public void setDisplayTeamName(DisplayTeamName displayTeamName) { editFilterPane.setDisplayTeamName(displayTeamName); } + /** + * + * @param items custom items to add + */ + public void addCustomItems(ArrayList items) { + editFilterPane.addCustomItems(items); + } + + /** + * + * @param title - title for the custom item check box list + */ + public void setCustomTitle(String title) { + editFilterPane.setCustomTitle(title); + } + /** * If filtering clarification, set this to true. - * @param filteringClarifications + * @param filteringClarifications */ public void setFilteringClarifications(boolean filteringClarifications) { editFilterPane.setFilteringClarifications(filteringClarifications); @@ -291,7 +313,7 @@ public void setFilteringClarifications(boolean filteringClarifications) { /** * This method initializes reportButton - * + * * @return javax.swing.JButton */ private JButton getReportButton() { @@ -300,6 +322,7 @@ private JButton getReportButton() { reportButton.setText("Report"); reportButton.setMnemonic(KeyEvent.VK_R); reportButton.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(java.awt.event.ActionEvent e) { showReport(); } @@ -307,7 +330,7 @@ public void actionPerformed(java.awt.event.ActionEvent e) { } return reportButton; } - + protected void showReport() { FilterReport report = new FilterReport(); report.setFilter(getEditFilterPane().getFilter()); diff --git a/src/edu/csus/ecs/pc2/ui/EditFilterPane.java b/src/edu/csus/ecs/pc2/ui/EditFilterPane.java index 21665541d..cd154328f 100644 --- a/src/edu/csus/ecs/pc2/ui/EditFilterPane.java +++ b/src/edu/csus/ecs/pc2/ui/EditFilterPane.java @@ -4,6 +4,7 @@ import java.awt.BorderLayout; import java.awt.GridLayout; import java.security.InvalidParameterException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.Vector; @@ -16,6 +17,7 @@ import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; +import javax.swing.border.TitledBorder; import edu.csus.ecs.pc2.core.IInternalController; import edu.csus.ecs.pc2.core.list.AccountComparator; @@ -173,8 +175,21 @@ public class EditFilterPane extends JPanePlugin { private JCheckBoxJList clientTypesListBox; // @jve:decl-index=0: + private TitledBorder customPaneBorder = null; + private JPanel customTypePane = null; + + private JScrollPane customTypeScroll = null; + + private DefaultListModel customTypeListModel = new DefaultListModel(); + + private JCheckBoxJList customTypesListBox; + private Permission permission = new Permission(); + private ArrayList customItems = new ArrayList(); + + private String customTitle = "Custom"; + /** * JList names in EditFilterPane. * @@ -233,6 +248,10 @@ public enum ListNames { * */ CLIENT_TYPES, + /** + * + */ + CUSTOM_LIST, } public EditFilterPane() { @@ -687,6 +706,15 @@ public void populateFields() { getToTimeTextField().setText("" + filter.getEndElapsedTime()); } } + + customTypeListModel.removeAllElements(); + for (Object custItem : customItems) { + WrapperJCheckBox wrapperJCheckBox = new WrapperJCheckBox(custItem); + if (filter.isFilteringCustom()) { + wrapperJCheckBox.setSelected(filter.matches(custItem)); + } + customTypeListModel.addElement(wrapperJCheckBox); + } } /** @@ -919,6 +947,16 @@ public Filter getFilter() { } } + filter.clearCustomItems(); + enumeration = customTypeListModel.elements(); + while (enumeration.hasMoreElements()) { + WrapperJCheckBox element = (WrapperJCheckBox) enumeration.nextElement(); + if (element.isSelected()) { + Object object = element.getContents(); + filter.addCustomItem(object); + } + } + filter.clearElapsedTimeRange(); if (getFromTimeTextField().getText().length() > 0){ filter.setStartElapsedTime(Long.parseLong(getFromTimeTextField().getText())); @@ -1045,11 +1083,33 @@ public void addList (ListNames listName){ case CLIENT_TYPES: listsPanel.add(getClientTypePane(), 0); break; + case CUSTOM_LIST: + listsPanel.add(getCustomTypePane(), 0); + break; default: throw new InvalidParameterException("Invalid listNames: " + listName); } } + /** + * + * @param items custom items to add + */ + public void addCustomItems(ArrayList items) { + customItems = items; + } + + /** + * + * @param title - title for the custom item check box list + */ + public void setCustomTitle(String title) { + customTitle = title; + if(customPaneBorder != null) { + customPaneBorder.setTitle(customTitle); + } + } + /** * This method initializes timeRangePane * @@ -1246,6 +1306,38 @@ private JCheckBoxJList getClientTypesListBox () { + public JPanel getCustomTypePane() { + if (customTypePane == null) { + customTypePane = new JPanel(); + customTypePane.setLayout(new BorderLayout()); + customTypePane.setName("customTypePane"); + customPaneBorder = javax.swing.BorderFactory.createTitledBorder(null, customTitle, javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, + javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Dialog", java.awt.Font.BOLD, 12), new java.awt.Color(51, 51, 51)); + customTypePane.setBorder(customPaneBorder); + customTypePane.setSize(new java.awt.Dimension(251, 151)); + customTypePane.add(getCustomTypeScroll(), java.awt.BorderLayout.CENTER); + } + + return customTypePane; + } + + private JScrollPane getCustomTypeScroll() { + if (customTypeScroll == null) { + customTypeScroll = new JScrollPane(); + customTypeScroll.setViewportView(getCustomTypesListBox()); + } + return customTypeScroll; + } + + private JCheckBoxJList getCustomTypesListBox () { + if (customTypesListBox == null) { + customTypesListBox = new JCheckBoxJList(customTypeListModel); + } + return customTypesListBox; + } + + + public JPanel getPermissionsPane() { if (permissionsPane == null) { permissionsPane = new JPanel(); diff --git a/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java b/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java index b3f6db14d..036b46b60 100644 --- a/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java +++ b/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java @@ -1,8 +1,9 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.ui; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; @@ -11,54 +12,72 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; import java.util.List; +import java.util.Timer; +import java.util.TimerTask; import java.util.logging.Level; -import javax.swing.ButtonGroup; import javax.swing.JButton; -import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; -import javax.swing.JRadioButton; import javax.swing.JScrollPane; -import javax.swing.JSplitPane; -import javax.swing.JTextArea; +import javax.swing.JTable; import javax.swing.JTextField; -import javax.swing.ScrollPaneConstants; +import javax.swing.RowSorter; +import javax.swing.RowSorter.SortKey; +import javax.swing.SortOrder; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; -import javax.swing.border.TitledBorder; import javax.swing.filechooser.FileFilter; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumnModel; +import javax.swing.table.TableRowSorter; -import edu.csus.ecs.pc2.VersionInfo; -import edu.csus.ecs.pc2.core.ClipboardUtilities; import edu.csus.ecs.pc2.core.FileUtilities; import edu.csus.ecs.pc2.core.IInternalController; +import edu.csus.ecs.pc2.core.Utilities; +import edu.csus.ecs.pc2.core.list.StringToNumberComparator; import edu.csus.ecs.pc2.core.log.Log; +import edu.csus.ecs.pc2.core.log.StaticLog; +import edu.csus.ecs.pc2.core.model.ClientId; import edu.csus.ecs.pc2.core.model.ClientSettings; +import edu.csus.ecs.pc2.core.model.ElementId; +import edu.csus.ecs.pc2.core.model.Filter; import edu.csus.ecs.pc2.core.model.IInternalContest; +import edu.csus.ecs.pc2.core.model.IRunListener; +import edu.csus.ecs.pc2.core.model.Judgement; +import edu.csus.ecs.pc2.core.model.JudgementRecord; import edu.csus.ecs.pc2.core.model.Language; import edu.csus.ecs.pc2.core.model.Problem; +import edu.csus.ecs.pc2.core.model.Run; +import edu.csus.ecs.pc2.core.model.Run.RunStates; +import edu.csus.ecs.pc2.core.model.RunEvent; +import edu.csus.ecs.pc2.core.security.Permission; +import edu.csus.ecs.pc2.imports.ccs.IContestLoader; import edu.csus.ecs.pc2.list.ListUtilities; +import edu.csus.ecs.pc2.list.SubmissionSample; import edu.csus.ecs.pc2.list.SubmissionSampleLocation; import edu.csus.ecs.pc2.list.SubmissionSolutionList; +import edu.csus.ecs.pc2.ui.EditFilterPane.ListNames; import edu.csus.ecs.pc2.ui.team.QuickSubmitter; /** * A UI that to submit files found in a CDP. - * - * + * + * * @author Douglas A. Lane, PC^2 Team, pc2@ecs.csus.edu */ public class SubmitSampleRunsPane extends JPanePlugin { + private static final int VERT_PAD = 2; + private static final int HORZ_PAD = 20; + private static final int SUBMISSION_WAIT_TIMEOUT_MS = 10000; + /** * ClientSettings key for CDP Path */ @@ -70,78 +89,51 @@ public class SubmitSampleRunsPane extends JPanePlugin { private JLabel messageLabel; - private JCheckBox checkBoxSubmitYesSamples; - - private JCheckBox checkBoxSubmitFailingSamples; - private QuickSubmitter submitter = new QuickSubmitter(); - private JTextArea textArea; - - private SimpleDateFormat hhMMSSformatter = new SimpleDateFormat("hh:mm:ss"); - - private int linenumber = 0; - /** - * @wbp.nonvisual location=162,159 - */ - private final ButtonGroup judgingTypesButtonGroup = new ButtonGroup(); - - private final ButtonGroup problemsButtonGroup = new ButtonGroup(); - - private final ButtonGroup languagesButtonGroup = new ButtonGroup(); - - /** * List of selected solutions names and dirs. */ private SubmissionSolutionList submissionSolutionList = null; - - /** - * List of selected Problems. - * - */ - private List selectedProblemList = null; - - private List selectedLanguageList = null; - - private int[] selectedJudgingTypeIndexes; - - private int[] selectedProblemsIndexes; - - private int[] selectedLanguagesIndexes; - - private JLabel selectedNosLabel = new JLabel("None selected"); - - private JRadioButton submitAllJudgingTypesRadioButton = new JRadioButton("Submit All"); - - private JRadioButton submitSelectedJudgingTypeRadioButton = new JRadioButton("Submit Selected"); - - private JCheckBox checkBoxProblems = null; - private JRadioButton selecteAllProblemsRadioButton = null; - private JRadioButton submitAllProblemsRadioButton; + private JPanel centerPane = null; + private JButton filterButton = null; - private JRadioButton submitSelectedProblems = null; - private JRadioButton submitSelectedProblemsRadioButton; + private JScrollPane scrollPane = null; + private JTableCustomized runTable = null; + private DefaultTableModel runTableModel = null; - private JLabel selectedProblemsLabel = null; + private JPanel messagePanel = null; + private JLabel rowCountLabel = null; - private JButton selectProblemsButton = null; + /** + * User filter + */ + private Filter filter = new Filter(); - private JCheckBox checkBoxLanguage = null; + private EditFilterFrame editFilterFrame = null; - private JRadioButton selecteAllLanguages = null; - private JRadioButton submitAllLanguagesRadioButton; + private String filterFrameTitle = "Judges' Submissions filter"; - private JRadioButton submitSelectedLanguages = null; - private JRadioButton submitSelectedLanguagesRadioButton; - private JLabel selectedLanguagesLabel = null; + private Log log; - private JButton selectLanguageButton = null; + private List submissionFileList = null; + private int currentSubmission = -1; + private List submissionList = null; + private Timer submissionWaitTimer = null; + private TimerTask submissionTimerTask = null; + + // Lightish green for match + private Color matchColorSuccess = new Color(128, 255, 128); + // Lightish red for hard non-match + private Color matchColorFailure = new Color(255, 128, 128); + // Lightish yellow for take a look/maybe's/indeterminates + private Color matchColorMaybe = new Color(255, 255, 128); + // Lightish cyan for pending + private Color matchColorPending = new Color(128, 255, 255); - private Log log; // TODO 232 remove debug22Flag private boolean debug22Flag = false; @@ -150,34 +142,64 @@ public class SubmitSampleRunsPane extends JPanePlugin { public SubmitSampleRunsPane() { super(); - setLayout(new BorderLayout(0, 0)); + setLayout(new BorderLayout()); + + add(getMessagePanel(), BorderLayout.NORTH); + add(getCenterPanel(), BorderLayout.CENTER); + add(getBottomPanel(), BorderLayout.SOUTH); + + } - JPanel centerPane = new JPanel(); - centerPane.setLayout(new BorderLayout()); - add(centerPane, BorderLayout.CENTER); + /** + * This method initializes messagePanel + * + * @return javax.swing.JPanel + */ + private JPanel getMessagePanel() { + if (messagePanel == null) { + rowCountLabel = new JLabel(); + rowCountLabel.setText("### of ###"); + rowCountLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + rowCountLabel.setPreferredSize(new java.awt.Dimension(100,16)); + + messageLabel = new JLabel("message label"); + messageLabel.setFont(new Font("Tahoma", Font.PLAIN, 14)); + messageLabel.setForeground(Color.RED); + messageLabel.setHorizontalAlignment(SwingConstants.CENTER); +// messageLabel.setPreferredSize(new Dimension(400, 32)); + + messagePanel = new JPanel(); + messagePanel.setLayout(new BorderLayout()); + messagePanel.setPreferredSize(new java.awt.Dimension(30, 30)); + messagePanel.add(messageLabel, java.awt.BorderLayout.CENTER); + messagePanel.add(rowCountLabel, java.awt.BorderLayout.EAST); + } + return messagePanel; + } - JSplitPane splitPane = new JSplitPane(); - splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); - centerPane.add(splitPane, BorderLayout.CENTER); + private JPanel getCenterPanel() { + JPanel centerPane = new JPanel(); + centerPane.setLayout(new BorderLayout()); - JPanel controlsPane = new JPanel(); - controlsPane.setPreferredSize(new Dimension(400, 400)); + JPanel controlsPane = new JPanel(); - controlsPane.setLayout(null); + controlsPane.setLayout(new FlowLayout()); - JLabel cdpConfigDirLabel = new JLabel("CDP config dir"); - cdpConfigDirLabel.setToolTipText("CDP Location for sample source files"); - cdpConfigDirLabel.setHorizontalAlignment(SwingConstants.RIGHT); - cdpConfigDirLabel.setBounds(10, 60, 86, 14); - controlsPane.add(cdpConfigDirLabel); + JLabel cdpConfigDirLabel = new JLabel("CDP config folder: "); + cdpConfigDirLabel.setToolTipText("CDP Location for judges' samples source files"); + cdpConfigDirLabel.setHorizontalAlignment(SwingConstants.RIGHT); + controlsPane.add(cdpConfigDirLabel); + + cdpTextField = new JTextField(); + cdpTextField.setFont(new Font("Tahoma", Font.PLAIN, 12)); + Dimension cdpDim = cdpTextField.getPreferredSize(); + cdpDim.setSize(cdpDim.getWidth(), 27); + cdpTextField.setPreferredSize(cdpDim); + controlsPane.add(cdpTextField); + cdpTextField.setColumns(40); - cdpTextField = new JTextField(); - cdpTextField.setFont(new Font("Tahoma", Font.PLAIN, 12)); - cdpTextField.setBounds(113, 54, 418, 27); - controlsPane.add(cdpTextField); - cdpTextField.setColumns(10); - cdpTextField.addKeyListener(new java.awt.event.KeyAdapter() { + @Override public void keyPressed(java.awt.event.KeyEvent e) { if (e.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER) { if (new File(cdpTextField.getText()).isDirectory()) { @@ -188,267 +210,61 @@ public void keyPressed(java.awt.event.KeyEvent e) { } }); - messageLabel = new JLabel("message label"); - messageLabel.setFont(new Font("Tahoma", Font.PLAIN, 14)); - messageLabel.setForeground(Color.RED); - messageLabel.setHorizontalAlignment(SwingConstants.CENTER); - messageLabel.setBounds(10, 11, 691, 32); - controlsPane.add(messageLabel); - - checkBoxSubmitYesSamples = new JCheckBox("Submit Yes Samples"); - checkBoxSubmitYesSamples.setSelected(true); - checkBoxSubmitYesSamples.setToolTipText("Only submit AC sample source"); - checkBoxSubmitYesSamples.setBounds(33, 102, 265, 23); - controlsPane.add(checkBoxSubmitYesSamples); - - JButton selectCDPButton = new JButton("..."); - selectCDPButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - selectNewCDP(); - } - }); - selectCDPButton.setToolTipText("Select a different CDP"); - selectCDPButton.setBounds(541, 56, 39, 23); - controlsPane.add(selectCDPButton); - - JPanel LogPanel = new JPanel(); - LogPanel.setSize(new Dimension(400, 400)); - LogPanel.setMinimumSize(new Dimension(400, 400)); - - LogPanel.setLayout(new BorderLayout(0, 0)); - - textArea = new JTextArea(); - textArea.setFont(new Font("Courier New", Font.PLAIN, 13)); - textArea.setSize(new Dimension(360, 360)); - JScrollPane scrollPane = new JScrollPane(textArea); - LogPanel.add(scrollPane, BorderLayout.CENTER); - - JPanel panel = new JPanel(); - panel.setPreferredSize(new Dimension(50, 50)); - FlowLayout flowLayout_1 = (FlowLayout) panel.getLayout(); - flowLayout_1.setHgap(45); - LogPanel.add(panel, BorderLayout.SOUTH); - - JButton clearTextAButton = new JButton("Clear"); - clearTextAButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - clearTextArea(); - } - - }); - panel.add(clearTextAButton); - - JButton copyButton = new JButton("Copy"); - copyButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - ClipboardUtilities.put(textArea.getText()); - } - }); - copyButton.setToolTipText("Copy text into clipboard"); - panel.add(copyButton); - - JPanel bottomPane = new JPanel(); - FlowLayout flowLayout = (FlowLayout) bottomPane.getLayout(); - flowLayout.setHgap(125); - add(bottomPane, BorderLayout.SOUTH); - - JButton submitRunButton = new JButton("Submit"); - submitRunButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - submitSelectedJudgesSolutions(); - } - }); - JButton resetButton = new JButton("Reset"); - resetButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - resetFields(true); - } - }); - resetButton.setToolTipText("Reset back to default settings"); - bottomPane.add(resetButton); - submitRunButton.setToolTipText("Submit selected sample runs"); - bottomPane.add(submitRunButton); - -// centerPane2.add(controlsPane, BorderLayout.CENTER); - JScrollPane leftSide = new JScrollPane(controlsPane); - - JPanel submitNoSamplesPane = new JPanel(); - submitNoSamplesPane.setBorder(new TitledBorder(null, "", TitledBorder.LEADING, TitledBorder.TOP, null, null)); - FlowLayout fl_submitNoSamplesPane = (FlowLayout) submitNoSamplesPane.getLayout(); - fl_submitNoSamplesPane.setAlignment(FlowLayout.LEFT); - submitNoSamplesPane.setBounds(33, 131, 650, 32); - controlsPane.add(submitNoSamplesPane); - - checkBoxSubmitFailingSamples = new JCheckBox("Submit Failing Samples"); - checkBoxSubmitFailingSamples.setVerticalAlignment(SwingConstants.TOP); - submitNoSamplesPane.add(checkBoxSubmitFailingSamples); - checkBoxSubmitFailingSamples.setSelected(true); - checkBoxSubmitFailingSamples.setToolTipText("Submt all non-AC (Yes) submissions"); - - judgingTypesButtonGroup.add(submitAllJudgingTypesRadioButton); - submitAllJudgingTypesRadioButton.setSelected(true); - judgingTypesButtonGroup.add(submitSelectedJudgingTypeRadioButton); - - submitNoSamplesPane.add(submitAllJudgingTypesRadioButton); - submitNoSamplesPane.add(submitSelectedJudgingTypeRadioButton); - - leftSide.setPreferredSize(new Dimension(230, 230)); - leftSide.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); - leftSide.setWheelScrollingEnabled(true); - splitPane.setLeftComponent(leftSide); - - // centerPane2.add(LogPanel, BorderLayout.SOUTH); - JScrollPane logScrollPanel = new JScrollPane(LogPanel); - logScrollPanel.setPreferredSize(new Dimension(60, 60)); - logScrollPanel.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); - logScrollPanel.setWheelScrollingEnabled(true); - splitPane.setRightComponent(logScrollPanel); - - - selectedNosLabel.setToolTipText("None selected"); - selectedNosLabel.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - showJudgementTypeList(); - } - }); - submitNoSamplesPane.add(selectedNosLabel); - JButton selectJudementTypesButton = new JButton("Select"); - selectJudementTypesButton.setToolTipText("Select Judgement Types"); - selectJudementTypesButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - showJudgementTypeList(); - } - }); - - submitNoSamplesPane.add(selectJudementTypesButton); - - JLabel lblNewLabel_2 = getWhatsThisOne(); - submitNoSamplesPane.add(lblNewLabel_2); - - JPanel submitNoSamplesPane_1 = new JPanel(); - FlowLayout flowLayout_2 = (FlowLayout) submitNoSamplesPane_1.getLayout(); - flowLayout_2.setAlignment(FlowLayout.LEFT); - submitNoSamplesPane_1.setBorder(new TitledBorder(null, "", TitledBorder.LEADING, TitledBorder.TOP, null, null)); - submitNoSamplesPane_1.setBounds(33, 161, 650, 32); - controlsPane.add(submitNoSamplesPane_1); - - checkBoxProblems = new JCheckBox("Problems"); - checkBoxProblems.setVerticalAlignment(SwingConstants.TOP); - checkBoxProblems.setToolTipText("Select Problems"); - checkBoxProblems.setSelected(true); - submitNoSamplesPane_1.add(checkBoxProblems); - - submitAllProblemsRadioButton = new JRadioButton("Submit All"); - submitAllProblemsRadioButton.setSelected(true); - submitNoSamplesPane_1.add(submitAllProblemsRadioButton); - - submitSelectedProblemsRadioButton = new JRadioButton("Submit Selected"); - submitNoSamplesPane_1.add(submitSelectedProblemsRadioButton); - - selectedProblemsLabel = new JLabel("None selected"); - selectedProblemsLabel.setToolTipText("None selected"); - submitNoSamplesPane_1.add(selectedProblemsLabel); - - selectProblemsButton = new JButton("Select"); - selectProblemsButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - showProblemList(); - } - }); - selectProblemsButton.setToolTipText("Select Problems"); - submitNoSamplesPane_1.add(selectProblemsButton); - - JPanel submitLanguages = new JPanel(); - FlowLayout fl_submitLanguages = (FlowLayout) submitLanguages.getLayout(); - fl_submitLanguages.setAlignment(FlowLayout.LEFT); - submitLanguages.setBorder(new TitledBorder(null, "", TitledBorder.LEADING, TitledBorder.TOP, null, null)); - submitLanguages.setBounds(33, 191, 650, 32); - controlsPane.add(submitLanguages); - - checkBoxLanguage = new JCheckBox("Languages"); - checkBoxLanguage.setVerticalAlignment(SwingConstants.TOP); - checkBoxLanguage.setToolTipText("Select Languages"); - checkBoxLanguage.setSelected(true); - submitLanguages.add(checkBoxLanguage); - - submitAllLanguagesRadioButton = new JRadioButton("Submit All Languages"); - submitAllLanguagesRadioButton.setSelected(true); - submitLanguages.add(submitAllLanguagesRadioButton); - - submitSelectedLanguagesRadioButton = new JRadioButton("Submit Selected"); - submitLanguages.add(submitSelectedLanguagesRadioButton); - - selectedLanguagesLabel = new JLabel("None selected Lang?"); - selectedLanguagesLabel.setToolTipText("None selected"); - submitLanguages.add(selectedLanguagesLabel); - - selectLanguageButton = new JButton("Select"); - selectLanguageButton.addActionListener(new ActionListener() { + JButton selectCDPButton = new JButton("..."); + selectCDPButton.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - showLanguageList(); + selectNewCDP(); } }); - selectLanguageButton.setToolTipText("Select Problems"); - submitLanguages.add(selectLanguageButton); - - - languagesButtonGroup.add(submitAllLanguagesRadioButton); - languagesButtonGroup.add(submitSelectedLanguagesRadioButton); - - problemsButtonGroup.add(submitAllProblemsRadioButton); - problemsButtonGroup.add(submitSelectedProblemsRadioButton); - - VersionInfo info = new VersionInfo(); - String verstring = info.getBuildNumber() + " x " + info.getPC2Version(); - addLineToTextArea(verstring); - - - - } + selectCDPButton.setToolTipText("Select a different CDP"); + selectCDPButton.setPreferredSize(new Dimension(56, 27)); +// selectCDPButton.setBounds(541, 56, 39, 23); + controlsPane.add(selectCDPButton); - protected void showLanguageList() { + JButton fb = getFilterButton(); + controlsPane.add(fb); - // TODO 232 show language selection - - Language[] Languages = getContest().getLanguages(); - - if (Languages.length == 0) { - showMessage("No Languagess defined in contest"); - return; - } - - JListFrame selectLanguagessFrame = new JListFrame("Select Languages ", Languages, selectedLanguagesIndexes, new ISelectedListsSetter() { - + + centerPane.add(controlsPane, BorderLayout.NORTH); + + centerPane.add(getScrollPane(), BorderLayout.SOUTH);; + + return(centerPane); + } + + /** + * Builds the bottom panel (buttons) + * + * @return JPanel for the bottom area (buttons) + */ + private JPanel getBottomPanel() { + JPanel bottomPane = new JPanel(); + FlowLayout flowLayout = (FlowLayout) bottomPane.getLayout(); + flowLayout.setHgap(125); + + JButton submitRunButton = new JButton("Submit"); + submitRunButton.addActionListener(new ActionListener() { @Override - public void setSelectedValuesList(List selectedValuesList, int[] selectedIndices) { - selectedLanguagesIndexes = selectedIndices; - updateLanguagesLabel(selectedValuesList); + public void actionPerformed(ActionEvent e) { + submitSelectedJudgesSolutions(); } }); - selectLanguagessFrame.setVisible(true); - } - - protected void showProblemList() { - - Problem[] problems = getContest().getProblems(); - - if (problems.length == 0) { - showMessage("No problems defined in contest"); - return; - } - - JListFrame selectProblemsFrame = new JListFrame("Select Problems ", problems, selectedProblemsIndexes, new ISelectedListsSetter() { - + JButton resetButton = new JButton("Reset"); + resetButton.addActionListener(new ActionListener() { @Override - public void setSelectedValuesList(List selectedValuesList, int[] selectedIndices) { - selectedProblemsIndexes = selectedIndices; - updateProblemsLabel(selectedValuesList); + public void actionPerformed(ActionEvent e) { + resetFields(true); } }); - selectProblemsFrame.setVisible(true); + + resetButton.setToolTipText("Reset back to default settings"); + bottomPane.add(resetButton); + submitRunButton.setToolTipText("Submit selected sample runs"); + bottomPane.add(submitRunButton); + return(bottomPane); } protected void updateCDPDirAndFields(String cdpConfigDir) { @@ -458,133 +274,30 @@ protected void updateCDPDirAndFields(String cdpConfigDir) { // if (configFile.getAbsolutePath().endsWith(IContestLoader.CONFIG_DIRNAME)) { // cdpRootDirectory = configFile.getParent(); // } - + cdpTextField.setText(cdpRootDirectory); updateClientCDPPath(cdpRootDirectory); - updateNosLabel(null); } catch (Exception e) { log.log(Level.WARNING, "Problem updating CDP Dir", e); } } - /** - * Dialog with question mark ison for info on selecting judgement types. - * @return - */ - private JLabel getWhatsThisOne() { - - String[] messageLines = { - "Selecting judgement types", // - "", // - "Use Select button to select judgement types", // - }; - - return FrameUtilities.getWhatsThisLabel("Selecting judgement samples", messageLines); - } - /** * Repopulate submissionSolutionList. - * - * @return + * + * @return */ public SubmissionSolutionList getSubmissionSolutionList() { String cdpPath = cdpTextField.getText(); - - SubmissionSolutionList list = new SubmissionSolutionList(new File(cdpPath)); - Collections.reverse(list); - submissionSolutionList = list; - - return submissionSolutionList; - } - - protected void showJudgementTypeList() { - - if (getSubmissionSolutionList() == null || getSubmissionSolutionList().size() == 0) { - showMessage("No submission judgement types found in dir: "+cdpTextField.getText()); - return; - } - - SubmissionSampleLocation[] listData = toArray(getSubmissionSolutionList()); - - JListFrame selectNoSolutionsFrame = new JListFrame("Select No/Failed Judges solutions", listData, selectedJudgingTypeIndexes, new ISelectedListsSetter() { - - @Override - public void setSelectedValuesList(List selectedValuesList, int[] selectedIndices) { - selectedJudgingTypeIndexes = selectedIndices; - updateNosLabel(selectedValuesList); - } - }); - selectNoSolutionsFrame.setVisible(true); - } - - private SubmissionSampleLocation[] toArray(SubmissionSolutionList list) { - return (SubmissionSampleLocation[]) list.toArray(new SubmissionSampleLocation[list.size()]); - } - - /** - * Update selected languages label and selected language list - * @param valuesList - */ - protected void updateLanguagesLabel(List valuesList) { - if (valuesList == null || valuesList.size() == 0) { - selectedLanguagesLabel.setText("None selected"); - selectedLanguagesLabel.setToolTipText("None selected"); - } else { - selectedLanguagesLabel.setText(valuesList.size()+" selected"); - selectedLanguagesLabel.setToolTipText(Arrays.toString(valuesList.toArray())); - - selectedLanguageList = new ArrayList(); - valuesList.forEach((lang) -> {selectedLanguageList.add((Language)lang);}); - } - } - - protected void updateProblemsLabel(List valuesList) { - - if (valuesList == null || valuesList.size() == 0) { - selectedProblemsLabel.setText("None selected"); - selectedProblemsLabel.setToolTipText("None selected"); - } else { - - selectedProblemsLabel.setText(valuesList.size()+" selected"); - selectedProblemsLabel.setToolTipText(Arrays.toString(valuesList.toArray())); - - selectedProblemList = new ArrayList(); - valuesList.forEach((prob) -> {selectedProblemList.add((Problem)prob);}); - } - } - - protected void updateNosLabel(List valuesList) { - - if (valuesList == null || valuesList.size() == 0) { - selectedNosLabel.setText("None selected"); - selectedNosLabel.setToolTipText("None selected"); - } else { - selectedNosLabel.setText(valuesList.size() + " selected"); - selectedNosLabel.setToolTipText(Arrays.toString(valuesList.toArray())); - submissionSolutionList = new SubmissionSolutionList(); - - // update/load selected items into submissionSolutionList - valuesList.forEach((subSL) -> { - submissionSolutionList.add((SubmissionSampleLocation) subSL); - }); - - } - } + submissionSolutionList = new SubmissionSolutionList(getContest(), cdpPath); - protected void clearTextArea() { - textArea.selectAll(); - textArea.replaceSelection(""); - linenumber = 0; + return submissionSolutionList; } - void addLineToTextArea(String s) { - - linenumber++; - String fmtLineNumber = String.format("%4d", linenumber); - textArea.insert(fmtLineNumber + " " + hhMMSSformatter.format(new Date()) + " " + s + "\n", 0); -// textArea.append(s); + private SubmissionSampleLocation[] toArray(SubmissionSolutionList list) { + return list.toArray(new SubmissionSampleLocation[list.size()]); } protected void selectNewCDP() { @@ -607,7 +320,7 @@ protected void selectNewCDP() { /** * Select yaml file/entry. - * + * * @param dialogTitle * @return */ @@ -647,11 +360,6 @@ void updateClientCDPPath(String path) { getController().updateClientSettings(settings); } - private void xlog(String string) { - System.out.println(string); - addLineToTextArea(string); - } - protected String getClientCDPPath() { ClientSettings settings = getContest().getClientSettings(); @@ -667,31 +375,15 @@ protected String getClientCDPPath() { /** * Reset fields back to default values - * + * * @param usingGui */ protected void resetFields(boolean isUsingGui) { - - - selectedJudgingTypeIndexes = new int[0]; - selectedProblemsIndexes = new int[0]; - selectedLanguagesIndexes = new int[0]; - - checkBoxSubmitYesSamples.setSelected(true); - checkBoxSubmitFailingSamples.setSelected(true); - - checkBoxLanguage.setSelected(true); - checkBoxProblems.setSelected(true); - - submitAllJudgingTypesRadioButton.setSelected(true); - submitAllProblemsRadioButton.setSelected(true); - submitAllLanguagesRadioButton.setSelected(true); - String cdpPath = getContest().getContestInformation().getJudgeCDPBasePath(); String clientPath = getClientCDPPath(); - if (clientPath != null && isUsingGui) { + if (clientPath != null && !clientPath.equals(cdpPath)) { int result = FrameUtilities.yesNoCancelDialog(this, "Overwrite locally saved CDP path with this (default) " + cdpPath, "Replace CDP Path?"); if (result == JOptionPane.NO_OPTION) { @@ -699,9 +391,15 @@ protected void resetFields(boolean isUsingGui) { } } + submissionList = null; + stopSubmissionTimer(); + clearSubmissionFiles(); + clearAllRuns(); + + cdpTextField.setText(cdpPath); -// getController().updateClientSettings(settings);; +// getController().updateClientSettings(settings); } @@ -711,98 +409,132 @@ protected void resetFields(boolean isUsingGui) { protected void submitSelectedJudgesSolutions() { showMessage(""); + if(submissionFileList != null) { + showMessage("Please wait until the previous files have finished being submitted (" + (submissionList.size() - currentSubmission) + " remain)"); + return; + } String warningMessage = verifyCDP (cdpTextField.getText()); if (warningMessage != null) { // let the user know that the CDP selected may not work - FrameUtilities.showMessage(this, "Trying to use an invalid CDP?", warningMessage); + FrameUtilities.showMessage(this, "Maybe the CDP is invalid?", warningMessage); } - List allFiles = ListUtilities.getAllJudgeSampleSubmissionFilenamesFromCDP(getContest(), cdpTextField.getText()); + List files = ListUtilities.getAllJudgeSampleSubmissionFilenamesFromCDP(getContest(), cdpTextField.getText()); - if (allFiles.size() == 0) { - FrameUtilities.showMessage(this, "No Runs", "No Runs found under " + cdpTextField.getText()); + if (files.size() == 0) { + FrameUtilities.showMessage(this, "No Submissions", "No submissions found under " + cdpTextField.getText()); return; } - boolean submitYesSamples = checkBoxSubmitYesSamples.isSelected(); - boolean submitNoSamples = checkBoxSubmitFailingSamples.isSelected(); - - if (!submitYesSamples && !submitNoSamples) { - FrameUtilities.showMessage(this, "No Runs", "Select either Yes or Failed runs"); - return; - } - - List files = new ArrayList(); + // The actual filtering is done somewhat differently for potential submissions. We can still use + // the Filter object (filter) since it has all the criteria we need. + if(filter.isFilterOn()) { + // We use the custom filtering list for judge submission types, eg. accepted, wrong_answer, etc + if(filter.isFilteringCustom()) { + files = ListUtilities.filterByJudgingTypes(files, filter.getCustomList()); + } - files = QuickSubmitter.filterRuns(allFiles, submitYesSamples, submitNoSamples); + if(filter.isFilteringProblems()) { + ElementId[] probElems = filter.getProblemIdList(); + ArrayList probList = new ArrayList(); - if (submitNoSamples && submitSelectedJudgingTypeRadioButton.isSelected()) { - if (submitSelectedJudgingTypeRadioButton.isSelected()) { - // if they selected the radio button for selected, they should select at least - if (selectedJudgingTypeIndexes == null || selectedJudgingTypeIndexes.length == 0) { - FrameUtilities.showMessage(this, "No Judging Types selected", "No Judging Types selected, select at least one"); - return; + for(ElementId ele : probElems) { + Problem prob = getContest().getProblem(ele); + if(prob != null) { + probList.add(prob); + } } - - // fitler by judging type (accepted, wrong_answer, etc.) - files = ListUtilities.filterByJudgingTypes(files, submissionSolutionList); + files = ListUtilities.filterByProblems(files, probList); } - } - - if (checkBoxProblems.isSelected() ) { - if (submitSelectedProblemsRadioButton.isSelected()) { - // submissions may be filtered by problem - - if (selectedProblemsIndexes == null || selectedProblemsIndexes.length == 0) { - FrameUtilities.showMessage(this, "No Problem selected", "No Problems selected, select at least one"); - return; - } - // filter list by problem name - files = ListUtilities.filterByProblems (files, selectedProblemList); + if(filter.isFilteringLanguages()) { + ElementId[] langElems = filter.getLanguageIdList(); + ArrayList langList = new ArrayList(); + for(ElementId ele : langElems) { + Language lang = getContest().getLanguage(ele); + if(lang != null) { + langList.add(lang); + } + } + files = ListUtilities.filterByLanguages(files, getContest(), langList); } } - - if (checkBoxLanguage.isSelected()) { - // submissions may be filtered by language - - if (submitSelectedLanguagesRadioButton.isSelected()) { - if (selectedLanguagesIndexes == null || selectedLanguagesIndexes.length == 0) { - FrameUtilities.showMessage(this, "No Language selected", "No Languages selected, select at least one"); - return; - - } + int count = 0; - files = ListUtilities.filterByLanguages(files, getContest(), selectedLanguageList); - } + if(Utilities.isDebugMode()) { + for (File file : files) { + count++; + System.out.println("Will submit #" + count + " file = " + file.getAbsolutePath()); + } + } else { + count = files.size(); } - - - int count = 0; - for (File file : files) { - count++; - xlog("Will submit #" + count + " file =" + file.getAbsolutePath()); + if (count == 0) { + showMessage("There are no matching CDP sample source files under " + cdpTextField.getText()); + return; } - if (count == 0) { - showMessage("There are no CDP samples source files under " + cdpTextField.getText()); + // check with the user to be sure they want to submit everything. + int result = FrameUtilities.yesNoCancelDialog(this, "Submit " + count + " judge sample submissions?", + "Submit CDP submissions"); + if (result != JOptionPane.YES_OPTION) { return; } + showMessage("Submitting " + count + " runs."); - int result = FrameUtilities.yesNoCancelDialog(this, "Submit " + files.size() + " sample submissions?", - "Submit CDP submissions"); + submissionFileList = files; + // create submissionList to add SubmissionSample's to as we submit them. + submissionList = new ArrayList(); + currentSubmission = 0; - if (result == JOptionPane.YES_OPTION) { - /** - * This will submit each file found - */ - submitter.sendSubmissions(files); + submitNextSubmission(); + } - showMessage("Submitted " + files.size() + " runs."); + private void submitNextSubmission() { + try { + File file = submissionFileList.get(currentSubmission); + + submissionTimerTask = new TimerTask() { + @Override + public void run() { + // Whoops! This means the submission never came in + log.severe("No submission was received from the server for #" + currentSubmission + "; cancelling remaining submissions"); + showMessage("Submission #" + currentSubmission + " not received from server"); + clearSubmissionFiles(); + stopSubmissionTimer(); + } + }; + + submissionWaitTimer = new Timer("Submission Wait Timer " + currentSubmission); + submissionWaitTimer.schedule(submissionTimerTask, SUBMISSION_WAIT_TIMEOUT_MS); + + SubmissionSample sub = submitter.sendSubmission(file); + if(sub != null) { + submissionList.add(sub); + updateRunRow(sub, getContest().getClientId(), true); + } + if(Utilities.isDebugMode()) { + System.out.println("Submitted #" + currentSubmission + " for problem " + sub.toString()); + } + } catch(Exception e) { + log.log(Level.WARNING, "Error submitting submission #" + currentSubmission, e); + clearSubmissionFiles(); + stopSubmissionTimer(); } + } + private void clearSubmissionFiles() { + submissionFileList = null; + currentSubmission = -1; + } + private void stopSubmissionTimer() { + if(submissionWaitTimer != null) { + submissionWaitTimer.cancel(); + submissionWaitTimer = null; + submissionTimerTask = null; + } } /** @@ -811,13 +543,36 @@ protected void submitSelectedJudgesSolutions() { * @return null if no issues, else a warning message about a diffence between model and cdpDir */ private String verifyCDP(String cdpDir) { - // TODO 232 compare problems in CDP with problems in model - return null; + + Problem[] problems = getContest().getProblems(); + List files = new ArrayList<>(); + String missingProbs = ""; + String warningMsg = null; + String configDir = cdpDir + File.separator + IContestLoader.CONFIG_DIRNAME; + + if (new File(configDir).isDirectory()) { + cdpDir = configDir; + } + + for (Problem problem : problems) { + + // config\sumit\submissions\accepted\ISumit.java + if(!(new File(cdpDir + File.separator + problem.getShortName()).isDirectory())) { + if(!missingProbs.isEmpty()) { + missingProbs = missingProbs + ','; + } + missingProbs = missingProbs + problem.getShortName(); + } + } + if(!missingProbs.isEmpty()) { + warningMsg = "No problem folder found for: " + missingProbs; + } + return warningMsg; } /** * Returns the list of filenames that end in extension - * + * * @param files * @param extension * @return @@ -851,27 +606,629 @@ public void setContestAndController(IInternalContest inContest, IInternalControl cdpPath = clientPath; } - xlog("CDP dir is now at " + cdpPath); +// xlog("CDP dir is now at " + cdpPath); cdpTextField.setText(cdpPath); showMessage(""); submitter.setContestAndController(inContest, inController); - - + getEditFilterFrame().setContestAndController(inContest, inController); + + log = inController.getLog(); + getContest().addRunListener(new RunListenerImplementation()); + } public void showMessage(final String message) { SwingUtilities.invokeLater(new Runnable() { - public void run() { - xlog(message); + @Override + public void run() { +// xlog(message); messageLabel.setText(message); messageLabel.setToolTipText(message); } }); } + /** + * This method initializes filterButton + * + * @return javax.swing.JButton + */ + private JButton getFilterButton() { + if (filterButton == null) { + filterButton = new JButton(); + filterButton.setText("Filter"); + filterButton.setToolTipText("Edit Filter"); + filterButton.setMnemonic(java.awt.event.KeyEvent.VK_F); + filterButton.setPreferredSize(new Dimension(80, 27)); + filterButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + showFilterRunsFrame(); + } + }); + } + return filterButton; + } + + protected void showFilterRunsFrame() { + getEditFilterFrame().addList(ListNames.CUSTOM_LIST); + getEditFilterFrame().addCustomItems(getSubmissionSolutionList()); + getEditFilterFrame().setCustomTitle("Solution Type"); + getEditFilterFrame().addList(ListNames.LANGUAGES); + getEditFilterFrame().addList(ListNames.PROBLEMS); + + getEditFilterFrame().setFilter(filter); + getEditFilterFrame().validate(); + getEditFilterFrame().setVisible(true); + } + + public EditFilterFrame getEditFilterFrame() { + if (editFilterFrame == null){ + Runnable callback = new Runnable(){ + @Override + public void run() { +// reloadRunList(); + } + }; + editFilterFrame = new EditFilterFrame(filter, filterFrameTitle, callback); + } + return editFilterFrame; + } + + /** + * Set title for the Filter Frame. + * + * @param title + */ + public void setFilterFrameTitle (String title){ + filterFrameTitle = title; + if (editFilterFrame != null){ + editFilterFrame.setTitle(title); + } + } + + /** + * This method initializes scrollPane + * + * @return javax.swing.JScrollPane + */ + private JScrollPane getScrollPane() { + if (scrollPane == null) { + scrollPane = new JScrollPane(getRunTable()); + resetRunsListBoxColumns(); + } + return scrollPane; + } + + /** + * This method initializes the runTable + * + * @return JTableCustomized + */ + private JTableCustomized getRunTable() { + if (runTable == null) { + runTable = new JTableCustomized() { + private static final long serialVersionUID = 1L; + + // override JTable's default renderer to set the background color based on the match status + // of the sample folder the submission was found in vs. the judgment. + // Essentially stolen from ShadowCompareScoreboardPane. Thank you JohnC. + @Override + public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { + Component c = super.prepareRenderer(renderer, row, column); + + //default to normal background + c.setBackground(getBackground()); + + if(runTableModel != null) { + //map the specified row index number to the corresponding model row (index numbers can change due + // to sorting/scrolling; model row numbers never change). + // Here are the columns: + // Object[] fullColumns = { "Run Id", "Time", "Problem", "Expected", "Status", "Source", "Judge", "Language", "ElementId" }; + + int modelRow = convertRowIndexToModel(row); + String submissionAcronym = submissionSolutionList.getAcronymForSubmissionDirectory((String)runTableModel.getValueAt(modelRow, 3)); + + if(submissionAcronym == null) { + c.setBackground(matchColorMaybe); + } else { + String judgment = (String)runTableModel.getValueAt(modelRow, 4); + // Format is something like: "Wrong answer:WA" + int idx = judgment.lastIndexOf(":"); + if(idx != -1) { + judgment = judgment.substring(idx+1); + if(submissionAcronym.equals(judgment)) { + c.setBackground(matchColorSuccess); + } else { + c.setBackground(matchColorFailure); + } + } else { + // No judgment yet; eg "QUEUED_FOR_COMPUTER_JUDGEMENT" or other non-judged status + c.setBackground(matchColorPending); + } + } + } + + return(c); + } + }; + + runTable.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent me) { + // If double-click see if we can select the run + if (me.getClickCount() == 2) { + JTable target = (JTable)me.getSource(); + if(target.getSelectedRow() != -1 && isAllowed(Permission.Type.JUDGE_RUN)) { +// requestSelectedRun(); + } + } + } + }); + } + return runTable; + } + + public void clearAllRuns() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if(runTableModel != null) { + // All rows are discarded - the TM will notify the Table + runTableModel.setRowCount(0); + } + } + }); + } + + private void resetRunsListBoxColumns() { + + runTable.removeAll(); + + Object[] fullColumns = { "Run Id", "Time", "Problem", "Expected", "Status", "Source", "Judge", "Language", "ElementId" }; + Object[] columns; + + columns = fullColumns; + runTableModel = new DefaultTableModel(columns, 0) { + @Override + public boolean isCellEditable(int row, int col) { + return false; + } + }; + + runTable.setModel(runTableModel); + TableColumnModel tcm = runTable.getColumnModel(); + // Remove ElementID from display - this does not REMOVE the column, just makes it so it doesn't show + tcm.removeColumn(tcm.getColumn(columns.length - 1)); + + // Sorters + TableRowSorter trs = new TableRowSorter(runTableModel); + + runTable.setRowSorter(trs); + runTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + + ArrayList sortList = new ArrayList(); + + + /* + * Column headers left justified + */ + ((DefaultTableCellRenderer)runTable.getTableHeader().getDefaultRenderer()).setHorizontalAlignment(JLabel.LEFT); + runTable.setRowHeight(runTable.getRowHeight() + VERT_PAD); + + + StringToNumberComparator numericStringSorter = new StringToNumberComparator(); + + int idx = 0; + + +// Object[] fullColumns = { "Run Id", "Time", "Problem", "Expected", "Status", "Source", "Judge", "Language" }; + + + // These are in column order - omitted ones are straight string compare + trs.setComparator(0, numericStringSorter); + trs.setComparator(1, numericStringSorter); + // These are in sort order + sortList.add(new RowSorter.SortKey(0, SortOrder.ASCENDING)); + sortList.add(new RowSorter.SortKey(1, SortOrder.ASCENDING)); + sortList.add(new RowSorter.SortKey(2, SortOrder.ASCENDING)); + sortList.add(new RowSorter.SortKey(3, SortOrder.ASCENDING)); + sortList.add(new RowSorter.SortKey(4, SortOrder.ASCENDING)); + sortList.add(new RowSorter.SortKey(5, SortOrder.ASCENDING)); + sortList.add(new RowSorter.SortKey(6, SortOrder.ASCENDING)); + sortList.add(new RowSorter.SortKey(7, SortOrder.ASCENDING)); + trs.setSortKeys(sortList); + resizeColumnWidth(runTable); + } + + private void resizeColumnWidth(JTableCustomized table) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + TableColumnAdjuster tca = new TableColumnAdjuster(table, HORZ_PAD); + tca.adjustColumns(); + } + }); + } + + protected Object[] buildRunRow(SubmissionSample sub, ClientId judgeId) { + + try { + Run run = sub.getRun(); + + int cols = runTableModel.getColumnCount(); + Object[] s = new Object[cols]; + + int idx = 0; + +// Object[] fullColumns = { "Run Id", "Time", "Problem", "Expected", "Status", "Source", "Judge", "Language", ["ElementId"] }; + if(run != null) { + boolean autoJudgedRun = isAutoJudgedRun(run); + s[idx++] = Integer.toString(run.getNumber()); + s[idx++] = Long.toString(run.getElapsedMins()); + s[idx++] = getProblemTitle(sub.getProblem()); + s[idx++] = sub.getSampleType(); + s[idx++] = getJudgementResultString(run); + s[idx++] = sub.getSourceFile().getName(); + s[idx++] = getJudgesTitle(run, judgeId, autoJudgedRun); + } else { + s[idx++] = "Waiting"; + s[idx++] = "N/A"; + s[idx++] = getProblemTitle(sub.getProblem()); + s[idx++] = sub.getSampleType(); + s[idx++] = "N/A"; + s[idx++] = sub.getSourceFile().getName(); + s[idx++] = "N/A"; + } + s[idx++] = getLanguageTitle(sub.getLanguage()); + s[idx++] = sub.getElementId(); + + return s; + } catch (Exception exception) { + StaticLog.getLog().log(Log.INFO, "Exception in buildRunRow()", exception); + } + return null; + } + + private String getLanguageTitle(ElementId languageId) { + Language language = getContest().getLanguage(languageId); + if(language != null) { + return(language.getDisplayName()); + } + return "Language ?"; + } + + private String getProblemTitle(ElementId problemId) { + Problem problem = getContest().getProblem(problemId); + if (problem != null) { + return problem.toString(); + } + return "Problem ?"; + } + + private String getJudgesTitle(Run run, ClientId judgeId, boolean autoJudgedRun) { + + String result = ""; + + if (judgeId != null) { + if (judgeId.equals(getContest().getClientId())) { + result = "Me"; + } else { + result = judgeId.getName() + " S" + judgeId.getSiteNumber(); + } + if (autoJudgedRun) { + result = result + "/AJ"; + } + } else { + result = ""; + } + return result; + } + + private boolean isAutoJudgedRun(Run run) { + if (run.isJudged()) { + if (!run.isSolved()) { + JudgementRecord judgementRecord = run.getJudgementRecord(); + if (judgementRecord != null && judgementRecord.getJudgementId() != null) { + return judgementRecord.isUsedValidator(); + } + } + } + return false; + } + + /** + * Return the judgement/status for the run. + * + * @param run + * @return a string that represents the state of the run + */ + protected String getJudgementResultString(Run run) { + + String result = ""; + String acronym = ""; + + if (run.isJudged()) { + + if (run.isSolved()) { + // oh my, this is bad, but, alas, copied from RunTable - gets the "accepted" judgment + Judgement judgment = getContest().getJudgements()[0]; + acronym = ":" + judgment.getAcronym(); + + result = judgment.getDisplayName(); + if (run.getStatus().equals(RunStates.MANUAL_REVIEW)) { + result = RunStates.MANUAL_REVIEW + " (" + result + ")"; + } + + } else { + result = "No"; + + JudgementRecord judgementRecord = run.getJudgementRecord(); + + if (judgementRecord != null && judgementRecord.getJudgementId() != null) { + Judgement judgment = getContest().getJudgement(judgementRecord.getJudgementId()); + // Get acronym now, because we tack it on later + if(judgment != null) { + acronym = ":" + judgment.getAcronym(); + } + if (judgementRecord.isUsedValidator() && judgementRecord.getValidatorResultString() != null) { + result = judgementRecord.getValidatorResultString(); + } else { + if (judgment != null) { + result = judgment.toString(); + } + } + + if (run.getStatus().equals(RunStates.MANUAL_REVIEW)) { + result = RunStates.MANUAL_REVIEW + " (" + result + ")"; + } + + if (run.getStatus().equals(RunStates.BEING_RE_JUDGED)) { + result = RunStates.BEING_RE_JUDGED.toString(); + } + } + } + + } else { + result = run.getStatus().toString(); + } + + if (run.isDeleted()) { + result = "DEL " + result; + } + + result = result + acronym; + + + return result; + } + + /** + * Find row that contains the supplied key (in last column) + * @param value - unique key - really, the ElementId of run + * @return index of row, or -1 if not found + */ + private int getRowByKey(Object value) { + Object o; + + if(runTableModel != null) { + int col = runTableModel.getColumnCount() - 1; + for (int i = runTableModel.getRowCount() - 1; i >= 0; --i) { + o = runTableModel.getValueAt(i, col); + if (o != null && o.equals(value)) { + return i; + } + } + } + return(-1); + } + + /** + * Remove run from grid by removing the data row from the TableModel + * + * @param run + */ + private void removeRunRow(final Run run) { + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + + int rowNumber = getRowByKey(run.getElementId()); + if (rowNumber != -1) { + runTableModel.removeRow(rowNumber); + updateRowCount(); + } + } + }); + } + + /** + * This updates the rowCountlabel & toolTipText. It should be called only while on the swing thread. + */ + private void updateRowCount() { + if (filter.isFilterOn()){ + int totalRuns = getContest().getRuns().length; + rowCountLabel.setText(runTable.getRowCount()+" of "+totalRuns); + rowCountLabel.setToolTipText(runTable.getRowCount() + " filtered runs"); + } else { + rowCountLabel.setText("" + runTable.getRowCount()); + rowCountLabel.setToolTipText(runTable.getRowCount() + " runs"); + } + } + + public void updateRunRow(final SubmissionSample sub, final ClientId whoModifiedId, final boolean autoSizeAndSort) { + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + + ClientId whoJudgedId = whoModifiedId; + Run run = sub.getRun(); + if (run != null && run.isJudged()) { + JudgementRecord judgementRecord = run.getJudgementRecord(); + if (judgementRecord != null) { + whoJudgedId = judgementRecord.getJudgerClientId(); + } + } + + Object[] objects = buildRunRow(sub, whoJudgedId); + int rowNumber = getRowByKey(sub.getElementId()); + if (rowNumber == -1) { + // No row with this key - add new one + runTableModel.addRow(objects); + } else { + // Update all fields + for(int j = runTableModel.getColumnCount()-1; j >= 0; j--) { + runTableModel.setValueAt(objects[j], rowNumber, j); + } + } + + if (autoSizeAndSort) { + updateRowCount(); + resizeColumnWidth(runTable); + } + +// if (selectJudgementFrame != null) { + //TODO the selectJudgementFrame should be placed above all PC2 windows, not working when dblClicking in Windows OS +// } + } + }); + } + + public void reloadRunList() { + + if (filter.isFilterOn()){ + getFilterButton().setForeground(Color.BLUE); + getFilterButton().setToolTipText("Edit filter - filter ON"); + rowCountLabel.setForeground(Color.BLUE); + } else { + getFilterButton().setForeground(Color.BLACK); + getFilterButton().setToolTipText("Edit filter"); + rowCountLabel.setForeground(Color.BLACK); + } + + for (SubmissionSample sub : submissionList) { + ClientId clientId = null; + + Run run = sub.getRun(); + if(run != null) { + RunStates runStates = run.getStatus(); + if (!(runStates.equals(RunStates.NEW) || run.isDeleted())) { + JudgementRecord judgementRecord = run.getJudgementRecord(); + if (judgementRecord != null) { + clientId = judgementRecord.getJudgerClientId(); + } + } + } + updateRunRow(sub, clientId, false); + } + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + updateRowCount(); + resizeColumnWidth(runTable); + } + }); + } + /** + * Run Listener + * @author pc2@ecs.csus.edu + * @version $Id$ + */ + + // $HeadURL$ + public class RunListenerImplementation implements IRunListener { + + @Override + public void runAdded(RunEvent event) { + SubmissionSample sub = null; + Run run = event.getRun(); + ClientId me = getContest().getClientId(); + + // We are only interested in runs we submitted + if(run.getSubmitter().equals(me)) { + + // JB - think this test for duplicate is inadequate. + // We should remember the run id in a hashmap or something and ignore it if was seen + SubmissionSample dupRun = getSubmission(event); + if(dupRun == null) { + try { + // This is the last run - it has to be the one that was just added by us + sub = submissionList.get(currentSubmission); + } catch (Exception e) { + log.log(Level.WARNING, "No submission sample for run id " + run.getNumber(), e); + if(Utilities.isDebugMode()) { + System.out.println("No submission runAdded (" + run.getNumber() + ") - currentSubmission #" + currentSubmission); + } + } + } else { + log.log(Level.WARNING, "Duplicate runAdded event for Run id " + run.getNumber() + " ignored."); + if(Utilities.isDebugMode()) { + System.out.println("Duplicate runAdded (" + run.getNumber() + ") ignored - currentSubmission #" + currentSubmission); + } + } + } + if(sub != null) { + stopSubmissionTimer(); + sub.setRun(run); + if(Utilities.isDebugMode()) { + System.out.println("Received runAdded currentSubmission #" + currentSubmission + " for problem " + sub.toString()); + } + updateRunRow(sub, event.getWhoModifiedRun(), true); + // setup for next submission; if last one clean things up. + currentSubmission++; + if(currentSubmission >= submissionFileList.size()) { + clearSubmissionFiles(); + } else { + submitNextSubmission(); + } + } + } + + @Override + public void refreshRuns(RunEvent event) { + reloadRunList(); + } + + @Override + public void runChanged(RunEvent event) { + SubmissionSample sub = getSubmission(event); + if(sub != null) { + updateRunRow(sub, event.getWhoModifiedRun(), true); + } + } + + @Override + public void runRemoved(RunEvent event) { + SubmissionSample sub = getSubmission(event); + if(sub != null) { + updateRunRow(sub, event.getWhoModifiedRun(), true); + } + } + + private SubmissionSample getSubmission(RunEvent event) + { + Run run = event.getRun(); + + // We are only interested in runs we submitted + if(run.getSubmitter().equals(getContest().getClientId())) { + for(SubmissionSample sub : submissionList) { + Run subRun = sub.getRun(); + // Check run numbers if this submission has a run + if(subRun != null && subRun.getNumber() == run.getNumber()) { + sub.setRun(run); + return(sub); + } + } + } + return(null); + } + } + } // @jve:decl-index=0:visual-constraint="10,10" diff --git a/src/edu/csus/ecs/pc2/ui/SubmitSubmissionsPane.java b/src/edu/csus/ecs/pc2/ui/SubmitSubmissionsPane.java index ebe44a2df..e5fcf9f27 100644 --- a/src/edu/csus/ecs/pc2/ui/SubmitSubmissionsPane.java +++ b/src/edu/csus/ecs/pc2/ui/SubmitSubmissionsPane.java @@ -1,6 +1,7 @@ // Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.ui; +import java.awt.BorderLayout; import java.awt.Color; import java.awt.FlowLayout; import java.awt.Font; @@ -10,6 +11,7 @@ import java.util.List; import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -19,14 +21,13 @@ import edu.csus.ecs.pc2.core.IInternalController; import edu.csus.ecs.pc2.core.model.IInternalContest; +import edu.csus.ecs.pc2.list.SubmissionSample; import edu.csus.ecs.pc2.ui.team.QuickSubmitter; -import java.awt.BorderLayout; -import javax.swing.JCheckBox; /** * A UI that to submit files found in a CDP. - * - * + * + * * @author Douglas A. Lane, PC^2 Team, pc2@ecs.csus.edu */ public class SubmitSubmissionsPane extends JPanePlugin { @@ -36,7 +37,7 @@ public class SubmitSubmissionsPane extends JPanePlugin { private JTextField cdptextField; private JLabel messageLabel; - + private JCheckBox checkBoxSubmitYesSamples; private JCheckBox checkBoxSubmitFailingSamples; @@ -68,14 +69,14 @@ public SubmitSubmissionsPane() { messageLabel.setHorizontalAlignment(SwingConstants.CENTER); messageLabel.setBounds(10, 11, 418, 32); centerPane.add(messageLabel); - - + + checkBoxSubmitYesSamples = new JCheckBox("Submit Yes Samples"); checkBoxSubmitYesSamples.setSelected(true); checkBoxSubmitYesSamples.setToolTipText("Only submit AC sample source"); checkBoxSubmitYesSamples.setBounds(48, 101, 265, 23); centerPane.add(checkBoxSubmitYesSamples); - + checkBoxSubmitFailingSamples = new JCheckBox("Submit Failing (non-AC) Samples"); checkBoxSubmitFailingSamples.setSelected(true); checkBoxSubmitFailingSamples.setToolTipText("Submt all non-AC (Yes) submissions"); @@ -89,6 +90,7 @@ public SubmitSubmissionsPane() { JButton submitRunButton = new JButton("Submit"); submitRunButton.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { submitSampleSubmissions(); } @@ -108,28 +110,33 @@ protected void submitSampleSubmissions() { if (submitall) { List files = submitter.getAllCDPsubmissionFileNames(getContest(), cdptextField.getText()); - + boolean submitYesSamples = checkBoxSubmitYesSamples.isSelected(); boolean submitNoSamples = checkBoxSubmitFailingSamples.isSelected(); - + if (! submitYesSamples || ! submitNoSamples){ files = QuickSubmitter.filterRuns (files, submitYesSamples, submitNoSamples); } - - + + int count = 1; for (File file : files) { System.out.println("Found file " + count + " " + file.getAbsolutePath()); count++; - - + + } int result = FrameUtilities.yesNoCancelDialog(this, "Submit " + files.size() + " sample submissions?", "Submit CDP submissions"); if (result == JOptionPane.YES_OPTION) { - int numberSubmitted = submitter.sendSubmissions(files); + List subList = submitter.sendSubmissions(files); + int numberSubmitted = 0; + + if(subList != null) { + numberSubmitted = subList.size(); + } if (numberSubmitted == files.size()) { showMessage("Submitted all (" + files.size() + ") files/runs."); @@ -166,6 +173,7 @@ public void setContestAndController(IInternalContest inContest, IInternalControl public void showMessage(final String message) { SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { messageLabel.setText(message); messageLabel.setToolTipText(message); diff --git a/src/edu/csus/ecs/pc2/ui/admin/AdministratorView.java b/src/edu/csus/ecs/pc2/ui/admin/AdministratorView.java index aa1a6a88a..e287f62ec 100644 --- a/src/edu/csus/ecs/pc2/ui/admin/AdministratorView.java +++ b/src/edu/csus/ecs/pc2/ui/admin/AdministratorView.java @@ -71,12 +71,13 @@ import edu.csus.ecs.pc2.ui.SitesPane; import edu.csus.ecs.pc2.ui.StandingsHTMLPane; import edu.csus.ecs.pc2.ui.StandingsTablePane; +import edu.csus.ecs.pc2.ui.SubmitSampleRunsPane; import edu.csus.ecs.pc2.ui.TeamStatusPane; import edu.csus.ecs.pc2.ui.UIPlugin; /** * Administrator GUI. - * + * * @author pc2@ecs.csus.edu */ public class AdministratorView extends JFrame implements UIPlugin, ChangeListener { @@ -122,10 +123,10 @@ public class AdministratorView extends JFrame implements UIPlugin, ChangeListene private JPanel aMessagePane = null; private JLabel messageLabel = null; - + /** * This method initializes - * + * */ public AdministratorView() { super(); @@ -134,7 +135,7 @@ public AdministratorView() { /** * This method initializes this - * + * */ private void initialize() { this.setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); @@ -142,18 +143,19 @@ private void initialize() { this.setContentPane(getJPanel()); this.setTitle("PC^2 Administrator"); this.addWindowListener(new java.awt.event.WindowAdapter() { + @Override public void windowClosing(java.awt.event.WindowEvent e) { promptAndExit(); } }); getMainTabbedPanel().addChangeListener(this); - + overRideLookAndFeel(); - + FrameUtilities.centerFrame(this); } - + private void overRideLookAndFeel(){ String value = IniFile.getValue("client.plaf"); if (value != null && value.equalsIgnoreCase("java")){ @@ -163,29 +165,31 @@ private void overRideLookAndFeel(){ FrameUtilities.setNativeLookAndFeel(); } } - + /** * Listeners for admin view. - * + * * This provides a way to refresh the admin view on refresh. - * + * * @author pc2@ecs.csus.edu * @version $Id$ */ - + // $HeadURL$ protected class AdminListeners implements UIPlugin { /** - * + * */ private static final long serialVersionUID = 3733076435840880891L; + @Override public void setContestAndController(IInternalContest inContest, IInternalController inController) { - + inContest.addProfileListener(new ProfileListenerImplementation()); } + @Override public String getPluginTitle() { return "AdminListeners"; } @@ -197,18 +201,20 @@ public String getPluginTitle() { // is NOT started; if both are true then get the ScheduledStartTime, format it, and display it on the Frame. + @Override public void setContestAndController(IInternalContest inContest, IInternalController inController) { this.contest = inContest; this.controller = inController; final JFrame thisFrame = this; updateProfileLabel(); - + AdminListeners adminListeners = new AdminListeners(); adminListeners.setContestAndController(inContest, inController); controller.register(adminListeners); - + SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { controller.startLogWindow(contest); @@ -234,14 +240,14 @@ public void run() { try { CategoriesPane categoriesPane = new CategoriesPane(); addUIPlugin(getConfigureContestTabbedPane(), "Clar Categories", categoriesPane); - + ContestPreloadPane contestPreloadPane = new ContestPreloadPane(); addUIPlugin(getConfigureContestTabbedPane(), "Contests", contestPreloadPane); } catch (Exception e) { logException(e); } } - + AutoJudgesPane autoJudgesPane = new AutoJudgesPane(); addUIPlugin(getConfigureContestTabbedPane(), "Auto Judge", autoJudgesPane); @@ -250,7 +256,7 @@ public void run() { ICPCLoadPane icpcPane = new ICPCLoadPane(); addUIPlugin(getConfigureContestTabbedPane(), "ICPC", icpcPane); - + ImportDataPane importDataPane = new ImportDataPane(); addUIPlugin(getConfigureContestTabbedPane(), "Import Config", importDataPane); @@ -259,7 +265,7 @@ public void run() { LanguagesPane languagesPane = new LanguagesPane(); addUIPlugin(getConfigureContestTabbedPane(), "Languages", languagesPane); - + BalloonSettingsPane balloonSettingsPane = new BalloonSettingsPane(); addUIPlugin(getConfigureContestTabbedPane(), "Notifications", balloonSettingsPane); @@ -302,7 +308,7 @@ public void run() { ConnectionsTablePane connectionsPane = new ConnectionsTablePane(); addUIPlugin(getRunContestTabbedPane(), "Connections", connectionsPane); } - + ClarificationsTablePane clarificationsTablePane = new ClarificationsTablePane(); addUIPlugin(getRunContestTabbedPane(), "Clarifications", clarificationsTablePane); @@ -314,24 +320,27 @@ public void run() { logException(e); } } - + // EventFeedsPane eventFeedsPane = new EventFeedsPane(); // addUIPlugin(getRunContestTabbedPane(), "Event Feeds", eventFeedsPane); ExportDataPane exportPane = new ExportDataPane(); addUIPlugin(getRunContestTabbedPane(), "Export", exportPane); - + FinalizePane finalizePane = new FinalizePane(); addUIPlugin(getRunContestTabbedPane(), "Finalize", finalizePane); - + QuickJudgePane quickJudgePane = new QuickJudgePane(); addUIPlugin(getRunContestTabbedPane(), "Judging Utilities", quickJudgePane); + SubmitSampleRunsPane sampleRunsPane = new SubmitSampleRunsPane(); + addUIPlugin(getRunContestTabbedPane(), "Submit Samples", sampleRunsPane); + if (!controller.isSuppressLoginsPaneDisplay()) { LoginsTablePane loginsTablePane = new LoginsTablePane(); addUIPlugin(getRunContestTabbedPane(), "Logins", loginsTablePane); } - + if (Utilities.isDebugMode()) { try { MessageMonitorPane messageMonitorPane = new MessageMonitorPane(); @@ -354,11 +363,11 @@ public void run() { logException(e); } } - + if (Utilities.isDebugMode()) { try { PlaybackPane playbackPane = new PlaybackPane(); - + addUIPlugin(getRunContestTabbedPane(), "Replay", playbackPane); PluginLoadPane pane = new PluginLoadPane(); pane.setParentTabbedPane(getRunContestTabbedPane()); @@ -367,11 +376,11 @@ public void run() { logException(e); } } - + ReportPane reportPane = new ReportPane(); addUIPlugin(getRunContestTabbedPane(), "Reports", reportPane); - + ResultsComparePane resultsExportComparePane = new ResultsComparePane(); addUIPlugin(getRunContestTabbedPane(), "Results Compare", resultsExportComparePane); @@ -398,7 +407,7 @@ public void run() { setSelectedTab (getRunContestTabbedPane(), "Runs"); setSelectedTab (getConfigureContestTabbedPane(), "Accounts"); - + /** * Clock and frame title. */ @@ -410,7 +419,7 @@ public void run() { contest.addContestTimeListener(new ContestTimeListenerImplementation()); controller.register(contestClockDisplay); - + FrameUtilities.setFrameTitle(thisFrame, contest.getTitle(), contest.getContestTime().isContestRunning(), new VersionInfo()); setVisible(true); } @@ -418,15 +427,15 @@ public void run() { }); } - + /** * Set the tab for the input name. - * + * * @param tabbedPane * @param name */ protected void setSelectedTab(JTabbedPane tabbedPane, String name) { - + for (int i = 0; i < tabbedPane.getComponentCount(); i ++){ String tabTitle = tabbedPane.getTitleAt(i); // System.err.println("For "+tabbedPane.getName()+" found "+tabTitle); @@ -458,13 +467,14 @@ protected void initializeSecurityAlertWindow(IInternalContest inContest) { securityAlertLogWindow.getLog().info("Security Log Started "+versionInfo.getSystemVersionInfo()); } + @Override public String getPluginTitle() { return "Admin GUI"; } /** * This method initializes jPanel - * + * * @return javax.swing.JPanel */ private JPanel getJPanel() { @@ -480,7 +490,7 @@ private JPanel getJPanel() { /** * This method initializes mainTabbedPanel - * + * * @return javax.swing.JTabbedPane */ private JTabbedPane getMainTabbedPanel() { @@ -494,7 +504,7 @@ private JTabbedPane getMainTabbedPanel() { /** * This method initializes statusPanel - * + * * @return javax.swing.JPanel */ private JPanel getStatusPanel() { @@ -507,7 +517,7 @@ private JPanel getStatusPanel() { /** * This method initializes topPanel - * + * * @return javax.swing.JPanel */ private JPanel getTopPanel() { @@ -524,7 +534,7 @@ private JPanel getTopPanel() { /** * This method initializes exitButton - * + * * @return javax.swing.JButton */ private JButton getExitButton() { @@ -534,6 +544,7 @@ private JButton getExitButton() { exitButton.setToolTipText("Click here to Shutdown PC^2"); exitButton.setMnemonic(java.awt.event.KeyEvent.VK_X); exitButton.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(java.awt.event.ActionEvent e) { promptAndExit(); } @@ -576,7 +587,7 @@ protected void showLog(boolean showLogWindow) { /** * This method initializes clockPane - * + * * @return javax.swing.JPanel */ private JPanel getClockPane() { @@ -595,7 +606,7 @@ private JPanel getClockPane() { /** * This method initializes exitButtonPane - * + * * @return javax.swing.JPanel */ private JPanel getExitButtonPane() { @@ -612,7 +623,7 @@ private JPanel getExitButtonPane() { /** * This method initializes padPane - * + * * @return javax.swing.JPanel */ private JPanel getPadPane() { @@ -625,7 +636,7 @@ private JPanel getPadPane() { /** * This method initializes configureContestTabbedPane - * + * * @return javax.swing.JTabbedPane */ private JTabbedPane getConfigureContestTabbedPane() { @@ -639,7 +650,7 @@ private JTabbedPane getConfigureContestTabbedPane() { /** * This method initializes runContestTabbedPane - * + * * @return javax.swing.JTabbedPane */ private JTabbedPane getRunContestTabbedPane() { @@ -649,6 +660,7 @@ private JTabbedPane getRunContestTabbedPane() { return runContestTabbedPane; } + @Override public void stateChanged (ChangeEvent e) { if (e.getSource()==getMainTabbedPanel()) { //change all mainpanel tab text to black @@ -656,7 +668,7 @@ public void stateChanged (ChangeEvent e) { for (int i=0; i 1){ // System.out.println("debug profile is "+model.getProfile().getName()); @@ -694,7 +727,7 @@ public void mouseClicked(java.awt.event.MouseEvent e) { /** * This method initializes exitPanel - * + * * @return javax.swing.JPanel */ private JPanel getExitPanel() { @@ -712,7 +745,7 @@ private JPanel getExitPanel() { /** * This method initializes exitButton - * + * * @return javax.swing.JButton */ private JButton getExitButton() { @@ -722,6 +755,7 @@ private JButton getExitButton() { exitButton.setMnemonic(KeyEvent.VK_X); exitButton.setToolTipText("Click here to Shutdown PC^2"); exitButton.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(java.awt.event.ActionEvent e) { promptAndExit(); } @@ -733,13 +767,14 @@ public void actionPerformed(java.awt.event.ActionEvent e) { private void showMessage(final String string) { SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { messageLabel.setText(string); } }); } - + private void updateProfileLabel() { int numberProfiles = model.getProfiles().length; @@ -752,6 +787,7 @@ private void updateProfileLabel() { final String message = s; SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { messageLabel.setText(message); messageLabel.setToolTipText("Version "+versionInfo.getVersionNumber()+" (Build "+versionInfo.getBuildNumber()+")"); @@ -759,35 +795,39 @@ public void run() { }); } - + /** - * + * * @author pc2@ecs.csus.edu * @version $Id$ */ - + // $HeadURL$ protected class ProfileListenerImplementation implements IProfileListener { + @Override public void profileAdded(ProfileEvent event) { updateProfileLabel(); } + @Override public void profileChanged(ProfileEvent event) { updateProfileLabel(); } + @Override public void profileRemoved(ProfileEvent event) { // ignore - + } + @Override public void profileRefreshAll(ProfileEvent profileEvent) { updateProfileLabel(); } } - + } // @jve:decl-index=0:visual-constraint="10,10" diff --git a/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java b/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java index 47febe482..d3f1b5b91 100644 --- a/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java +++ b/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java @@ -13,17 +13,20 @@ import edu.csus.ecs.pc2.core.model.Language; import edu.csus.ecs.pc2.core.model.Problem; import edu.csus.ecs.pc2.imports.ccs.IContestLoader; +import edu.csus.ecs.pc2.list.SubmissionSample; import edu.csus.ecs.pc2.ui.UIPlugin; /** * Submit runs from CDP submissions/. - * + * * @author Douglas A. Lane, PC^2 Team, pc2@ecs.csus.edu */ public class QuickSubmitter implements UIPlugin { private static final long serialVersionUID = 7640178138750506786L; + private static String DEFAULT_SUBMISSION_TYPE = "unknown"; + private IInternalController controller; private IInternalContest contest; @@ -32,7 +35,7 @@ public class QuickSubmitter implements UIPlugin { /** * Returns list of all files under dir path. - * + * * @param dir * @return */ @@ -69,9 +72,9 @@ public void setContestAndController(IInternalContest inContest, IInternalControl /** * Get all CDP submission filenames. - * + * * Example files under config\sumit\submissions - * + * * @param mycontest * @param cdpConfigdir CDP config/ dir * @return @@ -94,48 +97,74 @@ public List getAllCDPsubmissionFileNames(IInternalContest mycontest, Strin /** * submit runs for all input files. Guesses language and problem from file path and extension. - * + * * Will guess langauge and problem based on path - * + * * @see #guessLanguage(IInternalContest, String) * @see #guessProblem(IInternalContest, String) - * + * * @param a list of files to submit * @return count of files sucessfully submitted/added. */ - public int sendSubmissions(List filesToSubmit) { + public List sendSubmissions(List filesToSubmit) { + + List subList = new ArrayList(); + SubmissionSample sub; - int numberSubmitted = 0; - for (File file : filesToSubmit) { - try { - - Language language = LanguageUtilities.guessLanguage(getContest(), file.getAbsolutePath()); - if (language == null) { - String ext = LanguageUtilities.getExtension(file.getAbsolutePath()); - log.log(Level.WARNING, "Cannot identify language for ext= " + ext + " = Can not send submission for file " + file.getAbsolutePath()); - } else { - Problem problem = guessProblem(getContest(), file.getAbsolutePath()); - try { - controller.submitJudgeRun(problem, language, file.getAbsolutePath(), null); - log.log(Level.INFO, "submitted run with language " + language + " and problem " + problem); - numberSubmitted++; - } catch (Exception e) { - log.log(Level.SEVERE, "problem sending run for file " + file.getAbsolutePath() + " " + e.getMessage(), e); - } + sub = sendSubmission(file); + if(sub == null) { + break; + } + subList.add(sub); + } + + return subList; + } + + /** + * submit a single run + * + * Will guess langauge and problem based on path + * + * @see #guessLanguage(IInternalContest, String) + * @see #guessProblem(IInternalContest, String) + * + * @param File object to submit + * @return the SubmissionSample if it was submitted, null otherwise + */ + public SubmissionSample sendSubmission(File file) { + + SubmissionSample subResult = null; + String filePath = file.getAbsolutePath(); + try { + + Language language = LanguageUtilities.guessLanguage(getContest(), filePath); + if (language == null) { + String ext = LanguageUtilities.getExtension(file.getAbsolutePath()); + log.log(Level.WARNING, "Cannot identify language for ext= " + ext + " = Can not send submission for file " + filePath); + } else { + Problem problem = guessProblem(getContest(), filePath); + try { + controller.submitJudgeRun(problem, language, filePath, null); + log.log(Level.INFO, "submitted run with language " + language + " and problem " + problem + " source: " + filePath); + subResult = new SubmissionSample(problem.getShortName(), problem.getElementId(), + language.getDisplayName(), language.getElementId(), guessSubmissionType(file.getParent()), file); + } catch (Exception e) { + log.log(Level.SEVERE, "problem sending run for file " + filePath + " " + e.getMessage(), e); } - } catch (Exception e) { - e.printStackTrace(); - log.log(Level.SEVERE, "problem sending run for file " + file.getAbsolutePath() + " " + e.getMessage(), e); } + } catch (Exception e) { + e.printStackTrace(); + log.log(Level.SEVERE, "problem sending run for file " + filePath + " " + e.getMessage(), e); } - - return numberSubmitted; + + return subResult; } /** * Guess problem based on short problem name found in path. - * + * * @param contest2 * @param absolutePath * @return @@ -150,6 +179,25 @@ private Problem guessProblem(IInternalContest contest2, String absolutePath) { return null; } + /** + * Determine type of judge's submission based on the folder after "submissions/" + * + * @param filePath File to check + * @return String which is the type + */ + private String guessSubmissionType(String filePath) { + + int iSub = filePath.lastIndexOf(File.separator); + String retType; + + if(iSub != -1) { + retType = filePath.substring(iSub+1); + } else { + retType = DEFAULT_SUBMISSION_TYPE; + } + return(retType); + } + public IInternalContest getContest() { return contest; } @@ -161,19 +209,19 @@ public String getPluginTitle() { /** * List of files that match filter. - * + * * @param files * @param submitYesSamples output all AC/Yes sample file name * @param submitNoSamples output all non AC/Yes sample file name * @return list of files matching filter. */ public static List filterRuns(List files, boolean submitYesSamples, boolean submitNoSamples) { - + List outFiles = new ArrayList<>(); for (File file : files) { String path = file.getAbsolutePath().replace("\\", "/"); boolean isYes = path.indexOf("/accepted/") != -1; - + if (submitYesSamples && isYes){ outFiles.add(file); } @@ -181,7 +229,7 @@ public static List filterRuns(List files, boolean submitYesSamples, outFiles.add(file); } } - + return outFiles; } } From f7d3ec3bf8ab062a88c2036c19a205ad35332370 Mon Sep 17 00:00:00 2001 From: John Buck Date: Mon, 17 Jun 2024 16:51:46 -0400 Subject: [PATCH 03/10] i_232 Show detailed timings for each test case Allow user to click on a run's max execution time to show all execution times for each test case for that run. --- reject.ini | 21 + .../core/list/StringToDoubleComparator.java | 38 + .../csus/ecs/pc2/list/SubmissionSample.java | 9 - .../csus/ecs/pc2/ui/SampleResultsFrame.java | 86 ++ .../csus/ecs/pc2/ui/SampleResultsPane.java | 816 ++++++++++++++++++ .../csus/ecs/pc2/ui/SampleResultsRowData.java | 54 ++ .../ecs/pc2/ui/SampleResultsTableModel.java | 196 +++++ .../csus/ecs/pc2/ui/SubmitSampleRunsPane.java | 273 ++++-- 8 files changed, 1422 insertions(+), 71 deletions(-) create mode 100644 reject.ini create mode 100644 src/edu/csus/ecs/pc2/core/list/StringToDoubleComparator.java create mode 100644 src/edu/csus/ecs/pc2/ui/SampleResultsFrame.java create mode 100644 src/edu/csus/ecs/pc2/ui/SampleResultsPane.java create mode 100644 src/edu/csus/ecs/pc2/ui/SampleResultsRowData.java create mode 100644 src/edu/csus/ecs/pc2/ui/SampleResultsTableModel.java diff --git a/reject.ini b/reject.ini new file mode 100644 index 000000000..1327f11e9 --- /dev/null +++ b/reject.ini @@ -0,0 +1,21 @@ +# +# Purpose: reject.ini judgements for GNY Regional 2023 Fall +# +# with CLICS Validator judgements at bottom +# +Yes|AC +yes|ac +correct|AC +compiler error|CE +run error|RTE +timelimit|TLE +wrong answer|WA +memory limit|MLE +no output|NO +output limit|OLE +Wrong Answer|WA +No - Wrong answer|WA +Incomplete output|WA +incomplete output|WA +incorrect output format|WA +Undetermined|WA diff --git a/src/edu/csus/ecs/pc2/core/list/StringToDoubleComparator.java b/src/edu/csus/ecs/pc2/core/list/StringToDoubleComparator.java new file mode 100644 index 000000000..8c2036d09 --- /dev/null +++ b/src/edu/csus/ecs/pc2/core/list/StringToDoubleComparator.java @@ -0,0 +1,38 @@ +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +package edu.csus.ecs.pc2.core.list; + +import java.io.Serializable; +import java.util.Comparator; + +/** + * Compare the two strings as numbers + *

    + * Simply convert to integers and compare + * + * @version $Id$ + * @author John Buck + */ + +// $HeadURL$ +// $Id$ + +public class StringToDoubleComparator implements Comparator, Serializable { + + private static final long serialVersionUID = 1L; + + @Override + public int compare(String NumOne, String NumTwo) { + double dResult = 0; + try { + dResult = Double.parseDouble(NumOne) - Double.parseDouble(NumTwo); + } catch(Exception exception) { + return(NumOne.compareTo(NumTwo)); + } + if(dResult < 0) + return(-1); + if(dResult > 0) { + return(1); + } + return(0); + } +} diff --git a/src/edu/csus/ecs/pc2/list/SubmissionSample.java b/src/edu/csus/ecs/pc2/list/SubmissionSample.java index 5dedb8a6f..5234d2d68 100644 --- a/src/edu/csus/ecs/pc2/list/SubmissionSample.java +++ b/src/edu/csus/ecs/pc2/list/SubmissionSample.java @@ -42,15 +42,6 @@ public Run getRun() { return run; } - // JB this is wrong - needs fixing - public boolean isRunForSubmission(Run r) { - - if(srcFile != null) { - return(false); - } - return(false); - } - public String getProblemName() { return problemName; } diff --git a/src/edu/csus/ecs/pc2/ui/SampleResultsFrame.java b/src/edu/csus/ecs/pc2/ui/SampleResultsFrame.java new file mode 100644 index 000000000..e82592c74 --- /dev/null +++ b/src/edu/csus/ecs/pc2/ui/SampleResultsFrame.java @@ -0,0 +1,86 @@ +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +package edu.csus.ecs.pc2.ui; + +import java.awt.Dimension; + +import edu.csus.ecs.pc2.core.IInternalController; +import edu.csus.ecs.pc2.core.model.IInternalContest; +import edu.csus.ecs.pc2.core.model.Problem; +import edu.csus.ecs.pc2.core.model.ProblemDataFiles; +import edu.csus.ecs.pc2.core.model.Run; +import edu.csus.ecs.pc2.core.model.RunFiles; +import edu.csus.ecs.pc2.list.SubmissionSample; + +/** + * Judge's sample results details + * + * @author John Buck + */ + +public class SampleResultsFrame extends javax.swing.JFrame implements UIPlugin { + + /** + * + */ + private static final long serialVersionUID = 1L; + + private SampleResultsPane multiSetOutputViewerPane = null; + + /** + * Constructor which initializes this Frame to contain a {@link #multiSetOutputViewerPane}. + * Invokers are expected to call {@link #setContestAndController(IInternalContest, IInternalController)} + * and then {@link #setData(Run, RunFiles, Problem, ProblemDataFiles)} prior to calling + * {@link #setVisible(boolean)} on the frame. + * + */ + public SampleResultsFrame() { + super(); + initialize(); + } + + /** + * This method initializes this Frame to contain a {@link #multiSetOutputViewerPane}. + * Invokers are expected to call {@link #setContestAndController(IInternalContest, IInternalController)} + * and then {@link #setData(SubmissionSample)} prior to calling + * {@link #setVisible(boolean)} on the frame. + * + */ + private void initialize() { + this.setSize(new Dimension(860, 400)); + this.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + this.setContentPane(getMultiTestSetOutputViewerPane()); + this.setTitle("Sample Results"); + this.setLocationRelativeTo(null); + } + + public SampleResultsPane getMultiTestSetOutputViewerPane() { + if (multiSetOutputViewerPane == null) { + multiSetOutputViewerPane = new SampleResultsPane(); + } + return multiSetOutputViewerPane; + } + + @Override + public void setContestAndController(IInternalContest inContest, IInternalController inController) { + + getMultiTestSetOutputViewerPane().setContestAndController(inContest, inController); + + } + + @Override + public String getPluginTitle() { + return "Judge's Sample Submission Frame"; + } + + + public void setData(SubmissionSample sub) { + getMultiTestSetOutputViewerPane().setData(sub); + setTitle ("Sample Results for Run " + sub.getRun().getNumber()); + } + + public void clearData() + { + getMultiTestSetOutputViewerPane().resetResultsTable(); + } + +} // @jve:decl-index=0:visual-constraint="10,10" diff --git a/src/edu/csus/ecs/pc2/ui/SampleResultsPane.java b/src/edu/csus/ecs/pc2/ui/SampleResultsPane.java new file mode 100644 index 000000000..ae235c638 --- /dev/null +++ b/src/edu/csus/ecs/pc2/ui/SampleResultsPane.java @@ -0,0 +1,816 @@ +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +package edu.csus.ecs.pc2.ui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Arrays; +import java.util.Vector; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTabbedPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.border.LineBorder; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableModel; + +import edu.csus.ecs.pc2.core.IInternalController; +import edu.csus.ecs.pc2.core.log.Log; +import edu.csus.ecs.pc2.core.model.IInternalContest; +import edu.csus.ecs.pc2.core.model.Language; +import edu.csus.ecs.pc2.core.model.Problem; +import edu.csus.ecs.pc2.core.model.ProblemDataFiles; +import edu.csus.ecs.pc2.core.model.Run; +import edu.csus.ecs.pc2.core.model.RunFiles; +import edu.csus.ecs.pc2.core.model.RunTestCase; +import edu.csus.ecs.pc2.list.SubmissionSample; +import edu.csus.ecs.pc2.ui.cellRenderer.LinkCellRenderer; +import edu.csus.ecs.pc2.ui.cellRenderer.RightJustifiedCellRenderer; +import edu.csus.ecs.pc2.ui.cellRenderer.TestCaseResultCellRenderer; + +/** + * Multiple data set viewer pane. + * + * @author John Buck + * @version $Id: AutoJudgeSettingsPane.java 2825 2014-08-12 23:22:50Z boudreat $ + */ + +public class SampleResultsPane extends JPanePlugin implements TableModelListener { + + private static final long serialVersionUID = 1L; + + /** + * list of columns + */ + protected enum COLUMN { + DATASET_NUM, RESULT, TIME, JUDGE_OUTPUT, JUDGE_DATA + }; + + // define the column headers for the table of results + private String[] columnNames = { "Data Set #", "Result", "Time (s)", + "Judge's Output", "Judge's Data" }; + + private JPanel centerPanel = null; + + private JTable resultsTable; + + private JLabel lblProblemTitle; + + private JLabel lblRunID; + + private Run currentRun; + + private Problem currentProblem; + + private ProblemDataFiles currentProblemDataFiles; + + private JLabel lblLanguage; + + private JScrollPane resultsScrollPane; + + private Log log ; + + private JButton btnCancel; + + private JTabbedPane multiTestSetTabbedPane; + + private JPanel resultsPane; + + private JPanel resultsPaneHeaderPanel; + + private JPanel resultsPaneButtonPanel; + + private JButton resultsPaneCloseButton; + private JLabel lblTotalTestCases; + private JLabel lblNumTestCasesActuallyRun; + private JLabel lblNumFailedTestCases; + private Component horizontalGlue_9; + + private boolean debug = false; + + /** + * Constructs an instance of a plugin pane for viewing multi-testset output values. + * + */ + public SampleResultsPane() { + super(); + initialize(); + } + + /** + * This method initializes the pane. + * + */ + private void initialize() { + this.setLayout(new BorderLayout()); + this.setSize(new Dimension(717, 363)); + this.add(getCenterPanel(), java.awt.BorderLayout.CENTER); + + // TODO Bug 918 + + } + + @Override + public void setContestAndController(IInternalContest inContest, IInternalController inController) { + super.setContestAndController(inContest, inController); + log = getController().getLog(); + } + + @Override + public String getPluginTitle() { + return "Sample Execute Times Pane"; + } + + /** + * This method initializes and returns a JPanel containing a + * JTabbedPane holding the output results and options panes. Note that the method + * does not fill in any live data; that cannot be done until the View Pane's + * "setData()" method has been invoked, which doesn't happen until after construction + * of the View Pane is completed. + * + * @return javax.swing.JPanel + */ + private JPanel getCenterPanel() { + + if (centerPanel == null) { + + centerPanel = new JPanel(); + BorderLayout cpBorderLayout = new BorderLayout(); + cpBorderLayout.setVgap(0); + centerPanel.setLayout(cpBorderLayout); + + centerPanel.add(getResultsPane(), BorderLayout.CENTER); + + + } + return centerPanel; + } + + + /** + * Defines and returns a JPanel containing a Header Panel describing the current run, a JTable displaying + * test case results for the Run, and a button panel with various control Buttons. + * + * @return the Results Pane JPanel + */ + private JPanel getResultsPane() { + + if (resultsPane == null) { + + resultsPane = new JPanel(); + resultsPane.setName("View Execution Times"); + resultsPane.setLayout(new BorderLayout(0, 0)); + + // add a header for holding labels to the results panel + resultsPane.add(getResultsPaneHeaderPanel(),BorderLayout.NORTH); + + //add a scrollpane holding the actual test set results + resultsPane.add(getResultsScrollPane(), BorderLayout.CENTER); + + //add a button panel at the bottom + resultsPane.add(getResultsPaneButtonPanel(), BorderLayout.SOUTH); + } + return resultsPane; + + } + + /** + * Defines a header panel for the results pane containing information about the run whose results are being displayed. + * Note that this accessor does not fill in actual data; that cannot be done until the Test Results pane is populated + * via a call to {@link #setData(Run, RunFiles, Problem, ProblemDataFiles)}. + * + * @return a JPanel containing run information + */ + private JPanel getResultsPaneHeaderPanel() { + + if (resultsPaneHeaderPanel == null) { + + resultsPaneHeaderPanel = new JPanel(); + resultsPaneHeaderPanel.setBorder(new LineBorder(Color.BLUE, 2)); + + resultsPaneHeaderPanel.add(getRunIDLabel()); + + Component horizontalGlue_1 = Box.createHorizontalGlue(); + horizontalGlue_1.setPreferredSize(new Dimension(20, 20)); + resultsPaneHeaderPanel.add(horizontalGlue_1); + + // add a label to the header showing the Problem for which this set of test results applies + resultsPaneHeaderPanel.add(getProblemTitleLabel()); + + Component horizontalGlue = Box.createHorizontalGlue(); + horizontalGlue.setPreferredSize(new Dimension(20, 20)); + resultsPaneHeaderPanel.add(horizontalGlue); + + Component horizontalGlue_2 = Box.createHorizontalGlue(); + horizontalGlue_2.setPreferredSize(new Dimension(20, 20)); + resultsPaneHeaderPanel.add(horizontalGlue_2); + + resultsPaneHeaderPanel.add(getLanguageLabel()); + + Component horizontalGlue_8 = Box.createHorizontalGlue(); + horizontalGlue_8.setPreferredSize(new Dimension(20, 20)); + resultsPaneHeaderPanel.add(horizontalGlue_8); + resultsPaneHeaderPanel.add(getTotalTestCasesLabel()); + resultsPaneHeaderPanel.add(getHorizontalGlue_9()); + + // add a label to the header showing the total number of test cases for this problem + resultsPaneHeaderPanel.add(getNumTestCasesActuallyRunLabel()); + + Component horizontalGlue_7 = Box.createHorizontalGlue(); + horizontalGlue_7.setPreferredSize(new Dimension(20, 20)); + resultsPaneHeaderPanel.add(horizontalGlue_7); + + resultsPaneHeaderPanel.add(getNumFailedTestCasesLabel()); + } + return resultsPaneHeaderPanel; + } + + /** + * Returns a {@link JScrollPane} containing a {@link JTable} for holding test case results. + * @return + */ + private JScrollPane getResultsScrollPane() { + + if (resultsScrollPane == null) { + + // add a scrollpane to hold the table of results + resultsScrollPane = new JScrollPane(); + + // create an (empty) table of results and put it in the scrollpane + resultsTable = new JTable(12,7); + resultsTable.setValueAt(true, 0, 0); + resultsScrollPane.setViewportView(resultsTable); + } + return resultsScrollPane; + } + + /** + * Returns a JPanel containing control buttons for the Results Pane. + * @return the resultsPaneButtonPanel + */ + private JPanel getResultsPaneButtonPanel() { + + if (resultsPaneButtonPanel == null) { + + resultsPaneButtonPanel = new JPanel(); + + // add a control button to dismiss the frame + resultsPaneButtonPanel.add(getResultsPaneCloseButton()); + } + return resultsPaneButtonPanel; + } + + /** + * Returns a JButton whose action is to depends on whether it is invoked from the Options pane or the Results pane. + * If invoked from the Options pane, it simply makes the Results pane the active pane. + * If invoked from the Results pane, it closes any open child windows (such as a {@link MultiFileComparator}), and + * then disposes this MultiTestSetOutputViewerPane's parent window. + * + * Note that the Close button appears on both the Options pane and the Results pane -- but it is the same button, + * not two different instances (this is a result of the Singleton pattern implementation). + * + * Addendum: the above was the INTENT, and it is legal in Java/Swing to code it that way. However, doing so generates + * an error in the WindowBuilder (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=341111). As a result, the code was + * refactored to provide two distinct Close buttons: one for the Options pane and a different one for the Results pane. + * + * @return the Close JButton + */ + private JButton getResultsPaneCloseButton() { + if (resultsPaneCloseButton == null) { + resultsPaneCloseButton = new JButton("Close"); + + //add an action handler for the Close button + resultsPaneCloseButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Window parentFrame = SwingUtilities.getWindowAncestor(resultsPaneCloseButton); + if (parentFrame != null) { + parentFrame.dispose(); + } + } + }); + } + return resultsPaneCloseButton; + } + + private JLabel getTotalTestCasesLabel() { + if (lblTotalTestCases == null) { + lblTotalTestCases = new JLabel("Total Test Cases: XXX"); + } + return lblTotalTestCases; + } + + /** + * @return + */ + private JLabel getNumTestCasesActuallyRunLabel() { + if (lblNumTestCasesActuallyRun == null) { + lblNumTestCasesActuallyRun = new JLabel("Test Cases Run: XXX"); + } + return lblNumTestCasesActuallyRun; + } + + /** + * @return + */ + private JLabel getNumFailedTestCasesLabel() { + if (lblNumFailedTestCases == null) { + lblNumFailedTestCases = new JLabel("Failed: XXX"); + } + return lblNumFailedTestCases; + } + + private JLabel getLanguageLabel() { + if (lblLanguage == null) { + lblLanguage = new JLabel("Language: XXX"); + } + return lblLanguage; + } + + private JLabel getRunIDLabel() { + if (lblRunID == null) { + lblRunID = new JLabel("Run ID: XXX"); + } + + return lblRunID; + } + + private JLabel getProblemTitleLabel() { + if (lblProblemTitle == null) { + lblProblemTitle = new JLabel("Problem: XXX"); + } + return lblProblemTitle; + } + + private void populateGUI() { + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + // fill in the basic header information + String letter = currentProblem.getLetter(); + String shortName = currentProblem.getShortName(); + // HACK around EditProblemPane not requiring (or setting) a letter + if (letter == null || letter.equals("null") || letter.equals("")) { + Problem[] problems = getContest().getProblems(); + for (int i = 0; i < problems.length; i++) { + if (problems[i].equals(currentProblem)) { + int asciiLetter = i+65; + letter = Character.toString((char)asciiLetter); + } + } + } + // HACK around EditProblempane not requiring (or setting) a shortName + if (shortName == null || shortName.equals("")) { + shortName = currentProblem.getDisplayName().toLowerCase().trim(); + int spaceIndex = shortName.indexOf(" "); + if (spaceIndex > 0) { + shortName = shortName.substring(0, spaceIndex); + } + } + getProblemTitleLabel().setText("Problem: " + letter + " - " + shortName); + getRunIDLabel().setText("Run ID: " + currentRun.getNumber()); + getLanguageLabel().setText("Language: " + getCurrentRunLanguageName()); + + //display in the GUI the total test cases configured in the problem + int totalTestCases = currentProblem.getNumberTestCases(); + getTotalTestCasesLabel().setText("Total Test Cases: " + totalTestCases); + + // get the actually-run test case results for the current run + RunTestCase[] testCases = getCurrentTestCaseResults(currentRun); + + // fill in the test case summary information + if (testCases == null || testCases.length==0) { + getNumTestCasesActuallyRunLabel().setText("Test Cases Run: 0"); + } else { + getNumTestCasesActuallyRunLabel().setText("Test Cases Run: " + testCases.length); + } + + //set the status label to the default (blank) + getNumFailedTestCasesLabel().setForeground(Color.black); + getNumFailedTestCasesLabel().setText(""); + + int failedCount = getNumFailedTestCases(testCases); + + if (!currentProblem.isValidatedProblem()) { + // problem is not validated, cannot be failed or passed + getNumFailedTestCasesLabel().setForeground(Color.black); + getNumFailedTestCasesLabel().setText("(No validator)"); + } else if (failedCount > 0) { + getNumFailedTestCasesLabel().setForeground(Color.red); + getNumFailedTestCasesLabel().setText("Failed: " + failedCount); + } else if (failedCount == 0 && testCases!=null && testCases.length>0) { + getNumFailedTestCasesLabel().setForeground(Color.green); + getNumFailedTestCasesLabel().setText("ALL PASSED"); + } + + resultsTable = getResultsTable(testCases); + getResultsScrollPane().setViewportView(resultsTable); + } + + }); + + } + + + private int getNumFailedTestCases(RunTestCase[] testCases) { + int failed = 0 ; + if (testCases != null) { + for (int i = 0; i < testCases.length; i++) { + if (!testCases[i].isPassed()) { + failed++; + // int num = i+1; + // System.out.println("Found failed test case: " + num); + } + } + } +// System.out.println (" (including " + failed + " failed cases)"); + return failed; + } + + /** + * Returns the name of the language used in the "current run" defined by the field "currentRun". + * + * @return the language display name as defined by the toString() method of the defined language. + */ + private String getCurrentRunLanguageName() { + Language language = getContest().getLanguage(currentRun.getLanguageId()); + return language.toString(); + } + + /** + * Looks at all the TestCaseResults for a run and filters + * that list to just the most recent. + * + * @param run + * @return most recent RunTestCaseResults + */ + private RunTestCase[] getCurrentTestCaseResults(Run run) { + RunTestCase[] testCases = null; + RunTestCase[] allTestCases = run.getRunTestCases(); + // hope the lastTestCase has the highest testNumber.... + if (allTestCases != null && allTestCases.length > 0) { + testCases = new RunTestCase[allTestCases[allTestCases.length-1].getTestNumber()]; + for (int i = allTestCases.length-1; i >= 0; i--) { + RunTestCase runTestCaseResult = allTestCases[i]; + int testCaseNumIndex = runTestCaseResult.getTestNumber()-1; + if (testCases[testCaseNumIndex] == null) { + testCases[testCaseNumIndex] = runTestCaseResult; + if (testCaseNumIndex == 0) { + break; + } + } + } + } + return testCases; + } + + /** + * Loads the result table with data for all test cases. + */ + private void loadTableWithAllTestCaseResults() { + + // get the test case results for the current run + RunTestCase[] allTestCases = getCurrentTestCaseResults(currentRun); + + //build a new table with the test cases and install it in the scrollpane + resultsTable = getResultsTable(allTestCases); + resultsScrollPane.setViewportView(resultsTable); + } + + /** + * Loads the result table with data for failed test cases (only). + * The initial test for "failed" is to check the RunTestCase isPassed() flag, which is based on the value "passed" which is + * stored in the RunTestCase when it is constructed (see @link{Executable#executeAndValidateDataSet}). + * This value is TRUE (meaning isPassed() returns true) if and only if: + * the submitted program was successfully executed + * AND the problem has a validator + * AND method validateProgram() returned true (indicating the problem was correctly solved for the specified test case) + * AND the ExecutionData object for the run indicates that the submission solved the problem for the specified data case. + * (the ExecutionData object indicates the program solved the problem if: + * the program compiled successfully + * AND the system was able to successfully execute the program + * AND the program did not exceed the runtime limit + * AND the validator program ran successfully + * AND there were no exceptions during Validator execution + * AND the result string returned by the Validator was "accepted". + * The ExecutionData object returns false (the problem was NOT solved) if any of these conditions is false. + * ) + * If any of the above conditions is not true, isPassed() returns false. + * + * The above in turn means that test cases for runs where the Problem has no Validator will be considered "failed" (isPassed()==false) + * -- but this is not really what the table should contain for "failed test cases". + * Therefore an additional check for "isValidated()" needs to be made. + * + * The same is true for test cases which were never executed -- they will be considered "failed" but they really shouldn't + * be displayed in a table of "failed test cases". + * TODO: currently there is no easy way to determine whether a Test Case was actually executed, unless we assume that the + * mere presence of a TestCaseResult indicates that it was executed... + * + */ + private void loadTableWithFailedTestCases() { + + // get the test case results for the current run + RunTestCase[] allTestCases = getCurrentTestCaseResults(currentRun); + + //extract failed cases into a Vector (list) + Vector failedTestCaseList = new Vector(); + if (allTestCases != null) { + for (int i = 0; i < allTestCases.length; i++) { + //check for actual "failure" - ignoring "no validator" and "not executed" cases + // TODO: figure out how to implement the test for "wasExecuted"... + if (!allTestCases[i].isPassed() && allTestCases[i].isValidated() /* && allTestCases[i].wasExecuted() */ ) { + failedTestCaseList.add(allTestCases[i]); + } + } + } + + //convert Vector to array + RunTestCase[] failedTestCases = failedTestCaseList.toArray(new RunTestCase[failedTestCaseList.size()]); + + //build a new table with just the failed cases and install it in the scrollpane + resultsTable = getResultsTable(failedTestCases); + resultsScrollPane.setViewportView(resultsTable); + } + + /** + * Returns a JTable containing the results information for the specified set of test cases. + * The method sets not only the table data model but also the appropriate cell renderers and + * action/mouse listeners for the table. + */ + private JTable getResultsTable(RunTestCase [] testCases) { + + final JTable localResultsTable; + + //create the results table + TableModel tableModel = new SampleResultsTableModel(getContest(), testCases, columnNames) ; + + tableModel.addTableModelListener(this); + + if (debug) { + System.out.println("In getResultsTable(); table model contains:"); + System.out.println("--------------"); + for (int row = 0; row < tableModel.getRowCount(); row++) { + for (int col = 0; col < tableModel.getColumnCount(); col++) { + System.out.print("[" + tableModel.getValueAt(row, col) + "]"); + } + System.out.println(); + } + System.out.println("--------------"); + } + + localResultsTable = new JTable(tableModel); + + //set the desired options on the table + localResultsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + localResultsTable.setFillsViewportHeight(true); + localResultsTable.setRowSelectionAllowed(false); + localResultsTable.getTableHeader().setReorderingAllowed(false); + + //initialize column renderers based on column type + + // set a centering renderer on desired table columns + DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer(); + centerRenderer.setHorizontalAlignment(SwingConstants.CENTER); + localResultsTable.getColumn(columnNames[COLUMN.DATASET_NUM.ordinal()]).setCellRenderer(centerRenderer); + + // set a LinkRenderer on those cells containing links + localResultsTable.getColumn(columnNames[COLUMN.JUDGE_OUTPUT.ordinal()]).setCellRenderer(new LinkCellRenderer()); + localResultsTable.getColumn(columnNames[COLUMN.JUDGE_DATA.ordinal()]).setCellRenderer(new LinkCellRenderer()); + + // render Result column as Pass/Fail on Green/Red (if the test case was validated), or else either "" or "(Not Executed)" + localResultsTable.getColumn(columnNames[COLUMN.RESULT.ordinal()]).setCellRenderer(new TestCaseResultCellRenderer()); + + // render Time column right-justified + localResultsTable.getColumn(columnNames[COLUMN.TIME.ordinal()]).setCellRenderer(new RightJustifiedCellRenderer()); + + return localResultsTable; + } + + + /** + * Returns an array containing only test case results in the received array which represent test cases which failed. + * + * That is, removes any "passed" or "not executed" test cases (as well as any null elements) from the received array and + * returns a new array containing whatever is left. + * + * @param testCaseResults - an array of RunTestCaseResults from which non-failures are to be removed + * @return an array of RunTestCaseResults containing only the failed test cases in the received array, + * or returns null if the received array is null or zero-length. + */ + private RunTestCase[] removeNonFailuresFromTestCaseResults(RunTestCase[] testCaseResults) { + + if (testCaseResults!=null && testCaseResults.length>0) { + + if (debug) { + System.out.println("removeNonFailuresFromTestCaseResults(): received an array containing the following test case results: ["); + for (int i=0; i testCaseResultList = new Vector(Arrays.asList(testCaseResults)); + + Vector toBeRemoved = new Vector(); + + //find all passed and non-validated results (non-validated means they couldn't be "passed") + for (RunTestCase res : testCaseResultList) { + if (res==null || res.isPassed() || !res.isValidated()) { + toBeRemoved.add(res); + } + } + //remove all found results from the list + for (RunTestCase removeRes : toBeRemoved) { + testCaseResultList.remove(removeRes); + } + + RunTestCase [] retArray = new RunTestCase[0]; + //return an array of the remaining TestCaseResults (i.e. the ones that "failed") + retArray = testCaseResultList.toArray(retArray); + + if (debug) { + System.out.println("removeNonFailuresFromTestCaseResults(): returning an array containing the following test case results: ["); + for (int i=0; i testCasesInTableModel) { + //yes, there are missing cases; add them to the table + for (int testCaseNum=testCasesInTableModel+1; testCaseNum<=totalTestCaseCount; testCaseNum++) { + //add the current unexecuted test case to the table model + + if (debug) { + System.out.println ("...adding unexecuted test case " + testCaseNum + " to results table"); + } + + //build the variable portions of the row data + String viewJudgeAnswerFile = ""; + if (currentProblem.getAnswerFileName(testCaseNum)!=null && currentProblem.getAnswerFileName(testCaseNum).length()>0) { + viewJudgeAnswerFile = "View"; + } + String viewJudgeDataFile = ""; + if (currentProblem.getDataFileName(testCaseNum)!=null && currentProblem.getDataFileName(testCaseNum).length()>0) { + viewJudgeDataFile = "View"; + } +// "Not Executed", //result string +// "-- ", //execution time (of which there is none since the test case wasn't executed) +// "", //link to team output (none since it wasn't executed) +// "", //link to team compare-with-judge label (disabled since there's no team output) +// "", //link to team stderr (none since it wasn't executed) +// viewJudgeAnswerFile, //link to judge's output (answer file) if any +// viewJudgeDataFile, //link to judge's data if any +// "", //link to validator stdout (none) +// "" //link to validator stderr (none) + SampleResultsRowData rowData = new SampleResultsRowData("Not Executed", "-- ",viewJudgeAnswerFile,viewJudgeDataFile); + tableModel.addRow( + new String(Integer.toString(testCaseNum)), //test case number + rowData); + } + + } else { + if (debug) { + System.out.println("...all test cases are already in the results table."); + } + } + } + + /** + * Clears the given JTable with empty test cases + * + * @param aResultsTable - a JTable expected to already contain one row for each test case which has been executed + */ + public void resetResultsTable() { + if(resultsTable != null) { + //get the table model which defines the current table contents + SampleResultsTableModel tableModel = (SampleResultsTableModel) resultsTable.getModel(); + + //get how many test case rows are already in the table model + int testCasesInTableModel = tableModel.getRowCount(); + + for(int row = testCasesInTableModel-1; row >= 0; row--) { + tableModel.removeRow(row); + } + + // Add exactly one row as a place holder to tell the user judging is taking place + // "Loading", //result string + // "-- ", //execution time (of which there is none since the test case wasn't executed) + // "", //link to team output (none since it wasn't executed) + // "", //link to team compare-with-judge label (disabled since there's no team output) + // "", //link to team stderr (none since it wasn't executed) + // "", //link to judge's output (answer file) if any + // "", //link to judge's data if any + // "", //link to validator stdout (none) + // "" //link to validator stderr (none) + SampleResultsRowData rowData = new SampleResultsRowData("Judging", "-- ", "", ""); + // add new row + tableModel.addRow( + new String("*"), //test case number + rowData); + getNumFailedTestCasesLabel().setForeground(Color.cyan); + getNumFailedTestCasesLabel().setText("(Loading...)"); + + } + } + + /** + * Invoked when table data changes; checks to see if the change took place in the "Select" column and if so + * updates the Compare Selected button (enables or disables it as necessary). + * + * @param e the TableModelEvent describing the change in the table model + */ + @Override + public void tableChanged(TableModelEvent e) { + int column = e.getColumn(); + TableModel model = (TableModel)e.getSource(); + String columnName = model.getColumnName(column); + } + + public void showMessage(final String message) { + JOptionPane.showMessageDialog(this, message); + } + + + public void setData(SubmissionSample sub) { + Run run = sub.getRun(); + + if(run != null) { + Problem problem = getContest().getProblem(sub.getProblem()); + ProblemDataFiles problemDataFiles = getContest().getProblemDataFile(problem); + + + currentRun = run; + currentProblem = problem; + currentProblemDataFiles = problemDataFiles; + populateGUI(); + } + } + + private Component getHorizontalGlue_9() { + if (horizontalGlue_9 == null) { + horizontalGlue_9 = Box.createHorizontalGlue(); + horizontalGlue_9.setPreferredSize(new Dimension(20, 20)); + } + return horizontalGlue_9; + } +} // @jve:decl-index=0:visual-constraint="10,10" diff --git a/src/edu/csus/ecs/pc2/ui/SampleResultsRowData.java b/src/edu/csus/ecs/pc2/ui/SampleResultsRowData.java new file mode 100644 index 000000000..46847dcfa --- /dev/null +++ b/src/edu/csus/ecs/pc2/ui/SampleResultsRowData.java @@ -0,0 +1,54 @@ +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +/** + * + */ +package edu.csus.ecs.pc2.ui; + +/** + * @author John Buck + */ +public class SampleResultsRowData { + private String resultString; + private String time; + private String judgesOutputViewLabel; + private String judgesDataViewLabel; + /** + * @param resultString + * @param time + * @param judgesOutputViewLabel + * @param judgesDataViewLabel + */ + public SampleResultsRowData(String resultString, String time, String judgesOutputViewLabel, String judgesDataViewLabel) { + super(); + this.resultString = resultString; + this.time = time; + this.judgesOutputViewLabel = judgesOutputViewLabel; + this.judgesDataViewLabel = judgesDataViewLabel; + } + + /** + * @return the resultString + */ + public String getResultString() { + return resultString; + } + /** + * @return the time + */ + public String getTime() { + return time; + } + /** + * @return the judgesDataViewLable + */ + public String getJudgesDataViewLabel() { + return judgesDataViewLabel; + } + /** + * @return the judgesOutputViewLable + */ + public String getJudgesOutputViewLabel() { + return judgesOutputViewLabel; + } + +} diff --git a/src/edu/csus/ecs/pc2/ui/SampleResultsTableModel.java b/src/edu/csus/ecs/pc2/ui/SampleResultsTableModel.java new file mode 100644 index 000000000..567be8cb0 --- /dev/null +++ b/src/edu/csus/ecs/pc2/ui/SampleResultsTableModel.java @@ -0,0 +1,196 @@ +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +package edu.csus.ecs.pc2.ui; + +import java.util.Vector; + +import javax.swing.JLabel; +import javax.swing.table.DefaultTableModel; + +import edu.csus.ecs.pc2.core.model.ElementId; +import edu.csus.ecs.pc2.core.model.IInternalContest; +import edu.csus.ecs.pc2.core.model.Problem; +import edu.csus.ecs.pc2.core.model.Run; +import edu.csus.ecs.pc2.core.model.RunTestCase; + +/** + * This class defines a table model for tables holding judge Sample Test Case Results. + * + * @author John Buck + * + */ +public class SampleResultsTableModel extends DefaultTableModel { + private static final long serialVersionUID = 1L; + + private boolean debug = false; + + + /** + * Constructs a Table Model for Sample Test Case Results. The data and columnName values + * are stored in Vectors in the DefaultTableModel parent class. + * @param contest - the contest to which the results in this table model apply (needed for access to problem configuration) + * @param testCaseResults - the data to go in the model + * @param columnNames - Strings defining the table column headers + */ + public SampleResultsTableModel(IInternalContest contest, RunTestCase[] testCaseResults, Object[] columnNames) { + + //create a default table model with zero rows and columns + super (); + + //add the column names to the model + for (int col=0; col0) { + //there is a judge's answer file for this problem for this test case + judgesOutputViewLabel.setText("View"); + } + //update judge's data file link if the problem has a judge's data file + String dataFileName = prob.getDataFileName(row+1); + if (dataFileName!=null && dataFileName.length()>0) { + //there is a judge's data file for this problem for this test case + judgesDataViewLabel.setText("View"); + } + } + } + } + } + + // build the row object and add it to the model + Object[] rowData = new Object[] { testCaseNum, resultLabel, time, + judgesOutputViewLabel, judgesDataViewLabel}; + + super.addRow(rowData); + } + } + } + + /** + * Returns the Class of objects contained in the specified table column. + * The Class is determined by the type of object in the first row of + * the specified column. + */ + @Override + public Class getColumnClass(int col) { + //the data for the model is stored in the parent class vector "dataVector" + @SuppressWarnings("unchecked") + Vector v = (Vector)dataVector.elementAt(0); + return v.elementAt(col).getClass(); + } + + @Override + public int getRowCount() { + return dataVector.size(); + } + + @Override + public int getColumnCount() { + return columnIdentifiers.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return ((Vector)(dataVector.elementAt(rowIndex))).elementAt(columnIndex); + } + + /** + * Returns whether the specified cell is editable, which in the case of a cell containing a checkbox means whether the checkbox can be changed. + * The only editable cells in a Test Case Results table are those in the "select row" + * column; all other cells in all other columns are not editable. Further, the "select row" + * column should only be editable (selectable) when the "Results" column contains either the string + * "Passed" or the string "Failed". (This keeps "Not Executed" test cases from being selectable). + */ + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + + return false; + } + + /** + * Allows adding a row to the table model. + * This method delegates to super.add(); i.e., the add() method in {@link TableModel}. + */ + public void addRow(String testCaseNum, SampleResultsRowData data ) { + + //test case result (passed/failed) + JLabel resultLabel = new JLabel(data.getResultString()); + + //link for viewing judge's output + JLabel judgesOutputViewJLabel = new JLabel(data.getJudgesOutputViewLabel()); + + JLabel judgesDataViewJLabel = new JLabel(data.getJudgesDataViewLabel()); + + + //build the row object and add it to the model + Object [] rowData = new Object [] {testCaseNum, resultLabel, data.getTime(), + judgesOutputViewJLabel, judgesDataViewJLabel }; + + super.addRow(rowData); + } + + @Override + public void addRow(Object [] rowData) { + super.addRow(rowData); + } + +} diff --git a/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java b/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java index 036b46b60..302a66233 100644 --- a/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java +++ b/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java @@ -4,15 +4,18 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; +import java.awt.Cursor; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; +import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Timer; import java.util.TimerTask; @@ -36,11 +39,13 @@ import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumnModel; +import javax.swing.table.TableModel; import javax.swing.table.TableRowSorter; import edu.csus.ecs.pc2.core.FileUtilities; import edu.csus.ecs.pc2.core.IInternalController; import edu.csus.ecs.pc2.core.Utilities; +import edu.csus.ecs.pc2.core.list.StringToDoubleComparator; import edu.csus.ecs.pc2.core.list.StringToNumberComparator; import edu.csus.ecs.pc2.core.log.Log; import edu.csus.ecs.pc2.core.log.StaticLog; @@ -54,9 +59,11 @@ import edu.csus.ecs.pc2.core.model.JudgementRecord; import edu.csus.ecs.pc2.core.model.Language; import edu.csus.ecs.pc2.core.model.Problem; +import edu.csus.ecs.pc2.core.model.ProblemDataFiles; import edu.csus.ecs.pc2.core.model.Run; import edu.csus.ecs.pc2.core.model.Run.RunStates; import edu.csus.ecs.pc2.core.model.RunEvent; +import edu.csus.ecs.pc2.core.model.RunTestCase; import edu.csus.ecs.pc2.core.security.Permission; import edu.csus.ecs.pc2.imports.ccs.IContestLoader; import edu.csus.ecs.pc2.list.ListUtilities; @@ -64,6 +71,7 @@ import edu.csus.ecs.pc2.list.SubmissionSampleLocation; import edu.csus.ecs.pc2.list.SubmissionSolutionList; import edu.csus.ecs.pc2.ui.EditFilterPane.ListNames; +import edu.csus.ecs.pc2.ui.cellRenderer.LinkCellRenderer; import edu.csus.ecs.pc2.ui.team.QuickSubmitter; /** @@ -78,6 +86,8 @@ public class SubmitSampleRunsPane extends JPanePlugin { private static final int HORZ_PAD = 20; private static final int SUBMISSION_WAIT_TIMEOUT_MS = 10000; + private static final int ELAPSED_TIME_COLUMN = 5; + /** * ClientSettings key for CDP Path */ @@ -115,12 +125,14 @@ public class SubmitSampleRunsPane extends JPanePlugin { private String filterFrameTitle = "Judges' Submissions filter"; + private SampleResultsFrame sampleResultsFrame = null; private Log log; private List submissionFileList = null; private int currentSubmission = -1; private List submissionList = null; + private HashSet runsAdded = new HashSet(); private Timer submissionWaitTimer = null; private TimerTask submissionTimerTask = null; @@ -527,6 +539,7 @@ public void run() { private void clearSubmissionFiles() { submissionFileList = null; currentSubmission = -1; + runsAdded.clear(); } private void stopSubmissionTimer() { @@ -691,6 +704,35 @@ public void setFilterFrameTitle (String title){ } } + private ProblemDataFiles getProblemDataFiles(Run run) { + Problem problem = getContest().getProblem(run.getProblemId()); + return getContest().getProblemDataFile(problem); + } + + protected void viewOutputsAndData(SubmissionSample sub) { + + if(sub != null) { + if (getSampleResultsFrame().isVisible()) { + if (getSampleResultsFrame().getState() == Frame.ICONIFIED) { + getSampleResultsFrame().setState(javax.swing.JFrame.NORMAL); + } + } + + getSampleResultsFrame().setData(sub); + + getSampleResultsFrame().setVisible(true); + } + } + + private SampleResultsFrame getSampleResultsFrame() { + if (sampleResultsFrame == null) { + sampleResultsFrame = new SampleResultsFrame(); + sampleResultsFrame.setContestAndController(getContest(), getController()); + FrameUtilities.centerFrame(sampleResultsFrame); + } + return sampleResultsFrame; + } + /** * This method initializes scrollPane * @@ -728,7 +770,7 @@ public Component prepareRenderer(TableCellRenderer renderer, int row, int column //map the specified row index number to the corresponding model row (index numbers can change due // to sorting/scrolling; model row numbers never change). // Here are the columns: - // Object[] fullColumns = { "Run Id", "Time", "Problem", "Expected", "Status", "Source", "Judge", "Language", "ElementId" }; + // Object[] fullColumns = { "Run Id", "Time", "Problem", "Expected", "Status", "Source", "Judge", "Language", "SubmissionSample" }; int modelRow = convertRowIndexToModel(row); String submissionAcronym = submissionSolutionList.getAcronymForSubmissionDirectory((String)runTableModel.getValueAt(modelRow, 3)); @@ -764,8 +806,9 @@ public void mouseClicked(MouseEvent me) { if (me.getClickCount() == 2) { JTable target = (JTable)me.getSource(); if(target.getSelectedRow() != -1 && isAllowed(Permission.Type.JUDGE_RUN)) { -// requestSelectedRun(); - } + // Maybe we want to let them edit the run someday? + // requestSelectedRun(); + } } } }); @@ -773,6 +816,24 @@ public void mouseClicked(MouseEvent me) { return runTable; } + protected SubmissionSample findSelectedSubmissionSample() { + + SubmissionSample sub = null; + int[] selectedIndexes = runTable.getSelectedRows(); + + if (selectedIndexes.length >= 1) { + + try { + int modelIndex = runTable.convertRowIndexToModel(selectedIndexes[0]); + TableModel tm = runTable.getModel(); + sub = (SubmissionSample) tm.getValueAt(modelIndex, tm.getColumnCount()-1); + } catch (Exception e) { + // Just ignore exception - non-fatal. + } + } + return sub; + } + public void clearAllRuns() { SwingUtilities.invokeLater(new Runnable() { @Override @@ -789,7 +850,7 @@ private void resetRunsListBoxColumns() { runTable.removeAll(); - Object[] fullColumns = { "Run Id", "Time", "Problem", "Expected", "Status", "Source", "Judge", "Language", "ElementId" }; + Object[] fullColumns = { "Run Id", "Time", "Problem", "Expected", "Status", "Max Time(s)", "Source", "Judge", "Language", "SubmissionSample" }; Object[] columns; columns = fullColumns; @@ -802,7 +863,7 @@ public boolean isCellEditable(int row, int col) { runTable.setModel(runTableModel); TableColumnModel tcm = runTable.getColumnModel(); - // Remove ElementID from display - this does not REMOVE the column, just makes it so it doesn't show + // Remove SubmissionSample from display - this does not REMOVE the column, just makes it so it doesn't show tcm.removeColumn(tcm.getColumn(columns.length - 1)); // Sorters @@ -821,17 +882,26 @@ public boolean isCellEditable(int row, int col) { runTable.setRowHeight(runTable.getRowHeight() + VERT_PAD); +// DefaultTableCellRenderer rightAlign = new DefaultTableCellRenderer(); +// rightAlign.setHorizontalAlignment(JLabel.RIGHT); +// runTable.getTableHeader().getColumnModel().getColumn(ELAPSED_TIME_COLUMN).setCellRenderer(rightAlign); +// runTable.getColumnModel().getColumn(5).setCellRenderer(rightAlign); + + runTable.getColumnModel().getColumn(ELAPSED_TIME_COLUMN).setCellRenderer(new LinkCellRenderer()); + StringToNumberComparator numericStringSorter = new StringToNumberComparator(); + StringToDoubleComparator doubleStringSorter = new StringToDoubleComparator(); int idx = 0; -// Object[] fullColumns = { "Run Id", "Time", "Problem", "Expected", "Status", "Source", "Judge", "Language" }; +// Object[] fullColumns = { "Run Id", "Time", "Problem", "Expected", "Status", "Max CPU ms", "Source", "Judge", "Language" }; // These are in column order - omitted ones are straight string compare trs.setComparator(0, numericStringSorter); trs.setComparator(1, numericStringSorter); + trs.setComparator(5, doubleStringSorter); // These are in sort order sortList.add(new RowSorter.SortKey(0, SortOrder.ASCENDING)); sortList.add(new RowSorter.SortKey(1, SortOrder.ASCENDING)); @@ -841,8 +911,69 @@ public boolean isCellEditable(int row, int col) { sortList.add(new RowSorter.SortKey(5, SortOrder.ASCENDING)); sortList.add(new RowSorter.SortKey(6, SortOrder.ASCENDING)); sortList.add(new RowSorter.SortKey(7, SortOrder.ASCENDING)); + sortList.add(new RowSorter.SortKey(8, SortOrder.ASCENDING)); trs.setSortKeys(sortList); resizeColumnWidth(runTable); + + // add a listener to allow users to click an output or data file name and display it + MouseAdapter linkListener = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + JTable target = (JTable) e.getSource(); + int row = target.getSelectedRow(); + int column = target.getSelectedColumn(); + + if (Utilities.isDebugMode()) { + System.out.println("Mouse clicked in cell (" + row + "," + column + ")"); + } + + if (column != ELAPSED_TIME_COLUMN) { + //user clicked on a column that doesn't contain a link; ignore it + if (Utilities.isDebugMode()) { + System.out.println ("... ignored"); + } + return; + } + + //get the text in the JLabel at the current row/column cell + String labelString = ""; + try { + labelString = ((JLabel)target.getValueAt(row, column)).getText(); + } catch (ClassCastException e1) { + if (log != null) { + log.warning("SubmitSampleRunsPane.getResultsTable(): expected to find a JLabel in runTable; exception: " + + e1.getMessage()); + } else { + System.err.println("SubmitSampleRunsPane.getResultsTable(): expected to find a JLabel in runTable; exception: " + + e1.getMessage()); + } + return; + } + + //check whether the clicked cell has a visible string in it (only cells with legitimate links to something have non-empty strings) + if (!labelString.equals("")) { + if(Utilities.isDebugMode()) { + System.out.println("Clicked on " + labelString); + } + viewOutputsAndData(findSelectedSubmissionSample()); + } + //else cell was empty - ignore the the click + } + + @Override + public void mouseMoved(MouseEvent e) { + JTable target = (JTable) e.getSource(); + int column = target.columnAtPoint(e.getPoint()); + + if (column != ELAPSED_TIME_COLUMN) { + target.setCursor(Cursor.getDefaultCursor()); + return; + } + target.setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }; + runTable.addMouseListener(linkListener); + runTable.addMouseMotionListener(linkListener); } private void resizeColumnWidth(JTableCustomized table) { @@ -855,6 +986,33 @@ public void run() { }); } + /** + * Looks at all the TestCaseResults for a run and filters + * that list to just the most recent. + * + * @param run + * @return most recent RunTestCaseResults + */ + private RunTestCase[] getCurrentTestCaseResults(Run run) { + RunTestCase[] testCases = null; + RunTestCase[] allTestCases = run.getRunTestCases(); + // hope the lastTestCase has the highest testNumber.... + if (allTestCases != null && allTestCases.length > 0) { + testCases = new RunTestCase[allTestCases[allTestCases.length-1].getTestNumber()]; + for (int i = allTestCases.length-1; i >= 0; i--) { + RunTestCase runTestCaseResult = allTestCases[i]; + int testCaseNumIndex = runTestCaseResult.getTestNumber()-1; + if (testCases[testCaseNumIndex] == null) { + testCases[testCaseNumIndex] = runTestCaseResult; + if (testCaseNumIndex == 0) { + break; + } + } + } + } + return testCases; + } + protected Object[] buildRunRow(SubmissionSample sub, ClientId judgeId) { try { @@ -865,14 +1023,28 @@ protected Object[] buildRunRow(SubmissionSample sub, ClientId judgeId) { int idx = 0; -// Object[] fullColumns = { "Run Id", "Time", "Problem", "Expected", "Status", "Source", "Judge", "Language", ["ElementId"] }; +// Object[] fullColumns = { "Run Id", "Time", "Problem", "Expected", "Status", "Max CPU ms", "Source", "Judge", "Language", ["SubmissionSample"] }; if(run != null) { boolean autoJudgedRun = isAutoJudgedRun(run); + RunTestCase [] testCases = getCurrentTestCaseResults(run); + long maxMS = -1; + if(testCases != null) { + for(RunTestCase tc : testCases) { + if(tc.getElapsedMS() > maxMS) { + maxMS = tc.getElapsedMS(); + } + } + } s[idx++] = Integer.toString(run.getNumber()); s[idx++] = Long.toString(run.getElapsedMins()); s[idx++] = getProblemTitle(sub.getProblem()); s[idx++] = sub.getSampleType(); s[idx++] = getJudgementResultString(run); + if(maxMS == -1) { + s[idx++] = new JLabel("N/A"); + } else { + s[idx++] = new JLabel(String.format("%d.%03ds", maxMS/1000, maxMS%1000)); + } s[idx++] = sub.getSourceFile().getName(); s[idx++] = getJudgesTitle(run, judgeId, autoJudgedRun); } else { @@ -881,11 +1053,12 @@ protected Object[] buildRunRow(SubmissionSample sub, ClientId judgeId) { s[idx++] = getProblemTitle(sub.getProblem()); s[idx++] = sub.getSampleType(); s[idx++] = "N/A"; + s[idx++] = new JLabel("N/A"); s[idx++] = sub.getSourceFile().getName(); s[idx++] = "N/A"; } s[idx++] = getLanguageTitle(sub.getLanguage()); - s[idx++] = sub.getElementId(); + s[idx++] = sub; return s; } catch (Exception exception) { @@ -1009,7 +1182,7 @@ protected String getJudgementResultString(Run run) { /** * Find row that contains the supplied key (in last column) - * @param value - unique key - really, the ElementId of run + * @param value - unique key - really, the SubmissionSample * @return index of row, or -1 if not found */ private int getRowByKey(Object value) { @@ -1027,26 +1200,6 @@ private int getRowByKey(Object value) { return(-1); } - /** - * Remove run from grid by removing the data row from the TableModel - * - * @param run - */ - private void removeRunRow(final Run run) { - - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - - int rowNumber = getRowByKey(run.getElementId()); - if (rowNumber != -1) { - runTableModel.removeRow(rowNumber); - updateRowCount(); - } - } - }); - } - /** * This updates the rowCountlabel & toolTipText. It should be called only while on the swing thread. */ @@ -1077,7 +1230,7 @@ public void run() { } Object[] objects = buildRunRow(sub, whoJudgedId); - int rowNumber = getRowByKey(sub.getElementId()); + int rowNumber = getRowByKey(sub); if (rowNumber == -1) { // No row with this key - add new one runTableModel.addRow(objects); @@ -1148,44 +1301,40 @@ public class RunListenerImplementation implements IRunListener { public void runAdded(RunEvent event) { SubmissionSample sub = null; Run run = event.getRun(); + Integer runNum = new Integer(run.getNumber()); + + if(runsAdded.contains(runNum)) { + log.log(Level.WARNING, "Duplicate runAdded event for Run id " + run.getNumber() + " ignored."); + if(Utilities.isDebugMode()) { + System.out.println("Duplicate runAdded (" + run.getNumber() + ") ignored - currentSubmission #" + currentSubmission); + } + return; + } + runsAdded.add(runNum); + if(Utilities.isDebugMode()) { + System.out.println("Got runAdded for run ID " + run.getNumber() + " - added to runsAdded hashset"); + } + ClientId me = getContest().getClientId(); // We are only interested in runs we submitted if(run.getSubmitter().equals(me)) { - - // JB - think this test for duplicate is inadequate. - // We should remember the run id in a hashmap or something and ignore it if was seen - SubmissionSample dupRun = getSubmission(event); - if(dupRun == null) { - try { - // This is the last run - it has to be the one that was just added by us - sub = submissionList.get(currentSubmission); - } catch (Exception e) { - log.log(Level.WARNING, "No submission sample for run id " + run.getNumber(), e); - if(Utilities.isDebugMode()) { - System.out.println("No submission runAdded (" + run.getNumber() + ") - currentSubmission #" + currentSubmission); - } - } - } else { - log.log(Level.WARNING, "Duplicate runAdded event for Run id " + run.getNumber() + " ignored."); + // This is the last run - it has to be the one that was just added by us + sub = submissionList.get(currentSubmission); + if(sub != null) { + stopSubmissionTimer(); + sub.setRun(run); if(Utilities.isDebugMode()) { - System.out.println("Duplicate runAdded (" + run.getNumber() + ") ignored - currentSubmission #" + currentSubmission); + System.out.println("Received runAdded currentSubmission #" + currentSubmission + " for problem " + sub.toString()); + } + updateRunRow(sub, event.getWhoModifiedRun(), true); + // setup for next submission; if last one clean things up. + currentSubmission++; + if(currentSubmission >= submissionFileList.size()) { + clearSubmissionFiles(); + } else { + submitNextSubmission(); } - } - } - if(sub != null) { - stopSubmissionTimer(); - sub.setRun(run); - if(Utilities.isDebugMode()) { - System.out.println("Received runAdded currentSubmission #" + currentSubmission + " for problem " + sub.toString()); - } - updateRunRow(sub, event.getWhoModifiedRun(), true); - // setup for next submission; if last one clean things up. - currentSubmission++; - if(currentSubmission >= submissionFileList.size()) { - clearSubmissionFiles(); - } else { - submitNextSubmission(); } } } From 8e1a763df441cb8bd714e86a0f6f04a714b4d8ce Mon Sep 17 00:00:00 2001 From: John Buck Date: Tue, 18 Jun 2024 21:46:55 -0400 Subject: [PATCH 04/10] i_232 Allow viewing of judges data and answer files Add code to handle the links for judges input and judges answer files. --- .../csus/ecs/pc2/ui/SampleResultsPane.java | 140 +++++++++++++++++- .../ecs/pc2/ui/SampleResultsTableModel.java | 21 ++- 2 files changed, 155 insertions(+), 6 deletions(-) diff --git a/src/edu/csus/ecs/pc2/ui/SampleResultsPane.java b/src/edu/csus/ecs/pc2/ui/SampleResultsPane.java index ae235c638..67d21534d 100644 --- a/src/edu/csus/ecs/pc2/ui/SampleResultsPane.java +++ b/src/edu/csus/ecs/pc2/ui/SampleResultsPane.java @@ -4,10 +4,14 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; +import java.awt.Cursor; import java.awt.Dimension; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; import java.util.Arrays; import java.util.Vector; @@ -29,6 +33,7 @@ import javax.swing.table.TableModel; import edu.csus.ecs.pc2.core.IInternalController; +import edu.csus.ecs.pc2.core.Utilities; import edu.csus.ecs.pc2.core.log.Log; import edu.csus.ecs.pc2.core.model.IInternalContest; import edu.csus.ecs.pc2.core.model.Language; @@ -57,12 +62,12 @@ public class SampleResultsPane extends JPanePlugin implements TableModelListener * list of columns */ protected enum COLUMN { - DATASET_NUM, RESULT, TIME, JUDGE_OUTPUT, JUDGE_DATA + DATASET_NUM, RESULT, TIME, JUDGE_DATA, JUDGE_OUTPUT }; // define the column headers for the table of results private String[] columnNames = { "Data Set #", "Result", "Time (s)", - "Judge's Output", "Judge's Data" }; + "Judge's Data", "Judge's Output" }; private JPanel centerPanel = null; @@ -100,6 +105,8 @@ protected enum COLUMN { private JLabel lblNumFailedTestCases; private Component horizontalGlue_9; + private MultipleFileViewer currentViewer = null; + private boolean debug = false; /** @@ -421,6 +428,11 @@ public void run() { resultsTable = getResultsTable(testCases); getResultsScrollPane().setViewportView(resultsTable); + + // On switch of data, clear tabs that are there from previous + if(currentViewer != null) { + currentViewer.dispose(); + } } }); @@ -599,6 +611,80 @@ private JTable getResultsTable(RunTestCase [] testCases) { // render Time column right-justified localResultsTable.getColumn(columnNames[COLUMN.TIME.ordinal()]).setCellRenderer(new RightJustifiedCellRenderer()); + // add a listener to allow users to click an output or data file name and display it + MouseAdapter linkListener = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + JTable target = (JTable) e.getSource(); + int row = target.getSelectedRow(); + int column = target.getSelectedColumn(); + + if (Utilities.isDebugMode()) { + System.out.println("Mouse clicked in cell (" + row + "," + column + ")"); + } + + if (column != COLUMN.JUDGE_OUTPUT.ordinal() && column != COLUMN.JUDGE_DATA.ordinal()) { + //user clicked on a column that doesn't contain a link; ignore it + if (Utilities.isDebugMode()) { + System.out.println ("... ignored"); + } + return; + } + + //get the text in the JLabel at the current row/column cell + String labelString = ""; + String tooltipString = ""; + try { + JLabel targetLabel = (JLabel)target.getValueAt(row, column); + // Text shown in the cell + labelString = targetLabel.getText(); + // full filename is the tooltip, we use that to display the file. + tooltipString = targetLabel.getToolTipText(); + } catch (ClassCastException e1) { + if (log != null) { + log.warning("SampleResultsPane.getResultsTable(): expected to find a JLabel in localResultsTable; exception: " + + e1.getMessage()); + } else { + System.err.println("SampleResultsPane.getResultsTable(): expected to find a JLabel in localResultsTable; exception: " + + e1.getMessage()); + } + return; + } + + //check whether the clicked cell has a visible string in it (only cells with legitimate links to something have non-empty strings) + if (!labelString.equals("")) { + if(Utilities.isDebugMode()) { + System.out.println("Clicked on " + labelString + "(" + tooltipString + ")"); + } + String title, tabLabel; + if(column == COLUMN.JUDGE_OUTPUT.ordinal()) { + title = "Judge's Answer File"; + tabLabel= "Ans"; + } else { + title = "Judge's Input File"; + tabLabel= "In"; + } + tabLabel = tabLabel + " File #" + target.getValueAt(row, COLUMN.DATASET_NUM.ordinal()); + showFile(getCurrentViewer(), tooltipString, title, tabLabel, true); + } + //else cell was empty - ignore the the click + } + + @Override + public void mouseMoved(MouseEvent e) { + JTable target = (JTable) e.getSource(); + int column = target.columnAtPoint(e.getPoint()); + + if (column != COLUMN.JUDGE_OUTPUT.ordinal() && column != COLUMN.JUDGE_DATA.ordinal()) { + target.setCursor(Cursor.getDefaultCursor()); + return; + } + target.setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + }; + localResultsTable.addMouseListener(linkListener); + localResultsTable.addMouseMotionListener(linkListener); + return localResultsTable; } @@ -813,4 +899,54 @@ private Component getHorizontalGlue_9() { } return horizontalGlue_9; } + + /** + * @return the currentViewer + */ + public MultipleFileViewer getCurrentViewer() { + if (currentViewer == null) { + currentViewer = new MultipleFileViewer(getController().getLog()); + } + return currentViewer; + } + + /** + * Uses the specified fileViewer to display the specified file, setting the title and message + * on the viewer to the specified values and invoking "setVisible()" on the viewer if desired. + * @param fileViewer - the viewer to be used + * @param file - the file to be displayed in the viewer + * @param title - the title to be set on the viewer title bar + * @param tabLabel - the label to be put on the viewer pane tab + * @param visible - whether or not to invoke setVisible(true) on the viewer + */ + private void showFile(MultipleFileViewer fileViewer, String file, String title, String tabLabel, boolean visible) { + + if (fileViewer == null || file == null) { + log = getController().getLog(); + log.log(Log.WARNING, "SampleResultsPane.showFile(): fileViewer or file is null"); + JOptionPane.showMessageDialog(getParentFrame(), + "System Error: null fileViewer or file; contact Contest Administrator (check logs)", + "System Error", JOptionPane.ERROR_MESSAGE); + return ; + } + File myFile = new File(file); + if (! myFile.isFile()) { + JOptionPane.showMessageDialog(getParentFrame(), + "Error: could not find file: " + file, + "File Missing", JOptionPane.ERROR_MESSAGE); + log = getController().getLog(); + log.warning("SampleResultsPane.showFile(): could not find file "+file); + return; + } + fileViewer.setTitle(title); + fileViewer.addFilePane(tabLabel, file); + // addFilePane always adds it first + fileViewer.setSelectedIndex(0); + fileViewer.enableCompareButton(false); + fileViewer.setInformationLabelText("File: " + myFile.getName()); + if (visible) { + fileViewer.setVisible(true); + } + } + } // @jve:decl-index=0:visual-constraint="10,10" diff --git a/src/edu/csus/ecs/pc2/ui/SampleResultsTableModel.java b/src/edu/csus/ecs/pc2/ui/SampleResultsTableModel.java index 567be8cb0..e8a17deef 100644 --- a/src/edu/csus/ecs/pc2/ui/SampleResultsTableModel.java +++ b/src/edu/csus/ecs/pc2/ui/SampleResultsTableModel.java @@ -6,6 +6,7 @@ import javax.swing.JLabel; import javax.swing.table.DefaultTableModel; +import edu.csus.ecs.pc2.core.Utilities; import edu.csus.ecs.pc2.core.model.ElementId; import edu.csus.ecs.pc2.core.model.IInternalContest; import edu.csus.ecs.pc2.core.model.Problem; @@ -99,17 +100,29 @@ public SampleResultsTableModel(IInternalContest contest, RunTestCase[] testCaseR if (probID!=null) { Problem prob = contest.getProblem(probID); if (prob!=null) { + String extPath = contest.getContestInformation().getJudgeCDPBasePath(); + String judgesFileName; //update team-compare and judges-answer-file links if there is a judge's answer file String answerFileName = prob.getAnswerFileName(row+1); if (answerFileName!=null && answerFileName.length()>0) { //there is a judge's answer file for this problem for this test case - judgesOutputViewLabel.setText("View"); + judgesOutputViewLabel.setText(answerFileName); + judgesFileName = Utilities.locateJudgesDataFile(prob, answerFileName, extPath); + if(judgesFileName == null) { + judgesFileName = answerFileName; + } + judgesOutputViewLabel.setToolTipText(judgesFileName); } //update judge's data file link if the problem has a judge's data file String dataFileName = prob.getDataFileName(row+1); if (dataFileName!=null && dataFileName.length()>0) { //there is a judge's data file for this problem for this test case - judgesDataViewLabel.setText("View"); + judgesDataViewLabel.setText(dataFileName); + judgesFileName = Utilities.locateJudgesDataFile(prob, dataFileName, extPath); + if(judgesFileName == null) { + judgesFileName = dataFileName; + } + judgesDataViewLabel.setToolTipText(judgesFileName); } } } @@ -118,7 +131,7 @@ public SampleResultsTableModel(IInternalContest contest, RunTestCase[] testCaseR // build the row object and add it to the model Object[] rowData = new Object[] { testCaseNum, resultLabel, time, - judgesOutputViewLabel, judgesDataViewLabel}; + judgesDataViewLabel, judgesOutputViewLabel}; super.addRow(rowData); } @@ -183,7 +196,7 @@ public void addRow(String testCaseNum, SampleResultsRowData data ) { //build the row object and add it to the model Object [] rowData = new Object [] {testCaseNum, resultLabel, data.getTime(), - judgesOutputViewJLabel, judgesDataViewJLabel }; + judgesDataViewJLabel, judgesOutputViewJLabel }; super.addRow(rowData); } From c1f930e50545f679bce8053758f3bf29a9156d82 Mon Sep 17 00:00:00 2001 From: John Buck Date: Thu, 20 Jun 2024 10:50:06 -0400 Subject: [PATCH 05/10] i_232 Finishing touches Add ability to have all judges' samples "not stop on failure" by default, no matter how a problem has defined the setting. This can be controlled by a checkbox on the SampleResultsPane. Add the one-shot overrideStopOnFailure flag for a Run and handle it in Executable Add submitJudgeRun methods to support the overrideStopOnFailure flag to InternalController Add new method to PacketFactory to pass the overrideStopOnFailure flag to the properties for a run submission. Fix PacketHandler to deal with the overrideStopOnFailure property and set it in the Run so Executable will see it. Bug fix for filter by judging tyeps CI: Add ability to show why a run failed in the TestResutlsPane instead of just showing "Fail" --- .../ecs/pc2/core/IInternalController.java | 263 +++--- .../csus/ecs/pc2/core/InternalController.java | 771 +++++++++++------- src/edu/csus/ecs/pc2/core/PacketHandler.java | 11 + .../csus/ecs/pc2/core/execute/Executable.java | 7 + src/edu/csus/ecs/pc2/core/model/Run.java | 20 + .../ecs/pc2/core/packet/PacketFactory.java | 369 +++++---- src/edu/csus/ecs/pc2/list/ListUtilities.java | 12 +- .../ecs/pc2/ui/SampleResultsTableModel.java | 8 + .../csus/ecs/pc2/ui/SubmitSampleRunsPane.java | 10 +- .../TestCaseResultCellRenderer.java | 53 +- .../csus/ecs/pc2/ui/team/QuickSubmitter.java | 18 +- 11 files changed, 934 insertions(+), 608 deletions(-) diff --git a/src/edu/csus/ecs/pc2/core/IInternalController.java b/src/edu/csus/ecs/pc2/core/IInternalController.java index d77e89c93..2fad83a31 100644 --- a/src/edu/csus/ecs/pc2/core/IInternalController.java +++ b/src/edu/csus/ecs/pc2/core/IInternalController.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2020 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.core; import java.io.IOException; @@ -39,23 +39,23 @@ /** * Represents functions provided by modules comprising the contest engine. - * + * * Provides the methods to start PC2 clients and servers. *

    - * An example of starting a server: + * An example of starting a server: *

    * * public static void main(String[] args) {
    - *

    + *
    * IInternalContest contest = new InternalContest();
    * IInternalController controller = new InternalController (contest);
    * String serverArgs = "--server"; controller.start(serverArgs);
    - *
    - * } + *
    + * } * *

    - * - * To start a client: + * + * To start a client: *

    * * public static void main(String[] args) {
    @@ -64,10 +64,10 @@ * IInternalController controller = new InternalController (contest);
    * controller.start(args);
    * - * } + * } *
    *

    - * + * * @see edu.csus.ecs.pc2.Starter * @author pc2@ecs.csus.edu * @version $Id$ @@ -78,50 +78,99 @@ public interface IInternalController { /** * Submit a Judge Run to the server. - * + * * @param problem the {@link Problem} for which the Submission applies * @param language the {@link Language} used in the Submission * @param mainFileName the name of the file containing the main program source code * @param otherFiles an array of {@link SerializedFile}s containing additional source files being submitted with the Run - * + * * @throws Exception if an error occurs while attempting to send the Run to the Server */ void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles) throws Exception; /** * Submit a Judge Run to the server. - * + * * @param problem the {@link Problem} for which the Submission applies * @param language the {@link Language} used in the Submission * @param mainFileName the name of the file containing the main program source code * @param otherFiles an array of {@link SerializedFile}s containing additional source files being submitted with the Run - * @param overrideSubmissionTimeMS a value which, if non-zero, is to be used as the submission time of the Judge Run; + * @param overrideStopOnFailure if true, then do not stop judging on first failure. if false, use the setting for the problem + * + * @throws Exception if an error occurs while attempting to send the Run to the Server + */ + void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, boolean overrideStopOnFailure) throws Exception; + + /** + * Submit a Judge Run to the server. + * + * @param problem the {@link Problem} for which the Submission applies + * @param language the {@link Language} used in the Submission + * @param mainFileName the name of the file containing the main program source code + * @param otherFiles an array of {@link SerializedFile}s containing additional source files being submitted with the Run + * @param overrideSubmissionTimeMS a value which, if non-zero, is to be used as the submission time of the Judge Run; * only has effect when Contest Information "CCS Test Mode" is true * @param overrideRunId a value which, if non-zero, is to be used as the RunId for the submission instead of any * internally-assigned RunId; only has effect when Contest Information "CCS Test Mode" is true - * + * * @throws Exception if an error occurs while attempting to send the Run to the Server */ - void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, + void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, long overrideSubmissionTimeMS, long overrideRunId) throws Exception; /** * Submit a Judge Run to the server. - * + * + * @param problem the {@link Problem} for which the Submission applies + * @param language the {@link Language} used in the Submission + * @param mainFileName the name of the file containing the main program source code + * @param otherFiles an array of {@link SerializedFile}s containing additional source files being submitted with the Run + * @param overrideSubmissionTimeMS a value which, if non-zero, is to be used as the submission time of the Judge Run; + * only has effect when Contest Information "CCS Test Mode" is true + * @param overrideRunId a value which, if non-zero, is to be used as the RunId for the submission instead of any + * internally-assigned RunId; only has effect when Contest Information "CCS Test Mode" is true + * @param overrideStopOnFailure if true, then do not stop judging on first failure. if false, use the setting for the problem + * + * @throws Exception if an error occurs while attempting to send the Run to the Server + */ + void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, + long overrideSubmissionTimeMS, long overrideRunId, boolean overrideStopOnFailure) throws Exception; + + /** + * Submit a Judge Run to the server. + * * @param problem the {@link Problem} for which the Submission applies * @param language the {@link Language} used in the Submission * @param mainFile a {@link SerializedFile} containing the main program source code * @param otherFiles an array of {@link SerializedFile}s containing additional source files being submitted with the Run - * @param overrideSubmissionTimeMS a value which, if non-zero, is to be used as the submission time of the Judge Run; + * @param overrideSubmissionTimeMS a value which, if non-zero, is to be used as the submission time of the Judge Run; * only has effect when Contest Information "CCS Test Mode" is true * @param overrideRunId a value which, if non-zero, is to be used as the RunId for the submission instead of any * internally-assigned RunId; only has effect when Contest Information "CCS Test Mode" is true - * + * * @throws Exception if an error occurs while attempting to send the Run to the Server */ - void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, SerializedFile[] otherFiles, + void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, SerializedFile[] otherFiles, long overrideSubmissionTimeMS, long overrideRunId) throws Exception; + /** + * Submit a Judge Run to the server. + * + * @param problem the {@link Problem} for which the Submission applies + * @param language the {@link Language} used in the Submission + * @param mainFile a {@link SerializedFile} containing the main program source code + * @param otherFiles an array of {@link SerializedFile}s containing additional source files being submitted with the Run + * @param overrideSubmissionTimeMS a value which, if non-zero, is to be used as the submission time of the Judge Run; + * only has effect when Contest Information "CCS Test Mode" is true + * @param overrideRunId a value which, if non-zero, is to be used as the RunId for the submission instead of any + * internally-assigned RunId; only has effect when Contest Information "CCS Test Mode" is true + * @param overrideStopOnFailure if true, then do not stop judging on first failure. if false, use the setting for the problem + * + * @throws Exception if an error occurs while attempting to send the Run to the Server + */ + void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, SerializedFile[] otherFiles, + long overrideSubmissionTimeMS, long overrideRunId, boolean overrideStopOnFailure) throws Exception; + void setSiteNumber(int i); @@ -129,21 +178,21 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Send to client (or server), if necessary forward to another server. - * + * * @param packet */ void sendToClient(Packet packet); /** * Send to all logged in servers. - * + * * @param packet */ void sendToServers(Packet packet); /** * Send to a remote server. - * + * * @param siteNumber * @param packet */ @@ -151,49 +200,49 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Send to all judges on local site. - * + * * @param packet */ void sendToJudges(Packet packet); /** * Send to all administrators on local site. - * + * * @param packet */ void sendToAdministrators(Packet packet); /** * Send to all scoreboard on local site. - * + * * @param packet */ void sendToScoreboards(Packet packet); /** * Send to all teams on local site. - * + * * @param packet */ void sendToTeams(Packet packet); /** * Send to all spectator/API clients - * + * * @param packet */ void sendToSpectators(Packet packet); /** * Start InternalController with command line arguments. - * + * * @param stringArray */ void start(String[] stringArray); /** * Login to server, start MainUI. - * + * * @param loginName * @param password */ @@ -201,7 +250,7 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Login to server, wait for login - * + * * @param loginName * @param password * @return @@ -211,23 +260,23 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Logoff a client. - * + * * Logs this client off, or sends request to log client off. - * + * * @param clientId */ void logoffUser(ClientId clientId); /** * Start the UI for the input client. - * + * * @param clientId */ void startMainUI(ClientId clientId); /** * Request a run from the server. - * + * * @param run * - the run to retrieve * @param readOnly @@ -239,14 +288,14 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Request to checkout a judged run, to rejudge the run. - * + * * @param theRun */ void checkOutRejudgeRun(Run theRun); /** * Submit judgement from run to judge. - * + * * @param run * @param judgementRecord */ @@ -254,7 +303,7 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Cancel selected run. - * + * * @param run */ void cancelRun(Run run); @@ -262,21 +311,21 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, void addNewSite(Site site); void addNewProblem(Problem problem, ProblemDataFiles problemDataFiles); - + void addNewProblem(Problem [] problem, ProblemDataFiles [] problemDataFiles); void addProblem(Problem problem); /** * Add a new Judgement. - * + * * @param judgement */ void addNewJudgement(Judgement judgement); /** * Replace judgement list with new judgement list. - * + * * @param judgementList */ void setJudgementList(Judgement[] judgementList); @@ -286,13 +335,13 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, void updateRun(Run run, JudgementRecord judgementRecord, RunResultFiles runResultFiles); void sendServerLoginRequest(int inSiteNumber) throws Exception; - + /** - * Is this controller using GUI. + * Is this controller using GUI. * @return true if using GUI, false if using text only */ boolean isUsingGUI(); - + /** * Is this controller suppressing display of Connections grids. * @return true if GUIs using this controller should suppress display of Connections grids. @@ -314,10 +363,10 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, void updateProblem(Problem problem); void updateProblem(Problem problem, ProblemDataFiles problemDataFiles); - + /** * Send packet to local server to switch profile. - * + * * @param currentProfile profile to switch from * @param switchToProfile profile to switch to */ @@ -325,7 +374,7 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Clone profile (and potentially switch to the new profile). - * + * * @param profile current profile * @param settings set of changes to clone * @param switchNow true means switch to new profile now @@ -336,14 +385,14 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Get contest log. - * + * * @return */ Log getLog(); /** * Send message to server that needs attention/resolution. - * + * * @param event * optional event * @param message @@ -355,7 +404,7 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Generate new accounts on a server. - * + * * @param clientTypeName * @param siteNumber * site number to generate accounts. @@ -367,7 +416,7 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Generate new accounts for current site. - * + * * @param clientTypeName * @param count * @param startNumber @@ -377,7 +426,7 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Submit a clarification. - * + * * @param problem * @param question */ @@ -385,7 +434,7 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Request clarification to answer. - * + * * @param clarification * @param readOnly */ @@ -393,23 +442,23 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Cancel requested clarification. - * + * * @param clarification */ void cancelClarification(Clarification clarification); /** * Answer a clarification. - * + * * @param clarification */ void submitClarificationAnswer(Clarification clarification); /** * Force connection off. - * + * * Remove local connection, or send to server to remove connection. - * + * * @param connectionHandlerID */ void forceConnectionDrop(ConnectionHandlerID connectionHandlerID); @@ -440,13 +489,13 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, void addNewLanguage(Language language); void addNewLanguages(Language[] languages); - + void updateLanguage(Language language); void updateLanguages(Language[] languages); void addNewGroup(Group group); - + void addNewGroups(Group[] groups); void updateGroup(Group group); @@ -467,14 +516,14 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Load contest settings from disk and initialize InternalContest. - * @param contest - * + * @param contest + * * @throws FileSecurityException * @throws ClassNotFoundException * @throws IOException */ void initializeServer(IInternalContest contest) throws IOException, ClassNotFoundException, FileSecurityException; - + void initializeStorage (IStorage storage); void addNewClientSettings(ClientSettings newClientSettings); @@ -483,7 +532,7 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Get Security Level. - * + * * @return current security level */ int getSecurityLevel(); @@ -492,38 +541,38 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Send packet to server. - * + * * Also can be used to send a packet from this * server to this server as a consistent interface * to the server (esp from classes like ServerView) - * + * * @param packet */ void sendToLocalServer(Packet packet); /** * Get name of host contacted. - * + * * On server, gets name of host where listener listens. - * + * * @return name of host server */ String getHostContacted(); /** * Get port number of host contacted. - * + * * On server, gets port where listening. - * + * * @return */ int getPortContacted(); /** * Gets a run from the server. - * + * * Does not checkout run, simply requests the run info. Security note: only a non-team client can request runs. - * + * * @param run * @throws FileSecurityException * @throws ClassNotFoundException @@ -533,21 +582,21 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Send a compiling message to the Server. - * + * * @param run */ void sendCompilingMessage(Run run); /** * Send a executing message to the Server. - * + * * @param run */ void sendExecutingMessage(Run run); /** * Send a validating message to the Server. - * + * * @param run */ void sendValidatingMessage(Run run); @@ -558,21 +607,21 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Reset contest. - * + * * @param clientResettingContest */ void resetContest(ClientId clientResettingContest, boolean eraseProblems, boolean eraseLanguages); /** * Update existing judgement. - * + * * @param newJudgement */ void updateJudgement(Judgement newJudgement); /** * Update current Profile information. - * + * * @param profile */ void updateProfile(Profile profile); @@ -581,21 +630,21 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Register a plugin. - * + * * @param plugin */ void register(UIPlugin plugin); - + /** * Get list of plugins. - * + * * @return */ UIPlugin[] getPluginList(); /** * Update/replace contest and controller for all registered UI Plugins. - * + * * @param inContest * @param inController */ @@ -604,16 +653,16 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, void addPacketListener(IPacketListener packetListener); void removePacketListener(IPacketListener packetListener); - + void incomingPacket (Packet packet); - + void outgoingPacket (Packet packet); - + /** * Start Log Window. - * + * * Only starts if {@link #isUsingGUI()} returns true; - * + * * @param contest */ ILogWindow startLogWindow(IInternalContest contest); @@ -623,7 +672,7 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, * @param showWindow set LogWindow visible. */ void showLogWindow(boolean showWindow); - + boolean isLogWindowVisible(); /** @@ -635,10 +684,10 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Send Sync Submissions packet. - * + * * Send a packet to tell all servers to sync up their * submission and other local data with all servers. - * + * * @param profile */ void syncProfileSubmissions(Profile profile); @@ -650,30 +699,30 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Send shutdown server packet. - * + * * @param siteNumber site number to shut down. */ void sendShutdownSite(int siteNumber); /** * Shutdown this server. - * + * * @param requestor */ void shutdownServer(ClientId requestor); /** * Shutdown all remote servers. - * + * * Sends packet to all servers to shutdown. - * + * * @param requestor */ void shutdownRemoteServers(ClientId requestor); /** * Shutdown remove server (Server). - * + * * @param requestor * @param siteNumber */ @@ -681,17 +730,17 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Update Finalize data - * @param data + * @param data */ void updateFinalizeData(FinalizeData data); - + /** * Using GUI?. - * + * * @param usingGUI true means show GUI message, false means do not show GUI messages. */ void setUsingGUI(boolean usingGUI); - + void updateCategories(Category[] categories); void updateCategory(Category newCategory); @@ -699,7 +748,7 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, void addNewCategory(Category newCategory); void startPlayback(PlaybackInfo playbackInfo); - + /** * Send submitted run to Run Submission Interface. * @param run @@ -714,10 +763,10 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Send to all logged in Judges, Admins, Boards and optionally to other sites. - * - * This sends all sorts of packets to all logged in clients (except teams). + * + * This sends all sorts of packets to all logged in clients (except teams). * Typically sendToServers is set if this is the originating site, if not done then a nasty circular path will occur. - * + * * @param packet * @param sendToServers if true then send to other server. */ @@ -725,16 +774,16 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Override the connection manager. - * + * * @see ITransportManager * @param connectionManager */ void setConnectionManager(ITransportManager connectionManager); - + /** * Creates an {@link AutoStarter} if none exists, and then instructs the AutoStarter to update its Scheduled Start Task to correspond to the Scheduled Start Time information in the * {@link ContestInformation} object in the received {@link IInternalContest}. - * + * * @param aContest * - the Contest (Model) containing the Scheduled Start Time information * @param aController @@ -750,7 +799,7 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Submit a run to the server for a different client. - * + * * @param submitter - override submitter, if used the logged in client must have Permission.Type.SHADOW_PROXY_TEAM selected. * @param problem * @param language @@ -763,7 +812,7 @@ void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, /** * Submit a run to the server for a different client with entry_point - * + * * @param submitter - override submitter, if used the logged in client must have Permission.Type.SHADOW_PROXY_TEAM selected. * @param problem * @param language diff --git a/src/edu/csus/ecs/pc2/core/InternalController.java b/src/edu/csus/ecs/pc2/core/InternalController.java index 41ff0d853..b872912cf 100644 --- a/src/edu/csus/ecs/pc2/core/InternalController.java +++ b/src/edu/csus/ecs/pc2/core/InternalController.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2022 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.core; import java.io.File; @@ -95,7 +95,7 @@ /** * Implementation of InternalContest InternalController. - * + * * Run Flow, submit run. *

      *
    1. Team: {@link #submitRun(Problem, Language, String)} @@ -128,12 +128,12 @@ * {@link edu.csus.ecs.pc2.core.model.RunEvent.Action#RUN_AVAILABLE} *
    *

    - * + * * @author pc2@ecs.csus.edu */ public class InternalController implements IInternalController, ITwoToOne, IBtoA { - + private boolean haltOnFatalError = true; /** @@ -161,27 +161,27 @@ public class InternalController implements IInternalController, ITwoToOne, IBtoA private Log log; private Ini ini = new Ini(); - + private boolean suppressConnectionsPaneDisplay = false; private boolean suppressLoginsPaneDisplay = false; /** * The port that the server will listen on. - * + * * This is the port where all clients will contact this server/site. */ private static int port; /** * The host/IP for a client or server to contact. - * + * * Both client and server who are connecting a server use this host as the host to contact. */ private String remoteHostName = "127.0.0.1"; /** * The port for a client or server to login to/contact. - * + * * Both client and server who are connecting a server use this port as the portt to contact. */ private int remoteHostPort; @@ -249,7 +249,7 @@ public class InternalController implements IInternalController, ITwoToOne, IBtoA private String loginClassName = LOGIN_UI_GUI_CLASSNAME; private String startupDialogClassName = STARTUP_DIALOG_GUI_CLASS; - + private String countdownClassName = COUNTDOWN_UI_CLASSNAME; private IStartupContestDialog startDialog; @@ -261,7 +261,7 @@ public class InternalController implements IInternalController, ITwoToOne, IBtoA /** * Flag indicating whether Roman Numeral shutdown is done. - * + * * If set to false, then will trigger/send the event */ private boolean clientAutoShutdown = true; @@ -276,20 +276,20 @@ public class InternalController implements IInternalController, ITwoToOne, IBtoA private ILogWindow logWindow = null; private RunSubmitterInterfaceManager runSubmitterInterfaceManager = new RunSubmitterInterfaceManager(); - + /** * The object used to control contest auto-starting. */ private AutoStarter autoStarter; - + private AutoStopContestClockThread autoStopContestClockThread = null; - + /** * Packets which should be sent to multiple instances of logins (for example, a "RUN_SUBMSSION_CONFIRMATION" * packet should be sent to every instance of a given team client login when multiple team logins are allowed). * Listing an element of {@link PacketType.Type} in this EnumSet causes packets of that type to be duplicated * and sent to every login instance for the destination client specified in the packet. - * + * * @author John Clevenger, PC2 Development Team (pc2@ecs.csus.edu) * */ @@ -297,8 +297,8 @@ public class InternalController implements IInternalController, ITwoToOne, IBtoA PacketType.Type.RUN_SUBMISSION_CONFIRM, PacketType.Type.RUN_JUDGEMENT, // PacketType.Type.RUN_JUDGEMENT_UPDATE, //this seems to only be sent to judges/admins/boards to update run status, but not teams - PacketType.Type.CLARIFICATION_SUBMISSION_CONFIRM, - PacketType.Type.CLARIFICATION_UPDATE, + PacketType.Type.CLARIFICATION_SUBMISSION_CONFIRM, + PacketType.Type.CLARIFICATION_UPDATE, PacketType.Type.CLARIFICATION_ANSWER, PacketType.Type.CLARIFICATION_ANSWER_UPDATE ); @@ -308,6 +308,7 @@ public InternalController(IInternalContest contest) { setContest(contest); } + @Override public void sendToLocalServer(Packet packet) { if (isThisServer(packet.getSourceId()) && isServer()) { @@ -357,10 +358,11 @@ private void sendToClient(ConnectionHandlerID connectionHandlerID, Packet packet } /** - * + * * @param inSiteNumber site number for client to send to * @param packet info to send */ + @Override public void sendToRemoteServer(int inSiteNumber, Packet packet) { if (packet.getSourceId() != null && (packet.getOriginalSourceId().getSiteNumber() == inSiteNumber)) { @@ -369,9 +371,9 @@ public void sendToRemoteServer(int inSiteNumber, Packet packet) { } Site remoteSite = lookupRemoteServer(inSiteNumber); int siteNumber = remoteSite.getSiteNumber(); - + ClientId clientId = new ClientId(siteNumber, Type.SERVER, 0); - + ConnectionHandlerID connectionHandlerID = getConnectionHandleID(clientId); info("sendToRemoteServer " + clientId + " at "+siteNumber+" " + packet + " " + connectionHandlerID); @@ -397,7 +399,7 @@ public void sendToRemoteServer(int inSiteNumber, Packet packet) { } protected ConnectionHandlerID getConnectionHandleID(ClientId clientId) { - + ClientId[] ids = contest.getLocalLoggedInClients(clientId.getClientType()); for (ClientId id : ids) { if (id.equals(clientId)){ @@ -407,12 +409,13 @@ protected ConnectionHandlerID getConnectionHandleID(ClientId clientId) { return null; } + @Override public void sendToClient(Packet packet) { info("sendToClient b4 to " + packet.getDestinationId() + " " + packet); ClientId toClientId = packet.getDestinationId(); - //this method should never be called with a packet containing a destination ClientId containing a null ConnectionHandlerID; + //this method should never be called with a packet containing a destination ClientId containing a null ConnectionHandlerID; // however, the addition of "multiple login" support may have left some place where this is inadvertently true. //The following is an effort to catch/identify such situations. if (toClientId.getConnectionHandlerID()==null) { @@ -423,14 +426,14 @@ public void sendToClient(Packet packet) { if (isThisSite(toClientId.getSiteNumber())) { if (contest.isLocalLoggedIn(toClientId)) { - + ConnectionHandlerID connectionHandlerID = toClientId.getConnectionHandlerID(); info("sendToClient " + packet.getDestinationId() + " @ " + connectionHandlerID); sendToClient(connectionHandlerID, packet); - + //certain packets should also be sent to any other logged in clients (e.g. logins for the same team) sendToDuplicateClients(packet); - + } else { try { packetArchiver.writeNextPacket(packet); @@ -461,37 +464,37 @@ public void sendToClient(Packet packet) { info("sendToClient af to " + packet.getDestinationId() + " " + packet); } - + /** * Examines the specified packet to determine if there duplicate client logins to which the packet should be sent * (for example, in the case where multiple team clients for the same team have been allowed to login); sends the * specified packet to any duplicate login clients. - * + * * @param packet the packet to be sent to any duplicate login clients. */ private void sendToDuplicateClients(Packet packet) { //determine what client the packet was initially sent to (it is assumed that the caller took care of the initial send) ClientId toClientId = packet.getDestinationId(); - + //see if the packet is one of the types that should be duplicated (sent to all logins for the client) if (DuplicatePacketTypes.contains(packet.getType()) ) { - + //see if the destination for the packet is a team if (toClientId.getClientType()==ClientType.Type.TEAM) { - + //get a list of all logged-in team clients ClientId[] clientList = contest.getAllLoggedInClients(ClientType.Type.TEAM); - + //check every logged-in team client for (ClientId clientId : clientList) { - + //see if the current logged-in team client is the same team as the original intended destination if (clientId.equals(toClientId)) { - + //same team; make sure it's a DIFFERENT connection (we assume the caller already sent the packet to the original dest) if (!clientId.getConnectionHandlerID().equals(toClientId.getConnectionHandlerID())) { - + //it's a different connection for the same team; send a duplicate of the packet ConnectionHandlerID connectionHandlerID = clientId.getConnectionHandlerID(); info("sendToClient " + packet.getDestinationId() + " @ " + connectionHandlerID); @@ -527,15 +530,26 @@ protected void sendToServersAndAdmins(Packet packet) { /** * {@inheritDoc} - * Calling this method is equivalent to calling + * Calling this method is equivalent to calling * {@link #submitJudgeRun(Problem, Language, String, SerializedFile[], long, long)} * with zeroes as the last two parameters. */ - @Override + @Override public void submitJudgeRun(Problem problem, Language language, String filename, SerializedFile[] otherFiles) throws Exception { submitJudgeRun(problem, language, filename, otherFiles, 0, 0); } - + + /** + * {@inheritDoc} + * Calling this method is equivalent to calling + * {@link #submitJudgeRun(Problem, Language, String, SerializedFile[], long, long)} + * with zeroes as the last two parameters. + */ + @Override + public void submitJudgeRun(Problem problem, Language language, String filename, SerializedFile[] otherFiles, boolean overrideStopOnFailure) throws Exception { + submitJudgeRun(problem, language, filename, otherFiles, 0, 0, overrideStopOnFailure); + } + /** * {@inheritDoc} * Calling this method is equivalent to calling @@ -543,29 +557,58 @@ public void submitJudgeRun(Problem problem, Language language, String filename, * with a {@link SerializedFile} containing the main source code file contents. */ @Override - public void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, + public void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, + long overrideSubmissionTimeMS, long overrideRunId, boolean overrideStopOnFailure) throws Exception { + + SerializedFile serializedMainFile = new SerializedFile(mainFileName); + + submitJudgeRun(problem, language, serializedMainFile, otherFiles, overrideSubmissionTimeMS, overrideRunId, overrideStopOnFailure); + } + + /** + * {@inheritDoc} + * Calling this method is equivalent to calling + * {@link #submitJudgeRun(Problem, Language, SerializedFile, SerializedFile[], long, long, false)} + * with a {@link SerializedFile} containing the main source code file contents. + */ + @Override + public void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, long overrideSubmissionTimeMS, long overrideRunId) throws Exception { SerializedFile serializedMainFile = new SerializedFile(mainFileName); - submitJudgeRun(problem, language, serializedMainFile, otherFiles, overrideSubmissionTimeMS, overrideRunId); + submitJudgeRun(problem, language, serializedMainFile, otherFiles, overrideSubmissionTimeMS, overrideRunId, false); } /** * {@inheritDoc} + * Calling this method is equivalent to calling + * {@link #submitJudgeRun(Problem, Language, SerializedFile, SerializedFile[], long, long, false)} + * with a {@link SerializedFile} containing the main source code file contents. */ @Override - public void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, SerializedFile[] otherFiles, + public void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, SerializedFile[] otherFiles, long overrideSubmissionTimeMS, long overrideRunId) throws Exception { + submitJudgeRun(problem, language, mainFile, otherFiles, overrideSubmissionTimeMS, overrideRunId, false); + } + + /** + * {@inheritDoc} + */ + @Override + public void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, SerializedFile[] otherFiles, + long overrideSubmissionTimeMS, long overrideRunId, boolean overrideStopOnFailure) throws Exception { + ClientId serverClientId = new ClientId(contest.getSiteNumber(), Type.SERVER, 0); Run run = new Run(contest.getClientId(), language, problem); RunFiles runFiles = new RunFiles(run, mainFile, otherFiles); - Packet packet = PacketFactory.createSubmittedRun(contest.getClientId(), serverClientId, run, runFiles, overrideSubmissionTimeMS, overrideRunId); + Packet packet = PacketFactory.createSubmittedRun(contest.getClientId(), serverClientId, run, runFiles, overrideSubmissionTimeMS, overrideRunId, overrideStopOnFailure); sendToLocalServer(packet); } + @Override public void requestChangePassword(String oldPassword, String newPassword) { ClientId serverClientId = new ClientId(contest.getSiteNumber(), Type.SERVER, 0); @@ -576,7 +619,7 @@ public void requestChangePassword(String oldPassword, String newPassword) { /** * Return int for input string - * + * * @param s * @return zero if error, otherwise returns value. */ @@ -590,7 +633,7 @@ private static int getIntegerValue(String s) { /** * returns true if .ini file exists and key is present in file. - * + * * @see IniFile#getValue(String) * @param key * @return true if key found and ini file exists. @@ -605,7 +648,7 @@ private static boolean containsINIKey(String key) { /** * Get value from .ini file if it exists. - * + * * @param key * @return */ @@ -713,15 +756,16 @@ protected String stripChar(String s, char ch) { /** * Login to contest server. - * + * * @param id * the login name. * @param password * the password for the id. - * @throws SecurityException + * @throws SecurityException * if a login is attempted when the contest is not running or if the login is from a server * and this is a Client (servers can only log in to other servers) */ + @Override public void login(String id, String password) { if (!isStarted) { @@ -765,13 +809,13 @@ public void login(String id, String password) { } info("Contacted using connection id " + remoteServerConnectionHandlerID); - + boolean loggingInSiteRequestsToBeProxy = getBooleanValue(getINIValue(AppConstants.PROXY_ME_SERVER_KEY), false); - + if (parseArguments.isOptPresent(AppConstants.PROXYME_OPTION_STRING)){ loggingInSiteRequestsToBeProxy = true; } - + sendLoginRequestFromServerToServer(connectionManager, remoteServerConnectionHandlerID, clientId, password, loggingInSiteRequestsToBeProxy, 0); } else { @@ -802,12 +846,12 @@ public void login(String id, String password) { sendLoginRequest(connectionManager, clientId, id, password); } } - + /** * For input string return boolean value. - * + * * Does a trim and case in-sensitive match on the list: yes, no, true, false - * + * * @param string true/false string/value * @param defaultBoolean if matches none in list returns this values */ @@ -833,9 +877,9 @@ public boolean getBooleanValue(String string, boolean defaultBoolean) { /** * This is a very temporary kludge class. - * + * * This is used with clientLogin, as a - * + * * @author pc2@ecs.csus.edu * @version $Id$ */ @@ -850,15 +894,17 @@ protected class TemporaryClientUI implements UIPlugin, ILoginListener { private SecurityException securityException = null; /** - * + * */ private static final long serialVersionUID = 8735788359720905862L; + @Override public void setContestAndController(IInternalContest inContest, IInternalController inController) { contest = inContest; controller = inController; } + @Override public String getPluginTitle() { return "TemporaryClientUI"; } @@ -883,25 +929,30 @@ public void setController(IInternalController controller) { this.controller = controller; } + @Override public void loginAdded(LoginEvent event) { // no action } + @Override public void loginRemoved(LoginEvent event) { // no action } + @Override public void loginDenied(LoginEvent event) { securityException = new SecurityException("Login denied " + event.getMessage()); } + @Override public void loginRefreshAll(LoginEvent event) { // no action } } + @Override public IInternalContest clientLogin(IInternalContest internalContest, String loginName, String password) throws Exception { if (!isStarted) { @@ -964,12 +1015,14 @@ public IInternalContest clientLogin(IInternalContest internalContest, String log } } + @Override public void initializeStorage(IStorage storage) { contest.setStorage(storage); packetArchiver = new PacketArchiver(storage, getBaseProfileDirectoryName("packets")); } + @Override public void initializeServer(IInternalContest inContest) throws IOException, ClassNotFoundException, FileSecurityException { if (inContest.getSites().length == 0) { @@ -1038,7 +1091,7 @@ public void initializeServer(IInternalContest inContest) throws IOException, Cla inContest.initializeStartupData(inContest.getSiteNumber()); inContest.initializeSubmissions(inContest.getSiteNumber()); - + if (inContest.getGeneralProblem() == null) { inContest.setGeneralProblem(new Problem("General")); } @@ -1048,24 +1101,24 @@ public void initializeServer(IInternalContest inContest) throws IOException, Cla } info("initialized controller Site " + inContest.getSiteNumber()); - + handleCDPLoad(true); - + if (contest.getJudgements().length == 0) { - // judgements not loaded from yaml, cdp config - load from ./reject.ini + // judgements not loaded from yaml, cdp config - load from ./reject.ini String result = JudgementLoader.loadJudgements(inContest, false, "."); getLog().info(result); } - + if (contest.getJudgements().length == 0) { - // judgements not loaded from cdp, yaml or ./reject.ini + // judgements not loaded from cdp, yaml or ./reject.ini JudgementLoader.loadDefaultJudgements(contest); getLog().info("Loaded default judgements"); } - + dumpAutoStartInformation(contest.getContestInformation()); - + try { manager.mergeProfiles(inContest); } catch (Exception e) { @@ -1106,9 +1159,9 @@ public void initializeServer(IInternalContest inContest) throws IOException, Cla } catch (Exception e) { getLog().log(Log.WARNING, "Exception creating evals.log ", e); } - + updateAutoStartInformation(inContest, this); - + updateAutoStopClockThread(); } @@ -1139,14 +1192,14 @@ private void insureProfileDirectory(Profile profile) { /** * Loads reject.ini file contents into Judgements. - * + * * If finds reject.ini file, reads file. Adds Yes judgement, then prepends "No - " onto each entry from the reject.ini file and returns true. - * + * * Reads judge acronyms if present, if file contains a AC judgement then will use that * text for the Yes judgement. - * + * * Returns false if cannot read reject.ini file or reject.ini file is empty (perhaps only containing comments). - * + * * @return true if loaded, false if could not read file. */ protected boolean loadedJudgementsFromIni(String filename) { @@ -1160,17 +1213,17 @@ protected boolean loadedJudgementsFromIni(String filename) { protected void loadDefaultJudgements() { String[] judgementNames = { // - "Yes", // - "No - Compilation Error", // - "No - Run-time Error", // - "No - Time Limit Exceeded", // - "No - Wrong Answer", // - "No - Excessive Output", // - "No - Output Format Error", // + "Yes", // + "No - Compilation Error", // + "No - Run-time Error", // + "No - Time Limit Exceeded", // + "No - Wrong Answer", // + "No - Excessive Output", // + "No - Output Format Error", // "No - Other - Contact Staff" // }; String [] judgementAcronyms = { - Judgement.ACRONYM_ACCEPTED, // + Judgement.ACRONYM_ACCEPTED, // Judgement.ACRONYM_COMPILATION_ERROR, // Judgement.ACRONYM_RUN_TIME_ERROR, // Judgement.ACRONYM_TIME_LIMIT_EXCEEDED, // @@ -1179,7 +1232,7 @@ protected void loadDefaultJudgements() { Judgement.ACRONYM_OUTPUT_FORMAT_ERROR, // Judgement.ACRONYM_OTHER_CONTACT_STAFF, // }; - + int i = 0; for (String judgementName : judgementNames) { Judgement judgement = new Judgement(judgementName, judgementAcronyms[i]); @@ -1243,11 +1296,11 @@ private Site createFirstSite(int siteNumber, String hostName, int portNumber) { /** * Reads .ini file and sets server and port. - * + * * Sets the server and port for client. - * + * * @param portString - * + * */ private void setClientServerAndPort(String portString) { @@ -1344,9 +1397,9 @@ private void setServerPort(String portString) { /** * Send login request from server to another server. - * + * * Send login request directly to connectionHandlerId. - * + * * @param manager * transmission manager * @param targetConnectionHandlerID @@ -1359,8 +1412,8 @@ private void setServerPort(String portString) { * @param targetSiteNumber the target/destination site number for this login request */ private void sendLoginRequestFromServerToServer(ITransportManager manager, ConnectionHandlerID targetConnectionHandlerID, ClientId clientId, String password, boolean proxyMe, - int targetSiteNumber) { - + int targetSiteNumber) { + try { info("sendLoginRequestFromServerToServer ConId start - sending from " + clientId); ClientId serverClientId = new ClientId(targetSiteNumber, Type.SERVER, 0); @@ -1371,8 +1424,8 @@ private void sendLoginRequestFromServerToServer(ITransportManager manager, Conne } catch (TransportException e) { info("Exception sendLoginRequestFromServerToServer ", e); } - - + + // info("sendLoginRequestFromServerToServer ConId start - sending from " + clientId + " proxyMe = " + proxyMe); // ClientId serverClientId = new ClientId(0, Type.SERVER, 0); // String joeLoginName = password; @@ -1386,7 +1439,7 @@ private void sendLoginRequestFromServerToServer(ITransportManager manager, Conne /** * Send login request to server as a login. - * + * * @param manager * @param clientId * @param password @@ -1401,9 +1454,10 @@ private void sendLoginRequest(ITransportManager manager, ClientId clientId, Stri /** * Server receives Packet from client or server. - * + * * @see edu.csus.ecs.pc2.core.transport.ITwoToOne#receiveObject(java.io.Serializable, edu.csus.ecs.pc2.core.transport.ConnectionHandlerID) */ + @Override public void receiveObject(Serializable object, ConnectionHandlerID connectionHandlerID) { // SOMEDAY SECURITY code check the input connection to insure they are valid connection @@ -1415,7 +1469,7 @@ public void receiveObject(Serializable object, ConnectionHandlerID connectionHan Packet packet = (Packet) object; ClientId clientId = packet.getSourceId(); - + clientId.setConnectionHandlerID(connectionHandlerID); info("receiveObject " + packet); @@ -1439,20 +1493,20 @@ public void receiveObject(Serializable object, ConnectionHandlerID connectionHan } } else if (packet.getType().equals(PacketType.Type.LOGIN_REQUEST)) { - + if (packetHandler.forwardedToProxy((packet))) { - + // Handled proxy packets (send/receive), no additional action necesary in this method. return; } - + String password = PacketFactory.getStringValue(packet, PacketFactory.PASSWORD); boolean requestProxy = false; Boolean requestedProxy = PacketFactory.getBooleanValue(packet, PacketFactory.REQUEST_LOGIN_AS_PROXY); if (requestedProxy != null) { requestProxy = requestedProxy.booleanValue(); } - + try { /** @@ -1462,15 +1516,15 @@ public void receiveObject(Serializable object, ConnectionHandlerID connectionHan packetArchiver.writeNextPacket(packet); if (clientId.getSiteNumber() == ClientId.UNSET) { - + info("LOGIN_REQUEST packet contains clientId object with site number of " + ClientId.UNSET + "; replacing with my site number (" + contest.getSiteNumber() + ")"); - + ConnectionHandlerID connHID = clientId.getConnectionHandlerID(); clientId = new ClientId(contest.getSiteNumber(), clientId.getClientType(), clientId.getClientNumber()); clientId.setConnectionHandlerID(connHID); } attemptToLogin(clientId, password, connectionHandlerID); - + if (requestProxy){ if (isServer(packet.getSourceId())){ /** @@ -1479,7 +1533,7 @@ public void receiveObject(Serializable object, ConnectionHandlerID connectionHan sendSiteUpdateSetProxy (packet.getSourceId(), contest.getSiteNumber()); } } - + sendLoginSuccess(clientId, connectionHandlerID); // Send login notification to users. @@ -1539,16 +1593,16 @@ public void receiveObject(Serializable object, ConnectionHandlerID connectionHan // securityCheck(packet, connectionHandlerID); processPacket(packet, connectionHandlerID); } else { - + if (clientId.getClientType().equals(Type.SERVER)) { // Packet from a server. if (packet.getType() == PacketType.Type.LOGIN_FAILED) { - + handleServerLoginFailure(packet); - + } else if (packet.getType().equals(PacketType.Type.LOGIN_SUCCESS)) { - + /** * The current server has successfully logged into a remote server. */ @@ -1560,14 +1614,14 @@ public void receiveObject(Serializable object, ConnectionHandlerID connectionHan // Add the other (server we logged into) into our local logged in list. loginServer(clientId, connectionHandlerID); - + /** * Since this module is not logged in, this packet should only be a LOGIN_SUCCESS from a server we initially logged into, - * aka the remoteServer. + * aka the remoteServer. */ - + if (connectionHandlerID.equals(remoteServerConnectionHandlerID)){ - + /** * Only accept/change config data on this site if the login success is from the server that this site connected to initially. */ @@ -1575,42 +1629,42 @@ public void receiveObject(Serializable object, ConnectionHandlerID connectionHan // Add data from packet into contest and sync all runs processPacket(packet, connectionHandlerID); - + } else { - + /** * This should happen when a server logs into another server that is not its remoeteServer (initial server logged into). - * + * * This is where the remote site's data is synced on this server. */ - + info("Updating this server's settings from remote server specific settings from " + clientId + " @ " + connectionHandlerID); - + packetHandler.loadSettingsFromRemoteServer(new ContestLoader(), packet, connectionHandlerID); - + info("Sending this server's settings to remote server " + packet.getSourceId() + " @ " + connectionHandlerID); // Send settings packet to the server we logged into sendToClient(packetHandler.createContestSettingsPacket(packet.getSourceId())); - + info("Sending a request for all run files to remote server " + packet.getSourceId() + " @ " + connectionHandlerID); packetHandler.sendRequestForRunfFiles (packet, packet.getSourceId().getSiteNumber()); - + } } else if (contest.isLocalLoggedIn(clientId) && packet.getType().equals(PacketType.Type.LOGIN)) { /** - * A user has logged into another remote server + * A user has logged into another remote server */ // on site 2 login to site 1, site 2 reports LOGIN on login to site1 processPacket(packet, connectionHandlerID); } else if (packet.getType().equals(PacketType.Type.LOGIN) && contest.getSite(contest.getSiteNumber()).hasProxy() && packet.getDestinationId().getSiteNumber() == 0) { /** - * This is probably coming from our proxy + * This is probably coming from our proxy */ processPacket(packet, connectionHandlerID); } else if (contest.isLocalLoggedIn(packet.getDestinationId()) && contest.getSite(contest.getSiteNumber()).getMyProxy() == packet.getDestinationId().getSiteNumber()) { /** - * This is coming from our proxy + * This is coming from our proxy */ processPacket(packet, connectionHandlerID); } else if (contest.isRemoteLoggedIn(packet.getSourceId()) && packet.getSourceId().getClientType() == ClientType.Type.SERVER) { @@ -1648,18 +1702,18 @@ public void receiveObject(Serializable object, ConnectionHandlerID connectionHan /** * Assign proxy, send updated Site to all connected sites. - * + * * @param siteToBeProxied client/site to be proxied * @param proxySiteNumber proxy site for siteToBeProxied */ private void sendSiteUpdateSetProxy(ClientId siteToBeProxied, int proxySiteNumber) { - - // assign proxy + + // assign proxy Site site = contest.getSite(siteToBeProxied.getSiteNumber()); site.setMyProxy(proxySiteNumber); - + updateSite(site); - + } private String[] removeFirstElement(String[] stringArray) { @@ -1670,7 +1724,7 @@ private String[] removeFirstElement(String[] stringArray) { /** * Handle client attempt to auto register. - * + * * @param packet * @param connectionHandlerID */ @@ -1711,6 +1765,7 @@ private void handleAutoRegistration(Packet packet, ConnectionHandlerID connectio } } + @Override public void sendToJudgesAndOthers(Packet packet, boolean sendToServers) { if (isServer()) { @@ -1741,7 +1796,7 @@ private boolean isEnableAutoRegistration() { /** * Creates and saves a ClientSettings. - * + * * @param clientId * @return */ @@ -1769,7 +1824,7 @@ private ClientSettings getClientSettings(ClientId clientId) { /** * This logs server into local logins and out of remote logins, if needed. - * + * * @param clientId * @param connectionHandlerID */ @@ -1828,7 +1883,7 @@ private void securityCheck(Packet packet, ConnectionHandlerID connectionHandlerI /** * Handle incoming invalid login and message. - * + * * @param packet */ private void handleServerLoginFailure(Packet packet) { @@ -1861,7 +1916,7 @@ private void handleServerLoginFailure(Packet packet) { /** * Looks up site number based on password. - * + * * @param password * @return site number or throws SecurityException if nothing matches. */ @@ -1913,7 +1968,7 @@ public static boolean matchOverride(String password) { } return false; } - + /** * Returns true if the password matches the hash for the override password. */ @@ -1955,9 +2010,9 @@ protected boolean validAccountAndMatchOverride(ClientId clientId, String passwor /** * Attempt to login, if login success add to login list. - * + * * If login fails will throw SecurityException. - * + * * @param newClientId the new client attempting to log in. * @param password the new client's password. * @param connectionHandlerID the ConnectionHandlerID associated with the newly connecting client. @@ -1965,13 +2020,13 @@ protected boolean validAccountAndMatchOverride(ClientId clientId, String passwor private void attemptToLogin(ClientId newClientId, String password, ConnectionHandlerID connectionHandlerID) { info("ClientID=" + newClientId); - + if (newClientId.getClientType().equals(Type.SERVER)) { // Server login request int newSiteNumber = getServerSiteNumber(newClientId.getSiteNumber(), password); - - info("Logging in new server; newSiteNumber = " + newSiteNumber); + + info("Logging in new server; newSiteNumber = " + newSiteNumber); info("My site number = " + contest.getSiteNumber()); if (newSiteNumber == contest.getSiteNumber()) { @@ -1992,24 +2047,24 @@ private void attemptToLogin(ClientId newClientId, String password, ConnectionHan } else { // Client login request - + //check if the account and password are valid if (validAccountAndMatchOverride(newClientId, password) || contest.isValidLoginAndPassword(newClientId, password)) { //valid acct and pw; see if the account is already logged in if (contest.isLocalLoggedIn(newClientId)) { - + //already logged in; see if the current login(s) should be forced off if (newClientId.getClientType()!=ClientType.Type.TEAM || (!contest.getContestInformation().isAllowMultipleLoginsPerTeam())) { - + //not a team, or is a team but multiple team logins not allowed; force off all clients matching the new client forceOffAllClientsMatching(newClientId); } } - + contest.addLocalLogin(newClientId, connectionHandlerID); info("LOGIN logged in " + newClientId + " at " + connectionHandlerID); - + } else { //invalid account or bad password info("attemptToLogin FAILED logged on: " + newClientId); @@ -2019,46 +2074,46 @@ private void attemptToLogin(ClientId newClientId, String password, ConnectionHan } } } - + /** - * Searches the list of currently logged-in clients and forces a logoff for any client matching + * Searches the list of currently logged-in clients and forces a logoff for any client matching * the specified ClientId (that is, any client of the same type, number, and site). - * + * * @param clientId the ClientId for which matching client logins are to be forced logged-off. */ private void forceOffAllClientsMatching(ClientId clientId) { // get a list of all logged in clients of the same type as the specified client ClientId[] loggedInClientsOfSameType = contest.getLocalLoggedInClients(clientId.getClientType()); - + //check every logged in client in the list for (ClientId nextLoggedInClientId : loggedInClientsOfSameType) { - + //see if the next logged in client "matches" the specified incoming client. //(note that ClientId.equals() compares type, number, and site (only)) if (nextLoggedInClientId.equals(clientId)) { - + //yes, matches; force the existing client to logoff forceLogoff(nextLoggedInClientId); } } } - + /** * This method forces a logoff of the specified Client. - * + * * @param clientId the client that is to be forced logged off. */ private void forceLogoff(ClientId clientId) { - + // Already logged in, log them off log.info("login - " + clientId + " already logged in at connection " + clientId.getConnectionHandlerID() + "; forcing logoff " ); - + // old code: only removes login from local contest but doesn't notify Admins or Servers // // this updates the model contest-wide // contest.removeLogin(clientId); - + //new code: calls contest.removeLogin(clientId) as above, but also calls forceConnectionDrop() and sends LOGOFF packets to Admins and Servers logoffUser(clientId); @@ -2070,7 +2125,7 @@ private void forceLogoff(ClientId clientId) { log.log(Log.WARNING, "Exception on canceling runs/clars for " + clientId, e); } } - + // old code; not needed now because the call to logoffUser() (above) calls forceConnectionDrop() // //this is what actually causes the connection to be dropped/disconnected // forceConnectionDrop(connHandlerID); @@ -2085,7 +2140,7 @@ private void forceLogoff(ClientId clientId) { /** * Can this user checkout clars and runs. - * + * * @param theClient * @return */ @@ -2095,11 +2150,11 @@ protected boolean canCheckoutRunsAndClars(ClientId theClient) { /** * Process all packets. - * + * * Assumes that the packet is from an authenticated user. - * + * * Process packets when user is logged in. - * + * * @param packet * @param connectionHandlerID */ @@ -2176,7 +2231,7 @@ private void processPacket(Packet packet, ConnectionHandlerID connectionHandlerI /** * Send login failure packet back to non-logged in user, via ConnectionHandlerID. - * + * * @param destinationId * @param connectionHandlerID * @param message @@ -2188,7 +2243,7 @@ private void sendLoginFailure(ClientId destinationId, ConnectionHandlerID connec /** * Send Login Success packet to client. - * + * * @param clientId * @param connectionHandlerID */ @@ -2197,6 +2252,7 @@ private void sendLoginSuccess(ClientId clientId, ConnectionHandlerID connectionH sendToClient(packetHandler.createLoginSuccessPacket(clientId, contest.getContestPassword())); } + @Override public void connectionEstablished(ConnectionHandlerID connectionHandlerID) { info("connectionEstablished: " + connectionHandlerID); contest.connectionEstablished(connectionHandlerID); @@ -2208,9 +2264,10 @@ public void connectionEstablished(ConnectionHandlerID connectionHandlerID) { /** * Connection to client lost. - * + * * @throws IOException */ + @Override public void connectionDropped(ConnectionHandlerID connectionHandlerID) { // getLog().log(Log.INFO, "connection Dropped for " + connectionHandlerID, new Exception("connection Dropped for " + connectionHandlerID)); @@ -2258,7 +2315,7 @@ protected void cancelAllClarsByThisJudge(ClientId judgeId) throws ContestSecurit /** * Cancel all checked out runs and clarifications by this client. - * + * * @param judgeId * @throws ContestSecurityException * @throws FileSecurityException @@ -2296,6 +2353,7 @@ protected void cancelAllRunsByThisJudge(ClientId judgeId) { /** * @throws IllegalArgumentException if the specified ClientId contains a null ConnectionHandlerID. */ + @Override public void logoffUser(ClientId clientId) { if (isServer() && contest.isLocalLoggedIn(clientId)) { @@ -2307,7 +2365,7 @@ public void logoffUser(ClientId clientId) { ConnectionHandlerID connectionHandlerID = clientId.getConnectionHandlerID(); - //this method should never be called with a clientId having a null ConnectionHandlerID; however, the addition of + //this method should never be called with a clientId having a null ConnectionHandlerID; however, the addition of // "multiple login" support may have left some place where this is inadvertently true. //The following is an effort to catch/identify such situations. if (connectionHandlerID==null) { @@ -2316,7 +2374,7 @@ public void logoffUser(ClientId clientId) { logException("InternalController.logoffUser() called null ConnectionHandlerID in ClientId " + clientId, e); throw e; } - + contest.removeLogin(clientId); @@ -2335,6 +2393,7 @@ public void logoffUser(ClientId clientId) { } + @Override public void connectionError(Serializable object, ConnectionHandlerID connectionHandlerID, String causeDescription) { // SOMEDAY code create a packet and send it to servers and admins @@ -2346,9 +2405,10 @@ public void connectionError(Serializable object, ConnectionHandlerID connectionH /** * Client receive object. - * + * * @see edu.csus.ecs.pc2.core.transport.IBtoA#receiveObject(java.io.Serializable) */ + @Override public void receiveObject(Serializable object) { info(" receiveObject(S) start got " + object); @@ -2363,14 +2423,14 @@ public void receiveObject(Serializable object) { // SOMEDAY code put the server's connection handler id as 4th parameter packetHandler.handlePacket(packet, null); - + } else { info("receiveObject(S) Unsupported class received: " + object.getClass().getName()); } } catch (Exception e) { - + error(e.toString(),e); - + if (loginUI != null) { loginUI.regularCursor(); } @@ -2381,6 +2441,7 @@ public void receiveObject(Serializable object) { /** * This client lost connection. */ + @Override public void connectionDropped() { // Connection dropped, countdown and halt client @@ -2401,19 +2462,19 @@ public void connectionDropped() { contest.connectionDropped(null); } } - + public void setCountdownClassName(String countdownClassName) { this.countdownClassName = countdownClassName; } - + public String getCountdownClassName() { return countdownClassName; } - + public void setLoginClassName(String loginClassName) { this.loginClassName = loginClassName; } - + public String getLoginClassName() { return loginClassName; } @@ -2424,7 +2485,7 @@ public void setStartupDialogClassName(String startupDialogClassName) { public String getStartupDialogClassName() { return startupDialogClassName; - } + } private void shutdown() { @@ -2442,7 +2503,7 @@ private void shutdown() { */ countDownMessage = new TextCountDownMessage(); } - + if (contest.getClientId() != null) { info("connectionDropped: shutting down " + contest.getClientId()); countDownMessage.setTitle("Shutting down PC^2 " + contest.getClientId().getClientType() + " " + contest.getTitle()); @@ -2452,13 +2513,13 @@ private void shutdown() { } countDownMessage.setExitOnClose(true); countDownMessage.start("Shutting down PC^2 in ", 10); - + /** - * This is needed to allow the countdown timer threads to - * actually run, otherwise the JVM ends before the timer starts. + * This is needed to allow the countdown timer threads to + * actually run, otherwise the JVM ends before the timer starts. */ sleep (12); - + } /** @@ -2466,22 +2527,22 @@ private void shutdown() { * @param secs */ private void sleep(int secs) { - + try { Thread.sleep(secs * 1000); } catch (InterruptedException e) { e.printStackTrace(); } - + } - + public void info(String message) { if (! isUsingGUI()){ System.out.println(message); } log.log(Log.INFO, message); } - + public void error(String message, Exception ex){ if (! isUsingGUI()){ System.err.println(message+" exception "+ex.getMessage()); @@ -2490,7 +2551,7 @@ public void error(String message, Exception ex){ } public void info(String message, Exception exception) { - + if (! isUsingGUI()){ System.out.println(message); } @@ -2501,10 +2562,12 @@ public void info(String message, Exception exception) { log.log(Log.INFO, message, exception); } + @Override public void setSiteNumber(int number) { contest.setSiteNumber(number); } + @Override public void setContestTime(ContestTime contestTime) { if (contest.getContestTime() != null) { contest.updateContestTime(contestTime); @@ -2513,6 +2576,7 @@ public void setContestTime(ContestTime contestTime) { } } + @Override public void sendToServers(Packet packet) { // do remotes first, for proxies this mean they are shutdown before the server @@ -2550,25 +2614,25 @@ public void sendToServers(Packet packet) { /** * Send packet to all clients logged into this site that are a particular clienttype. - * + * * @param packet * @param type client type */ private void sendPacketToClients(Packet packet, ClientType.Type type) { ClientId[] clientIds = contest.getLocalLoggedInClients(type); - + List badClients = new ArrayList(); - + for (ClientId clientId : clientIds) { - + if (isThisSite(clientId.getSiteNumber())) { - + ConnectionHandlerID connectionHandlerID = null; try { connectionHandlerID = clientId.getConnectionHandlerID(); - - //there should never be localLoggedInClients with null ConnectionHandlerIDs; however, the addition of + + //there should never be localLoggedInClients with null ConnectionHandlerIDs; however, the addition of // "multiple login" support may have left some place where this is inadvertently true. //The following is an effort to catch/identify such situations. if (connectionHandlerID==null) { @@ -2576,13 +2640,13 @@ private void sendPacketToClients(Packet packet, ClientType.Type type) { badClients.add(clientId); } else { //good clientId; send the packet to the client - sendToClient(connectionHandlerID, packet); + sendToClient(connectionHandlerID, packet); } } catch (Exception e) { getLog().log(Level.WARNING, "Exception attempting to send packet to client " + clientId + "at connectionHandlerId " + connectionHandlerID + ": " + packet + ": "+ e.getMessage(), e); } - + //check if we got any bad clientIds if (badClients.size()>0) { //yes, build a comma-separated list of bad clientIds @@ -2599,7 +2663,7 @@ private void sendPacketToClients(Packet packet, ClientType.Type type) { e.printStackTrace(); throw e; } - + } } } @@ -2610,29 +2674,34 @@ private boolean isThisSite(int siteNumber) { /** * Send to judges and spectators clients. - * + * */ + @Override public void sendToJudges(Packet packet) { sendPacketToClients(packet, ClientType.Type.JUDGE); sendPacketToClients(packet, ClientType.Type.SPECTATOR); } + @Override public void sendToSpectators(Packet packet) { sendPacketToClients(packet, ClientType.Type.SPECTATOR); } + @Override public void sendToAdministrators(Packet packet) { sendPacketToClients(packet, ClientType.Type.ADMINISTRATOR); } + @Override public void sendToScoreboards(Packet packet) { sendPacketToClients(packet, ClientType.Type.SCOREBOARD); } - + public void sendToFeeders(Packet packet) { sendPacketToClients(packet, ClientType.Type.FEEDER); } + @Override public void sendToTeams(Packet packet) { Properties properties = (Properties) packet.getContent(); @@ -2681,10 +2750,11 @@ private int getPortForSite(int inSiteNumber) { /** * Client has successfully logged in, show them UI. - * + * * @param clientId * new client id */ + @Override public void startMainUI(ClientId clientId) { try { @@ -2739,7 +2809,7 @@ public void startMainUI(ClientId clientId) { info("Loaded UI class " + uiClassName); } } - + uiPlugin.setContestAndController(contest, this); if (loginUI != null) { @@ -2770,95 +2840,95 @@ public void startMainUI(ClientId clientId) { * @param allowedToLoadConfig if true will overwrite config with CDP, else does nothing. */ protected void handleCDPLoad(boolean allowedToLoadConfig) { - + /** * Name of CDP dir or file to be loaded. */ String entryLocation = contest.getCommandLineOptionValue(AppConstants.LOAD_OPTION_STRING); - + if (contest.isCommandLineOptionPresent(AppConstants.LOAD_OPTION_STRING)){ - + if (allowedToLoadConfig){ - + IContestLoader loader = new ContestSnakeYAMLLoader(); info("Loading CDP from " + entryLocation); - + try { - + // Load Configuration from CDP - + loader.initializeContest(contest, new File(entryLocation)); - + info("Loaded CDP/config values from " + entryLocation); - + File cdpConfigDir = loader.findCDPConfigDirectory(new File(entryLocation)); - + if (contest.getJudgements().length == 0) { // judgements not loaded from yaml nor config/reject.ini // load from "." JudgementLoader.loadJudgements(contest, false, "."); } - - - + + + if (saveCofigurationToDisk) { // save newly merged profiles contest.storeConfiguration(getLog()); } - + // Load Submissions from CDP - + String submissionsDir = entryLocation + File.separator + IContestLoader.SUBMISSIONS_DIRNAME; - - String eventFeedDirectory = entryLocation + File.separator + IContestLoader.EVENT_FEED_DIRNAME; + + String eventFeedDirectory = entryLocation + File.separator + IContestLoader.EVENT_FEED_DIRNAME; String eventFeedfilename = eventFeedDirectory + File.separator + IContestLoader.EVENT_FEED_XML_FILENAME; - - + + if (new File(submissionsDir).isDirectory()){ - + if (new File(eventFeedfilename).isFile()){ - + info("Loading event feed runs... "); info("Event feed file is "+eventFeedfilename); - + LoadRuns loadRuns = new LoadRuns(); - + List eventFeedRuns = loadRuns.loadRunsFromEventFeed(eventFeedfilename); - + info("Found "+eventFeedRuns.size()+" runs."); - + info("Validating event feed runs"); - + loadRuns.validateEventFeedRuns(contest, eventFeedRuns); - + info("Validated "+eventFeedRuns.size()+" event feed runs."); - + info("Loading "+eventFeedRuns.size()+" event feed runs."); - + boolean addRuneJudgementsFromEventFeed = contest.isCommandLineOptionPresent(AppConstants.LOAD_EF_JUDGEMENTS_OPTION_STRING); - + loadRuns.updateContestFromEFRuns(contest, eventFeedRuns, cdpConfigDir.getParent(), addRuneJudgementsFromEventFeed); - + info("Loaded "+eventFeedRuns.size()+" event feed runs."); if (addRuneJudgementsFromEventFeed){ info("Loaded judgments for "+eventFeedRuns.size()+" event feed runs."); } else { info("No judgements were added for "+eventFeedRuns.size()+" event feed runs, all are 'new' runs."); } - + eventFeedRuns = null; loadRuns = null; - + } else { info("No submissions loaded, no event feed at "+eventFeedfilename); } - + } else { info("No submissions loaded, no submissions at "+submissionsDir); } - - - + + + } catch (Exception e) { String szMsg = e.getMessage(); if(szMsg == null) { @@ -2869,17 +2939,17 @@ protected void handleCDPLoad(boolean allowedToLoadConfig) { loader = null; } } else { - + info("** Not loading (" + AppConstants.LOAD_OPTION_STRING + ") CDP from " + entryLocation+" contest config ALREADY exists. **"); - System.err.println ("Warning: contest configuration already exists; ignoring " + AppConstants.LOAD_OPTION_STRING + " option"); - + System.err.println ("Warning: contest configuration already exists; ignoring " + AppConstants.LOAD_OPTION_STRING + " option"); + } } } /** * Dump Auto Start information to log. - * + * * @param contestInformation */ private void dumpAutoStartInformation(ContestInformation contestInformation) { @@ -2898,19 +2968,20 @@ private void dumpAutoStartInformation(ContestInformation contestInformation) { /** * Start the UI. */ + @Override public void start(String[] stringArray) { /** * Saved exception. - * + * * If TransportException thrown before UI has been created, save the exception and present it on the UI later. */ TransportException savedTransportException = null; - String[] requireArgumentArgs = { // - AppConstants.LOGIN_OPTION_STRING, + String[] requireArgumentArgs = { // + AppConstants.LOGIN_OPTION_STRING, AppConstants.PASSWORD_OPTION_STRING, - AppConstants.MAIN_UI_OPTION_STRING, + AppConstants.MAIN_UI_OPTION_STRING, AppConstants.REMOTE_SERVER_OPTION_STRING, // AppConstants.PORT_OPTION_STRING, // AppConstants.LOAD_OPTION_STRING, // @@ -2919,7 +2990,7 @@ public void start(String[] stringArray) { AppConstants.CONTEST_PASSWORD_OPTION_STRING, // AppConstants.CONTEST_ID_OPTION_STRING, AppConstants.FILE_OPTION_STRING }; - + /** * This will not catch unknown options, that is done below after logging is set up * We scan the arguments twice. First time to allow logging to be set up @@ -2931,24 +3002,24 @@ public void start(String[] stringArray) { // mostly catches "IllegalArgumentException" and informs the user fatalError(e.getMessage(), e); } - + /** * usingGUI should be set early no matter what, since we do not want to pop-up * GUI message boxes on errors, if NO_GUI_OPTION_STRING was specified. * Validation of NO_GUI_OPTION_STRING is handled in handleCommandLineOptions(). * That is, currently, NO_GUI_OPTION_STRING is only allowed for AJ and server. - * We don't care about that at this point in time though. + * We don't care about that at this point in time though. */ if (parseArguments.isOptPresent(AppConstants.NO_GUI_OPTION_STRING)) { usingGUI = false; } - + if (parseArguments.isOptPresent(AppConstants.DEBUG_OPTION_STRING)){ parseArguments.dumpArgs(System.out); } - + contest.setCommandLineArguments(parseArguments); - + if (parseArguments.isOptPresent(AppConstants.SERVER_OPTION_STRING)) { if (!isContactingRemoteServer()) { theProfile = getCurrentProfile(); @@ -2961,7 +3032,7 @@ public void start(String[] stringArray) { } else { startLog(null, "pc2.startup."+System.currentTimeMillis(), null, null); } - + // make sure supplied arguments are recognized (allowed) try { // this is the second scan of the argument list where accepted options are checked. @@ -2986,7 +3057,7 @@ public void start(String[] stringArray) { /** * if (args DOES NOT contains login/pwd) { String s; if (args contains LoginUI ) { s = args login UI } else { s = pc2 LoginFrame } UIPlugin l = classloader (s); l.setModelAndListener (contest, * this); } else { this.login (login,password) - * + * */ log.info("Starting ConnectionManager..."); @@ -3022,7 +3093,7 @@ public void start(String[] stringArray) { fatalError("Cannot start PC^2, " + iniName + " cannot be read (" + exception.getMessage() + ")", exception); } //the following line was deleted when InternalController was updated per b_1564_integrate_API_work -// IniFile.setHashtable(ini.getHashmap()); +// IniFile.setHashtable(ini.getHashmap()); } contest.setSiteNumber(0); @@ -3061,7 +3132,7 @@ public void start(String[] stringArray) { try { setServerPort(parseArguments.getOptValue(AppConstants.PORT_OPTION_STRING)); } catch (NumberFormatException numException) { - savedTransportException = new TransportException("Unable to parse value after " + + savedTransportException = new TransportException("Unable to parse value after " + AppConstants.PORT_OPTION_STRING + "'" + parseArguments.getOptValue(AppConstants.PORT_OPTION_STRING) + "'"); log.log(Log.WARNING, "Exception parsing " + AppConstants.PORT_OPTION_STRING, numException); } @@ -3176,7 +3247,7 @@ private UIPlugin loadUIClass(String className) { /** * Get current profile, create one if needed. - * + * * @return */ private Profile getCurrentProfile() { @@ -3218,7 +3289,7 @@ private void handleCommandLineOptions() { "[" + AppConstants.FIRST_SERVER_OPTION_STRING + "] " + // "[" + AppConstants.LOGIN_OPTION_STRING + " ] " + // "[" + AppConstants.PASSWORD_OPTION_STRING + " ]", // - " " + + " " + "[" + AppConstants.LOAD_OPTION_STRING + "

    | ] " + // "[" + AppConstants.SKIP_INI_OPTION_STRING + "] " + // "[" + AppConstants.INI_FILENAME_OPTION_STRING + " INIfilename] " + // @@ -3230,11 +3301,11 @@ private void handleCommandLineOptions() { " " + "[" + AppConstants.NOLOGGING_OPTION_STRING + "] " + // "[" + AppConstants.NO_GUI_OPTION_STRING + "] " + // - "[" + AppConstants.NOSTANDINGS_OPTION_STRING + "] " + - "[" + AppConstants.NO_CONNECTIONS_PANE_OPTION_STRING + "] " + + "[" + AppConstants.NOSTANDINGS_OPTION_STRING + "] " + + "[" + AppConstants.NO_CONNECTIONS_PANE_OPTION_STRING + "] " + "[" + AppConstants.NO_LOGINS_PANE_OPTION_STRING + "]", // "", // - "See https://github.com/pc2ccs/pc2v9/wiki/Command-Line-Arguments for more information", // + "See https://github.com/pc2ccs/pc2v9/wiki/Command-Line-Arguments for more information", // }; for (String string : usage) { System.out.println(string); @@ -3259,7 +3330,7 @@ private void handleCommandLineOptions() { fatalError("Unable to read file " + propertiesFileName, e); } } - + if (parseArguments.isOptPresent(AppConstants.NOSTANDINGS_OPTION_STRING)) { Utilities.setShowStandingsPanes(false); } @@ -3297,7 +3368,7 @@ private void handleCommandLineOptions() { } else if (isScoreboard(client)){ overRideUIName = "edu.csus.ecs.pc2.ui.board.ScoreboardModule"; } else if (isEventFeeder(client)) { - overRideUIName = "edu.csus.ecs.pc2.services.eventFeed.EventFeederModule"; + overRideUIName = "edu.csus.ecs.pc2.services.eventFeed.EventFeederModule"; } else { fatalError(AppConstants.NO_GUI_OPTION_STRING + " can only be used with a judge, server, scoreboard or event feed login, login '" + loginName + "' is not one of those."); } @@ -3359,18 +3430,18 @@ private boolean isEventFeeder(ClientId clientId) { /** * Print debug message to stdout. - * + * * @param string */ protected void printDebug(String message) { System.out.println("debug: "+message); - + } private boolean isJudge(ClientId clientId) { return clientId.getClientType().equals(ClientType.Type.JUDGE); } - + private boolean isScoreboard(ClientId clientId) { return clientId.getClientType().equals(ClientType.Type.SCOREBOARD); } @@ -3382,9 +3453,9 @@ private ClientId getServerClientId() { /** * Return working directory. - * + * * File.separator has already been appended as needed. - * + * * @param dirname * @return profile directory if server, else return ""; */ @@ -3399,9 +3470,9 @@ private String getBaseProfileDirectoryName(String dirname) { /** * Start new Log for client/server. - * + * * This new a new Log(logFileName), sets up the StaticLog, and prints basic info to the log. If loginName is not null a Login: line is printed. - * + * * @param directoryName * if null will use the profile/* directory. * @param logFileName @@ -3435,12 +3506,14 @@ private void startLog(String directoryName, String logFileName, String loginName } } + @Override public void checkOutRun(Run run, boolean readOnly, boolean computerJudge) { ClientId clientId = contest.getClientId(); Packet packet = PacketFactory.createRunRequest(clientId, getServerClientId(), run, clientId, readOnly, computerJudge); sendToLocalServer(packet); } + @Override public void checkOutRejudgeRun(Run run) { ClientId clientId = contest.getClientId(); Packet packet = PacketFactory.createRunRejudgeRequest(clientId, getServerClientId(), run, clientId); @@ -3450,6 +3523,7 @@ public void checkOutRejudgeRun(Run run) { /** * Send run judgement to server. */ + @Override public void submitRunJudgement(Run run, JudgementRecord judgementRecord, RunResultFiles runResultFiles) { ClientId clientId = contest.getClientId(); Packet packet = PacketFactory.createRunJudgement(clientId, getServerClientId(), run, judgementRecord, runResultFiles); @@ -3459,6 +3533,7 @@ public void submitRunJudgement(Run run, JudgementRecord judgementRecord, RunResu /** * Send cancel run to server. */ + @Override public void cancelRun(Run run) { ClientId clientId = contest.getClientId(); Packet packet = PacketFactory.createUnCheckoutRun(clientId, getServerClientId(), run, clientId); @@ -3467,11 +3542,12 @@ public void cancelRun(Run run) { /** * Add a new site into contest, send update to other servers. - * + * * @throws FileSecurityException * @throws ClassNotFoundException * @throws IOException */ + @Override public void addNewSite(Site site) { if (isServer()) { contest.addSite(site); @@ -3511,6 +3587,7 @@ public void modifySite(Site site) { sendToServers(packet); } + @Override public void sendServerLoginRequest(int inSiteNumber) throws Exception { if (isServer()) { @@ -3525,7 +3602,7 @@ public void sendServerLoginRequest(int inSiteNumber) throws Exception { } Site remoteSite = lookupRemoteServer(inSiteNumber); - + Site localSite = contest.getSite(contest.getSiteNumber()); String localPassword = localSite.getPassword(); @@ -3554,7 +3631,7 @@ public void sendServerLoginRequest(int inSiteNumber) throws Exception { info("Contacted Site " + inSiteNumber + " (via " + remoteSite.getSiteNumber() + ") using connection id " + connectionHandlerID); sendLoginRequestFromServerToServer(connectionManager, connectionHandlerID, getServerClientId(), localPassword, false, inSiteNumber); - + } else if (contest.isAllowed(Permission.Type.ALLOWED_TO_RECONNECT_SERVER)) { // Send the reconnection request to our server @@ -3571,9 +3648,9 @@ public void sendServerLoginRequest(int inSiteNumber) throws Exception { /** * Determine which site to send this packet to. - * + * * This handles packets sent via proxy. - * + * * @param inSiteNumber destination site * @return site to send packet to. */ @@ -3584,8 +3661,8 @@ protected Site lookupRemoteServer(int inSiteNumber) { */ Site site = contest.getSite(inSiteNumber); Site mySite = contest.getSite(contest.getSiteNumber()); - - // if the destination has a proxy + + // if the destination has a proxy if (site.hasProxy()) { /** @@ -3599,14 +3676,14 @@ protected Site lookupRemoteServer(int inSiteNumber) { } else if (mySite.hasProxy()) { site = contest.getSite(mySite.getMyProxy()); }// else no proxys, send to site - + // System.out.println("debug lookupRemoteServer for site "+inSiteNumber+" use site "+site); return site; } /** * Contacting remote server (joining contest). - * + * * @return true if joining contest, false if first server */ public boolean isContactingRemoteServer() { @@ -3619,9 +3696,9 @@ public void setContactingRemoteServer(boolean contactingRemoteServer) { /** * Will main UI be invoked/displayed ? - * + * * This includes Login UI as well as Main UI. - * + * * @return true - shows main UI, false - does not show main UI. */ public boolean isUsingMainUI() { @@ -3640,6 +3717,7 @@ public void setUiPlugin(UIPlugin uiPlugin) { this.uiPlugin = uiPlugin; } + @Override public void updateSite(Site site) { if (isServer()) { @@ -3670,7 +3748,7 @@ public void updateSite(Site site) { /** * Returns true if this client is a server. - * + * * @return true if logged in client is a server. */ private boolean isServer() { @@ -3681,21 +3759,25 @@ private boolean isServer(ClientId clientId) { return clientId.getClientType().equals(ClientType.Type.SERVER); } + @Override public final Log getLog() { return log; } + @Override public void generateNewAccounts(String clientTypeName, int siteNumber, int count, int startNumber, boolean active) { ClientType.Type type = ClientType.Type.valueOf(clientTypeName); Packet packet = PacketFactory.createGenerateAccounts(contest.getClientId(), getServerClientId(), siteNumber, type, count, startNumber, active); sendToLocalServer(packet); } + @Override public void generateNewAccounts(String clientTypeName, int count, int startNumber, boolean active) { generateNewAccounts(clientTypeName, contest.getSiteNumber(), count, startNumber, active); } + @Override public void submitClarification(Problem problem, String question) { ClientId serverClientId = new ClientId(contest.getSiteNumber(), Type.SERVER, 0); @@ -3706,27 +3788,31 @@ public void submitClarification(Problem problem, String question) { sendToLocalServer(packet); } + @Override public void checkOutClarification(Clarification clarification, boolean readOnly) { ClientId serverClientId = new ClientId(contest.getSiteNumber(), Type.SERVER, 0); Packet packet = PacketFactory.createClarificationRequest(contest.getClientId(), serverClientId, clarification.getElementId(), contest.getClientId()); sendToLocalServer(packet); } + @Override public void cancelClarification(Clarification clarification) { ClientId serverClientId = new ClientId(contest.getSiteNumber(), Type.SERVER, 0); Packet packet = PacketFactory.createUnCheckoutClarification(contest.getClientId(), serverClientId, clarification); sendToLocalServer(packet); } + @Override public void submitClarificationAnswer(Clarification clarification) { ClientId serverClientId = new ClientId(contest.getSiteNumber(), Type.SERVER, 0); Packet packet = PacketFactory.createAnsweredClarification(contest.getClientId(), serverClientId, clarification, clarification.getAnswer()); sendToLocalServer(packet); } + @Override public void forceConnectionDrop(ConnectionHandlerID connectionHandlerID) { - //this method should never be called with a null ConnectionHandlerID; however, the addition of + //this method should never be called with a null ConnectionHandlerID; however, the addition of // "multiple login" support may have left some place where this is inadvertently true. //The following is an effort to catch/identify such situations. if (connectionHandlerID==null) { @@ -3735,7 +3821,7 @@ public void forceConnectionDrop(ConnectionHandlerID connectionHandlerID) { logException("InternalController.forceConnectionDrop() called with null ConnectionHandlerID", e); throw e; } - + if (isServer()) { if (contest.isConnected(connectionHandlerID)) { @@ -3755,40 +3841,48 @@ public void forceConnectionDrop(ConnectionHandlerID connectionHandlerID) { } } + @Override public void addNewProblem(Problem problem, ProblemDataFiles problemDataFiles) { Packet updateProblemPacket = PacketFactory.createAddSetting(contest.getClientId(), getServerClientId(), problem, problemDataFiles); sendToLocalServer(updateProblemPacket); } + @Override public void addNewProblem(Problem[] problem, ProblemDataFiles[] problemDataFiles) { Packet updateProblemPacket = PacketFactory.createAddSetting(contest.getClientId(), getServerClientId(), problem, problemDataFiles); sendToLocalServer(updateProblemPacket); } + @Override public void updateRun(Run run, JudgementRecord judgementRecord, RunResultFiles runResultFiles) { Packet updateRunPacket = PacketFactory.createRunUpdated(contest.getClientId(), getServerClientId(), run, judgementRecord, runResultFiles, contest.getClientId()); sendToLocalServer(updateRunPacket); } + @Override public void addProblem(Problem problem) { Packet updateProblemPacket = PacketFactory.createAddSetting(contest.getClientId(), getServerClientId(), problem, null); sendToLocalServer(updateProblemPacket); } + @Override public void updateProblem(Problem problem) { Packet updateProblemPacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), problem, null); sendToLocalServer(updateProblemPacket); } + @Override public void updateProblem(Problem problem, ProblemDataFiles problemDataFiles) { Packet updateProblemPacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), problem, problemDataFiles); sendToLocalServer(updateProblemPacket); } + @Override public ProblemDataFiles getProblemDataFiles(Problem problem) { return contest.getProblemDataFile(problem); } + @Override public void shutdownTransport() { connectionManager.shutdownTransport(); } @@ -3796,6 +3890,7 @@ public void shutdownTransport() { /** * Removes connection from list and sends packet. */ + @Override public void removeConnection(ConnectionHandlerID connectionHandlerID) { contest.connectionDropped(connectionHandlerID); @@ -3809,6 +3904,7 @@ public void removeConnection(ConnectionHandlerID connectionHandlerID) { /** * Removed login from system and sends packet. */ + @Override public void removeLogin(ClientId clientId) { contest.removeLogin(clientId); @@ -3825,66 +3921,79 @@ public void removeLogin(ClientId clientId) { } } + @Override public void startContest(int inSiteNumber) { Packet packet = PacketFactory.createStartContestClock(contest.getClientId(), getServerClientId(), inSiteNumber, contest.getClientId()); sendToLocalServer(packet); } + @Override public void stopContest(int inSiteNumber) { Packet packet = PacketFactory.createStopContestClock(contest.getClientId(), getServerClientId(), inSiteNumber, contest.getClientId()); sendToLocalServer(packet); } + @Override public void startAllContestTimes() { Packet packet = PacketFactory.createStartAllClocks(contest.getClientId(), getServerClientId(), contest.getClientId()); sendToLocalServer(packet); } + @Override public void stopAllContestTimes() { Packet packet = PacketFactory.createStopAllClocks(contest.getClientId(), getServerClientId(), contest.getClientId()); sendToLocalServer(packet); } + @Override public void addNewLanguage(Language language) { Packet addLanguagePacket = PacketFactory.createAddSetting(contest.getClientId(), getServerClientId(), language); sendToLocalServer(addLanguagePacket); } + @Override public void addNewJudgement(Judgement judgement) { Packet addJudgementPacket = PacketFactory.createAddSetting(contest.getClientId(), getServerClientId(), judgement); sendToLocalServer(addJudgementPacket); } + @Override public void updateLanguage(Language language) { Packet updateLanguagePacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), language); sendToLocalServer(updateLanguagePacket); } + @Override public void updateJudgement(Judgement judgement) { Packet updatePacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), judgement); sendToLocalServer(updatePacket); } + @Override public void updateAccount(Account account) { Packet updatePacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), account); sendToLocalServer(updatePacket); } + @Override public void updateAccounts(Account[] accounts) { Packet updatePacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), accounts); sendToLocalServer(updatePacket); } + @Override public void updateCategories(Category[] categories) { Packet updatePacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), categories); sendToLocalServer(updatePacket); } + @Override public void addNewAccount(Account account) { Packet addAccountPacket = PacketFactory.createAddSetting(contest.getClientId(), getServerClientId(), account); sendToLocalServer(addAccountPacket); } + @Override public void addNewAccounts(Account[] accounts) { Packet addAccountPacket = PacketFactory.createAddSetting(contest.getClientId(), getServerClientId(), accounts); sendToLocalServer(addAccountPacket); @@ -3892,9 +4001,9 @@ public void addNewAccounts(Account[] accounts) { /** * Read Configuration. - * + * * Halt if configuration is corrupt. - * + * * @param siteNum * @return true if config file read */ @@ -3904,15 +4013,15 @@ public boolean readConfigFromDisk(int siteNum) { if (saveCofigurationToDisk) { try { loadedConfiguration = contest.readConfiguration(siteNum, getLog()); - + } catch (FileNotFoundException fnf){ // This is expected loadedConfiguration = false; - + } catch (Exception e) { logException(e); - - // Bug 879 -If there is a problem reading the config then exit and show a message. + + // Bug 879 -If there is a problem reading the config then exit and show a message. fatalError("Halting server - configuration file corrupt", e); return false; } @@ -3920,36 +4029,43 @@ public boolean readConfigFromDisk(int siteNum) { return loadedConfiguration; } + @Override public void addNewClientSettings(ClientSettings clientSettings) { Packet addClientSettingsPacket = PacketFactory.createAddSetting(contest.getClientId(), getServerClientId(), clientSettings); sendToLocalServer(addClientSettingsPacket); } + @Override public void updateClientSettings(ClientSettings clientSettings) { Packet updateClientSettingsPacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), clientSettings); sendToLocalServer(updateClientSettingsPacket); } + @Override public void updateContestInformation(ContestInformation contestInformation) { Packet contestInfoPacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), contestInformation); sendToLocalServer(contestInfoPacket); } + @Override public void setJudgementList(Judgement[] judgementList) { Packet updatePacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), judgementList); sendToLocalServer(updatePacket); } + @Override public void removeJudgement(Judgement judgement) { Packet deleteJudgmentPacket = PacketFactory.createDeleteSetting(contest.getClientId(), getServerClientId(), judgement); sendToLocalServer(deleteJudgmentPacket); } + @Override public void addNewBalloonSettings(BalloonSettings newBalloonSettings) { Packet newBalloonSettingsPacket = PacketFactory.createAddSetting(contest.getClientId(), getServerClientId(), newBalloonSettings); sendToLocalServer(newBalloonSettingsPacket); } + @Override public void updateBalloonSettings(BalloonSettings balloonSettings) { Packet balloonSettingsPacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), balloonSettings); sendToLocalServer(balloonSettingsPacket); @@ -3959,32 +4075,37 @@ public int getSiteNumber() { return contest.getSiteNumber(); } + @Override public void updateContestTime(ContestTime newContestTime) { Packet newContestTimePacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), newContestTime); sendToLocalServer(newContestTimePacket); } + @Override public void addNewGroup(Group group) { Packet newGroupPacket = PacketFactory.createAddSetting(contest.getClientId(), getServerClientId(), group); sendToLocalServer(newGroupPacket); } + @Override public void updateGroup(Group group) { Packet groupPacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), group); sendToLocalServer(groupPacket); } + @Override public int getSecurityLevel() { return securityLevel; } + @Override public void setSecurityLevel(int securityLevel) { this.securityLevel = securityLevel; } /** * Server send out security packet. - * + * */ public void sendSecurityMessageFromServer(ContestSecurityException contestSecurityException, ConnectionHandlerID connectionHandlerID, Packet packet) { Packet violationPacket = PacketFactory.createSecurityMessagePacket(contest.getClientId(), PacketFactory.ALL_SERVERS, contestSecurityException.getSecurityMessage(), null, connectionHandlerID, @@ -3997,20 +4118,24 @@ public void sendSecurityMessageFromServer(ContestSecurityException contestSecuri } + @Override public void sendSecurityMessage(String event, String message, ContestSecurityException contestSecurityException) { Packet securityMessagePacket = PacketFactory.createSecurityMessagePacket(contest.getClientId(), getServerClientId(), event, contestSecurityException.getClientId(), contestSecurityException.getConnectionHandlerID(), contestSecurityException, null); sendToLocalServer(securityMessagePacket); } + @Override public String getHostContacted() { return remoteHostName; } + @Override public int getPortContacted() { return remoteHostPort; } + @Override public void fetchRun(Run run) throws IOException, ClassNotFoundException, FileSecurityException { RunFiles runFiles = contest.getRunFiles(run); @@ -4030,42 +4155,51 @@ private void sendStatusMessge(Run run, RunExecutionStatus status) { } } + @Override public void sendCompilingMessage(Run run) { sendStatusMessge(run, RunExecutionStatus.COMPILING); } + @Override public void sendExecutingMessage(Run run) { sendStatusMessge(run, RunExecutionStatus.EXECUTING); } + @Override public void sendValidatingMessage(Run run) { sendStatusMessge(run, RunExecutionStatus.VALIDATING); } + @Override public boolean isClientAutoShutdown() { return clientAutoShutdown; } + @Override public void setClientAutoShutdown(boolean clientAutoShutdown) { this.clientAutoShutdown = clientAutoShutdown; } + @Override public void resetContest(ClientId clientResettingContest, boolean eraseProblems, boolean eraseLanguages) { Profile currentProfile = contest.getProfile(); Packet sendPacket = PacketFactory.createResetAllSitesPacket(contest.getClientId(), getServerClientId(), clientResettingContest, currentProfile, eraseProblems, eraseLanguages); sendToLocalServer(sendPacket); } + @Override public void cloneProfile(Profile profile, ProfileCloneSettings settings, boolean switchNow) { Packet sendPacket = PacketFactory.createCloneProfilePacket(contest.getClientId(), getServerClientId(), profile, settings, switchNow); sendToLocalServer(sendPacket); } + @Override public void switchProfile(Profile currentProfile, Profile switchToProfile, String contestPassword) { Packet sendPacket = PacketFactory.createSwitchProfilePacket(contest.getClientId(), getServerClientId(), currentProfile, switchToProfile, contestPassword); sendToLocalServer(sendPacket); } + @Override public void updateProfile(Profile profile) { Packet updateProfilePackert = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), profile); sendToLocalServer(updateProfilePackert); @@ -4094,12 +4228,12 @@ private void showErrorMessage(String message, String title) { /** * Fatal error - log error and show user message before exiting. - * + * * @param message * @param ex */ protected void fatalError(String message, Exception ex) { - + if (log != null) { if (ex != null) { log.log(Log.SEVERE, message, ex); @@ -4131,11 +4265,11 @@ protected void fatalError(String message, Exception ex) { if (haltOnFatalError) { System.exit(4); } - + } /** - * + * * @see #fatalError(String, Exception) * @param message */ @@ -4143,6 +4277,7 @@ private void fatalError(String message) { fatalError(message, null); } + @Override public void setContest(IInternalContest newContest) { this.contest = newContest; contest.setCommandLineArguments(parseArguments); @@ -4150,10 +4285,12 @@ public void setContest(IInternalContest newContest) { runSubmitterInterfaceManager.setContestAndController(newContest, this); } + @Override public void register(UIPlugin plugin) { pluginList.register(plugin); } + @Override public UIPlugin[] getPluginList() { return pluginList.getList(); } @@ -4170,6 +4307,7 @@ private void firePacketListener(PacketEvent packetEvent) { } } + @Override public void updateContestController(IInternalContest inContest, IInternalController inController) { setContest(inContest); @@ -4250,19 +4388,23 @@ private void logException(String message, Exception e) { } } + @Override public void addPacketListener(IPacketListener packetListener) { packetListenerList.addElement(packetListener); } + @Override public void removePacketListener(IPacketListener packetListener) { packetListenerList.removeElement(packetListener); } + @Override public void incomingPacket(Packet packet) { PacketEvent event = new PacketEvent(Action.RECEIVED, packet); firePacketListener(event); } + @Override public void outgoingPacket(Packet packet) { PacketEvent event = new PacketEvent(Action.SENT, packet); firePacketListener(event); @@ -4272,18 +4414,22 @@ public void setLog(Log log) { this.log = log; } + @Override public boolean isUsingGUI() { return usingGUI; } + @Override public boolean isSuppressConnectionsPaneDisplay() { return suppressConnectionsPaneDisplay; } + @Override public boolean isSuppressLoginsPaneDisplay() { return suppressLoginsPaneDisplay; } + @Override public ILogWindow startLogWindow(IInternalContest inContest) { if (!isUsingGUI()) { @@ -4305,11 +4451,12 @@ public ILogWindow startLogWindow(IInternalContest inContest) { return logWindow; } - private String noLogWindowAvailableMsg = - "Log Window is null or invalid; cannot show log." + private String noLogWindowAvailableMsg = + "Log Window is null or invalid; cannot show log." + "\n (Log Windows were temporarily disabled in certain Clients (see Issue https://github.com/pc2ccs/pc2v9/pull/555);" - + "\n you may be running a version of PC^2 which still includes this patch...)"; + + "\n you may be running a version of PC^2 which still includes this patch...)"; + @Override public void showLogWindow(boolean showWindow) { if (isUsingGUI()) { @@ -4322,6 +4469,7 @@ public void showLogWindow(boolean showWindow) { } } + @Override public boolean isLogWindowVisible() { if (isUsingGUI()) { if (logWindow != null && logWindow instanceof ILogWindow) { @@ -4340,6 +4488,7 @@ public void logWarning(String string) { System.err.println("Warning: " + string); } + @Override public void logWarning(String string, Exception e) { log.log(Log.WARNING, string, e); System.err.println("Warning: " + string); @@ -4367,24 +4516,28 @@ private void printStackTraceTop(Throwable throwable, PrintStream printStream, in } } + @Override public void syncProfileSubmissions(Profile profile) { Packet packet = PacketFactory.createSwitchSynchronizePacket(contest.getClientId(), getServerClientId(), profile); sendToLocalServer(packet); } + @Override public void sendShutdownAllSites() { Packet packet = PacketFactory.createShutdownAllServersPacket(contest.getClientId(), getServerClientId()); sendToLocalServer(packet); } + @Override public void sendShutdownSite(int siteNumber) { Packet packet = PacketFactory.createShutdownPacket(contest.getClientId(), getServerClientId(), siteNumber); sendToLocalServer(packet); } /** - * + * */ + @Override public void shutdownServer(ClientId requestor) { if (isServer()) { @@ -4418,6 +4571,7 @@ public void shutdownServer(ClientId requestor) { } } + @Override public void shutdownRemoteServers(ClientId requestor) { if (contest.isAllowed(requestor, Permission.Type.SHUTDOWN_ALL_SERVERS)) { @@ -4434,6 +4588,7 @@ public void shutdownRemoteServers(ClientId requestor) { } } + @Override public void shutdownServer(ClientId requestor, int siteNumber) { if (contest.isAllowed(requestor, Permission.Type.SHUTDOWN_ALL_SERVERS) || contest.isAllowed(requestor, Permission.Type.SHUTDOWN_SERVER)) { @@ -4476,30 +4631,36 @@ protected ClientId getServerClientId(int siteNumber) { return new ClientId(siteNumber, Type.SERVER, 0); } + @Override public void updateFinalizeData(FinalizeData data) { Packet updateFinalizePacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), data); sendToLocalServer(updateFinalizePacket); } + @Override public void setUsingGUI(boolean usingGUI) { this.usingGUI = usingGUI; } + @Override public void updateCategory(Category newCategory) { Packet updatePacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), newCategory); sendToLocalServer(updatePacket); } + @Override public void addNewCategory(Category newCategory) { Packet addNewCategory = PacketFactory.createAddSetting(contest.getClientId(), getServerClientId(), newCategory); sendToLocalServer(addNewCategory); } + @Override public void startPlayback(PlaybackInfo playbackInfo) { Packet startPacket = PacketFactory.createStartPlayback(contest.getClientId(), getServerClientId(), playbackInfo); sendToLocalServer(startPacket); } + @Override public void sendRunToSubmissionInterface(Run run, RunFiles runFiles) { try { runSubmitterInterfaceManager.sendRun(run, runFiles); @@ -4520,15 +4681,16 @@ public void addConsoleLogging() { System.err.println("Unable to add console logging, log is null"); } } - + public Profile getTheProfile() { return theProfile; } - + public void setTheProfile(Profile theProfile) { this.theProfile = theProfile; } - + + @Override public void autoRegister(String loginName) { ClientId serverClientId = new ClientId(contest.getSiteNumber(), Type.SERVER, 0); @@ -4541,11 +4703,11 @@ public void autoRegister(String loginName) { public void setConnectionManager(ITransportManager connectionManager) { this.connectionManager = connectionManager; } - + public void setHaltOnFatalError(boolean haltOnFatalError) { this.haltOnFatalError = haltOnFatalError; } - + public boolean isHaltOnFatalError() { return haltOnFatalError; } @@ -4573,18 +4735,19 @@ public void updateGroups(Group[] groups) { Packet updatePacket = PacketFactory.createUpdateSetting(contest.getClientId(), getServerClientId(), groups); sendToLocalServer(updatePacket); } - + /** * Creates an {@link AutoStarter} if none exists, and then instructs the AutoStarter to update its Scheduled Start Task to correspond to the Scheduled Start Time information in the * {@link ContestInformation} object in the received {@link IInternalContest}. - * + * * @param theContest * - the Contest (Model) containing the Scheduled Start Time information * @param theController * - the Controller to which this request applies */ + @Override public void updateAutoStartInformation(IInternalContest theContest, IInternalController theController) { - + // if I'm a server then if there's no AutoStarter create one, and then tell the AutoStarter to // update its Scheduled Start task list based on the ContestInformation in theContest (Model). // if (isServer()) { @@ -4641,7 +4804,7 @@ public void updateAutoStartInformation(IInternalContest theContest, IInternalCon // System.err.println ("in updateAutoStartInformation() -- NOT A SERVER!!"); // } } - + /** * Start Auto Stop Contest Clock Thread. */ @@ -4650,7 +4813,7 @@ private void updateAutoStopClockThread() { if (autoStopContestClockThread == null) { autoStopContestClockThread = new AutoStopContestClockThread(this, contest); autoStopContestClockThread.start(); - + ContestTime time = contest.getContestTime(); log.info("Started auto stop clock thread, remaining time is " + time.getRemainingTimeStr()); } @@ -4664,13 +4827,13 @@ public IInternalContest getContest() { @Override public void submitRun(ClientId submitter, Problem problem, Language language, SerializedFile mainSubmissionFile, SerializedFile[] additionalFiles, long overrideTimeMS, long overrideRunId) { - + submitRun(submitter, problem, language, null, mainSubmissionFile, additionalFiles, overrideTimeMS, overrideRunId); } @Override public void submitRun(ClientId submitter, Problem problem, Language language, String entry_point, SerializedFile mainSubmissionFile, SerializedFile[] additionalFiles, long overrideTimeMS, long overrideSubmissionId) { - + ClientId serverClientId = new ClientId(contest.getSiteNumber(), Type.SERVER, 0); Run run = new Run(submitter, language, problem); run.setEntryPoint(entry_point); @@ -4678,7 +4841,7 @@ public void submitRun(ClientId submitter, Problem problem, Language language, St Packet packet = PacketFactory.createSubmittedRun(contest.getClientId(), serverClientId, run, runFiles, overrideTimeMS, overrideSubmissionId); sendToLocalServer(packet); - + } - + } diff --git a/src/edu/csus/ecs/pc2/core/PacketHandler.java b/src/edu/csus/ecs/pc2/core/PacketHandler.java index 4fe1b8840..6fb04a94e 100644 --- a/src/edu/csus/ecs/pc2/core/PacketHandler.java +++ b/src/edu/csus/ecs/pc2/core/PacketHandler.java @@ -1561,6 +1561,8 @@ private void runSubmission(Packet packet, ClientId fromId, ConnectionHandlerID c } } + Boolean overrideStopOnFailure = (Boolean) PacketFactory.getObjectValue(packet, PacketFactory.OVERRIDE_STOP_ON_FAILURE); + ClientId submitter = submittedRun.getSubmitter(); boolean proxySubmission = ! submitter.equals(fromId); @@ -1589,6 +1591,7 @@ private void runSubmission(Packet packet, ClientId fromId, ConnectionHandlerID c } Run run = contest.acceptRun(submittedRun, runFiles); + boolean updateRun = false; /** * There are three conditions where a run would be added to the system but not appear on the scoreboard (or team's display): @@ -1600,6 +1603,14 @@ private void runSubmission(Packet packet, ClientId fromId, ConnectionHandlerID c if (contestTime.isPastEndOfContest() || !contestTime.isContestRunning() || submittedRun.getOverRideElapsedTimeMS() > contestTime.getContestLengthMS()) { run.setDeleted(true); submittedRun.setDeleted(true); + updateRun = true; + } + + if(overrideStopOnFailure) { + run.setOverrideStopOnFailure(true); + updateRun = true; + } + if(updateRun) { contest.updateRun(run, getServerClientId()); } diff --git a/src/edu/csus/ecs/pc2/core/execute/Executable.java b/src/edu/csus/ecs/pc2/core/execute/Executable.java index 630857363..9d3ef1827 100644 --- a/src/edu/csus/ecs/pc2/core/execute/Executable.java +++ b/src/edu/csus/ecs/pc2/core/execute/Executable.java @@ -510,6 +510,13 @@ public IFileViewer execute(boolean clearDirFirst) { //problem indicates stop-on-first-failure boolean stopOnFirstFailedTestCase = problem.isStopOnFirstFailedTestCase(); + // if we should override the overrideStopOnFailure, the unset our local flag. Also clear the + // run's copy of the flag since this is a one-shot flag. We do not wantto overrideStopOnFailure if + // the run is rejudged, for example. + if(run.isOverrideStopOnFailure()) { + stopOnFirstFailedTestCase = false; + run.setOverrideStopOnFailure(false); + } if (dataFiles == null || dataFiles.length <= 1) { diff --git a/src/edu/csus/ecs/pc2/core/model/Run.java b/src/edu/csus/ecs/pc2/core/model/Run.java index ebb71313d..57eff8582 100644 --- a/src/edu/csus/ecs/pc2/core/model/Run.java +++ b/src/edu/csus/ecs/pc2/core/model/Run.java @@ -111,6 +111,8 @@ public enum RunStates { private int overrideNumber = 0; + private boolean overrideStopOnFailure = false; + /** * Short/basename for submitted file. */ @@ -484,4 +486,22 @@ public String getEntryPoint(){ return null; } + + /** + * Sets the "one-shot" flag to override the stop on failure for a problem + * This is used for submitting sample judge runs. + * + * @param override true to override stop on failure, otherwise it uses the value for the problem + */ + public void setOverrideStopOnFailure(boolean override) { + overrideStopOnFailure = override; + } + + /** + * + * @return if we should override the stop on failure set for a problem + */ + public boolean isOverrideStopOnFailure() { + return overrideStopOnFailure; + } } diff --git a/src/edu/csus/ecs/pc2/core/packet/PacketFactory.java b/src/edu/csus/ecs/pc2/core/packet/PacketFactory.java index 00a5ef332..f1e38ecdb 100644 --- a/src/edu/csus/ecs/pc2/core/packet/PacketFactory.java +++ b/src/edu/csus/ecs/pc2/core/packet/PacketFactory.java @@ -48,7 +48,7 @@ /** * Creates {@link Packet}s. - * + * * Each packet can be created by using a method in this class. There is a "create" method for each {@link Type}.
    * There are also some methods to extract fields/classes from packets. *

    @@ -56,13 +56,13 @@ *

    * Constants are present in this class that are used to extract individual contents from a packet.
    * Example of extracting individual contents from a packet {@link edu.csus.ecs.pc2.core.packet.Packet}. - * + * *

      * Clarification clarification = (Clarification) PacketFactory.getObjectValue(packet, PacketFactory.CLARIFICATION);
    - * 
    + *
      * ClientId whoCheckedOut = (ClientId) PacketFactory.getObjectValue(packet, PacketFactory.CLIENT_ID);
      * 
    - * + * * @author pc2@ecs.csus.edu * @version $Id$ */ @@ -96,7 +96,7 @@ public final class PacketFactory { public static final String PROBLEM = "PROBLEM"; public static final String GENERAL_PROBLEM = "GENERAL_PROBLEM"; - + public static final String GROUP = "GROUP"; public static final String CLARIFICATION_ANSWER = "CLARIFICATION_ANSWER"; @@ -110,12 +110,12 @@ public final class PacketFactory { public static final String CLIENT_ID = "CLIENT_ID"; public static final String CONTEST_PASSWORD = "CONTEST_PASSWORD"; - + /** * Array of ClientIds of logged in users. */ public static final String LOCAL_LOGGED_IN_USERS = "LOCAL_LOGGED_IN_USERS"; - + /** * Array of ClientIds of logged in users. */ @@ -160,7 +160,7 @@ public final class PacketFactory { /** * A single ClientType.Type. - * + * * @see #createGenerateAccounts(ClientId, ClientId, int, ClientType.Type, int, int, boolean) */ public static final String CLIENT_TYPE = "CLIENT_TYPE"; @@ -169,7 +169,7 @@ public final class PacketFactory { /** * Used as a start count (id) for generating accounts. - * + * * If start count is 0, will add accounts after max account number.
    * If start count is 100, will add accounts after max account number is greater than 100. */ @@ -208,16 +208,16 @@ public final class PacketFactory { public static final String SITE_LIST = "SITE_LIST"; public static final String MESSAGE_STRING = "MESSAGE_STRING"; - + public static final String CONTEST_INFORMATION = "CONTEST_INFORMATION"; - + /** * Array of {@link ClientSettings}. */ public static final String CLIENT_SETTINGS_LIST = "CLIENT_SETTINGS_LIST"; - + public static final String CLIENT_SETTINGS = "CLIENT_SETTINGS"; - + /** * Array of {@link BalloonSettings}. */ @@ -234,11 +234,11 @@ public final class PacketFactory { * Boolean value. */ public static final String PASSWORD_CHANGED = "PASSWORD_CHANGED"; - + /** * On login, send settings to server. - * + * * Usually set to false.s */ public static final String SEND_SETTINGS = "SEND_SETTINGS"; @@ -274,7 +274,7 @@ public final class PacketFactory { * Array of {@link Judgement}. */ public static final String JUDGEMENT_LIST = "JUDGEMENT_LIST"; - + /** * Array of {@link ContestTime}. */ @@ -348,16 +348,18 @@ public final class PacketFactory { public static final String OVERRIDE_RUN_ID = "OVERRIDE_RUN_ID"; + public static final String OVERRIDE_STOP_ON_FAILURE = "OVERRIDE_STOP_ON_FAILURE"; + public static final String AUTO_REG_REQUEST_INFO = "AUTO_REG_REQUEST_INFO"; - + /** * List of files submitted by team. */ public static final String TEAM_RUN_SOURCE_FILES_LIST = "TEAM_RUN_SOURCE_FILES_LIST"; public static final String REQUEST_LOGIN_AS_PROXY = "REQUEST_LOGIN_AS_PROXY"; - - + + /** * Constructor is private as this is a utility class which should not be extended or invoked. */ @@ -367,7 +369,7 @@ private PacketFactory() { /** * Create a packet of {@link PacketType.Type#LOGIN_REQUEST}. - * + * * @param source - * who is logging in. * @param password - @@ -379,9 +381,9 @@ private PacketFactory() { public static Packet createLoginRequest(ClientId source, String loginName, String password, ClientId destination) { return createLoginRequest(source, loginName, password, destination, false); } - + /** - * + * * @param source * @param loginName * @param password @@ -397,7 +399,7 @@ public static Packet createLoginRequest(ClientId source, String loginName, Strin prop.put(REQUEST_LOGIN_AS_PROXY, new Boolean(proxiedSite)); return createPacket(PacketType.Type.LOGIN_REQUEST, source, destination, prop); } - + public static Packet createPasswordChangeRequest(ClientId source, ClientId destination, String password, String newPassword) { Properties prop = new Properties(); prop.put(CLIENT_ID, source); @@ -405,7 +407,7 @@ public static Packet createPasswordChangeRequest(ClientId source, ClientId dest prop.put(NEW_PASSWORD, newPassword); return createPacket(PacketType.Type.PASSWORD_CHANGE_REQUEST, source, destination, prop); } - + public static Packet createPasswordChangeResult(ClientId source, ClientId destination, boolean passwordChanged, String message) { Properties prop = new Properties(); prop.put(CLIENT_ID, source); @@ -413,11 +415,11 @@ public static Packet createPasswordChangeResult(ClientId source, ClientId desti prop.put(PacketFactory.MESSAGE_STRING, message); return createPacket(PacketType.Type.PASSWORD_CHANGE_RESULTS, source, destination, prop); } - + /** * Create a packet. - * - * + * + * * @param type - * {@link PacketType.Type} * @param source - @@ -435,7 +437,7 @@ protected static Packet createPacket(Type type, ClientId source, ClientId destin /** * Create a packet of {@link PacketType.Type#MESSAGE}. - * + * * @param source * @param destination * @param message @@ -458,12 +460,14 @@ public static Packet createMessage(ClientId source, ClientId destination, Area a } /** * Create a packet of {@link PacketType.Type#RUN_SUBMISSION}. - * + * + * This method is for backward compatibiltiy for classes that do not pass the overrideStopOnFailure flag + * * @param source * @param destination * @param run * @param runFiles - * @param overrideSubmissionTime + * @param overrideSubmissionTime * @return submitted run packet. */ public static Packet createSubmittedRun(ClientId source, ClientId destination, Run run, RunFiles runFiles, long overrideSubmissionTime, long overrideRunId) { @@ -479,19 +483,46 @@ public static Packet createSubmittedRun(ClientId source, ClientId destination, R Packet packet = new Packet(Type.RUN_SUBMISSION, source, destination, prop); return packet; } - + + /** + * Create a packet of {@link PacketType.Type#RUN_SUBMISSION}. + * + * @param source + * @param destination + * @param run + * @param runFiles + * @param overrideSubmissionTime + * @param overrideRunId + * @param overrideStopOnFailure + * @return submitted run packet. + */ + public static Packet createSubmittedRun(ClientId source, ClientId destination, Run run, RunFiles runFiles, long overrideSubmissionTime, long overrideRunId, boolean overrideStopOnFailure) { + Properties prop = new Properties(); + prop.put(RUN, run); + prop.put(RUN_FILES, runFiles); + if (overrideSubmissionTime > 0) { + prop.put(ELAPSED_TIME, new Long(overrideSubmissionTime)); + } + if (overrideRunId > 0) { + prop.put(OVERRIDE_RUN_ID, new Long(overrideRunId)); + } + prop.put(OVERRIDE_STOP_ON_FAILURE, Boolean.valueOf(overrideStopOnFailure)); + Packet packet = new Packet(Type.RUN_SUBMISSION, source, destination, prop); + return packet; + } + public static Packet createRunSubmissionConfirmation(ClientId source, ClientId destination, Run run, RunFiles runFiles) { Properties prop = new Properties(); prop.put(RUN, run); prop.put(RUN_FILES, runFiles); Packet packet = new Packet(Type.RUN_SUBMISSION_CONFIRM_SERVER, source, destination, prop); return packet; - + } /** * Dump packet info to PrintWriter and System.err. - * + * * @param pw * @param packet */ @@ -522,10 +553,10 @@ public static void dumpPacket(PrintWriter pw, Packet packet) { pw.println(); } - + /** * Dump packet info to PrintWriter and System.err. - * + * * @param log * @param packet * @param message @@ -557,10 +588,10 @@ public static void dumpPacket(Log log, Packet packet, String message) { /** * Dump packet to PrintStream. - * + * * @param pw * @param packet - * @param message + * @param message */ public static void dumpPacket(PrintStream pw, Packet packet, String message) { pw.println("Packet " + packet.getType() + " (Seq #" + packet.getPacketNumber() + ", o#" + packet.getOriginalPacketNumber() + " ) " + message); @@ -590,7 +621,7 @@ public static void dumpPacket(PrintStream pw, Packet packet, String message) { /** * Create a packet of {@link PacketType.Type#RUN_AVAILABLE}. - * + * * @param source * @param destination * @param run @@ -605,7 +636,7 @@ public static Packet createRunAvailable(ClientId source, ClientId destination, R /** * Create a packet of {@link PacketType.Type#RUN_UPDATE}. - * + * * @param source * @param destination * @param run @@ -626,7 +657,7 @@ public static Packet createRunUpdated(ClientId source, ClientId destination, Run Packet packet = new Packet(Type.RUN_UPDATE, source, destination, prop); return packet; } - + public static Packet createRunUpdateNotification(ClientId source, ClientId destination, Run run, ClientId whoModifiedRun) { Properties prop = new Properties(); prop.put(CLIENT_ID, whoModifiedRun); @@ -638,7 +669,7 @@ public static Packet createRunUpdateNotification(ClientId source, ClientId desti /** * Send checked out packet to requesting judge. - * + * * @param source * @param destination * @param run @@ -665,7 +696,7 @@ public static Packet createCheckedOutRun(ClientId source, ClientId destination, /** * Create packet that notifies judges and others that run has been checked out. - * + * * @param source * @param destination * @param run @@ -681,10 +712,10 @@ public static Packet createCheckedOutRunNotification(ClientId source, ClientId d return packet; } - + /** * Create a packet of {@link PacketType.Type#RUN_NOTAVAILABLE}. - * + * * @param source * @param destination * @param run @@ -695,10 +726,10 @@ public static Packet createRunNotAvailable(ClientId source, ClientId destination Packet packet = new Packet(Type.RUN_NOTAVAILABLE, source, destination, prop); return packet; } - + /** * Create a packet of {@link PacketType.Type#RUN_NOTAVAILABLE}. - * + * * @param source * @param destination * @param run @@ -713,7 +744,7 @@ public static Packet createRunRevoked (ClientId source, ClientId destination, Ru /** * Create a packet of {@link PacketType.Type#RUN_LIST}. - * + * * @param source * @param destination * @param runs @@ -727,7 +758,7 @@ public static Packet createRunList(ClientId source, ClientId destination, Run[] /** * Create a packet of {@link PacketType.Type#CLARIFICATION_LIST}. - * + * * @param source * @param destination * @param clarList @@ -739,7 +770,7 @@ public static Packet createClarList(ClientId source, ClientId destination, Clari /** * Create a packet of {@link PacketType.Type#RUN_UNCHECKOUT}. - * + * * @param source * @param destination * @param beingJudgingRun @@ -755,7 +786,7 @@ public static Packet createUnCheckoutRun(ClientId source, ClientId destination, /** * Create a packet of {@link PacketType.Type#RUN_JUDGEMENT}. - * + * * @param source * @param destination * @param run @@ -776,27 +807,27 @@ public static Packet createRunJudgement(ClientId source, ClientId destination, R return packet; } - + /** * Return the value (Object) inside a packet. - * + * * If the packet contents is a {@link Properties} object, will retrieve the value for the input key from that {@link Properties} * object. *

    * Examples: *

          * Clarification [] clarifications =(Clarification[]) PacketFactory.getObjectValue(packet, PacketFactory.CLARIFICATION_LIST);
    -     * 
    +     *
          * Run [] runs = (Run[]) PacketFactory.getObjectValue(packet, PacketFactory.RUN_LIST);
    -     * 
    +     *
          * ContestTime contestTime = (ContestTime) PacketFactory.getObjectValue(packet, PacketFactory.CONTEST_TIME);
    -     * 
    +     *
          * ClientId clientId = (ClientId) PacketFactory.getObjectValue(packet, PacketFactory.CLIENT_ID);
    -     * 
    +     *
          * 
    * One can then check for whether the item is null to determine whether item * is in the packet. - * + * * @param packet packet to extract data from. * @param key one of the many constant Strings in PacketFactory * @return a Object value for a property inside a packet, or null if object is not present. @@ -812,7 +843,7 @@ public static Object getObjectValue(Packet packet, String key) { /** * Return the String value inside a packet. - * + * * @see #getObjectValue(Packet, String) * @param packet * @param key @@ -824,7 +855,7 @@ public static String getStringValue(Packet packet, String key) { /** * Return the Boolean value inside a packet. - * + * * @see #getObjectValue(Packet, String) * @param packet * @param key @@ -836,7 +867,7 @@ public static Boolean getBooleanValue(Packet packet, String key) { /** * Create a packet of {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param language @@ -848,14 +879,14 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, Packet packet = new Packet(Type.UPDATE_SETTING, source, destination, prop); return packet; } - + public static Packet createUpdateSetting(ClientId source, ClientId destination, Profile profile) { Properties prop = new Properties(); prop.put(PROFILE, profile); Packet packet = new Packet(Type.UPDATE_SETTING, source, destination, prop); return packet; } - + public static Packet createUpdateSetting(ClientId source, ClientId destination, BalloonSettings balloonSettings) { Properties prop = new Properties(); prop.put(BALLOON_SETTINGS, balloonSettings); @@ -884,7 +915,7 @@ public static Packet createAddSetting(ClientId source, ClientId destination, Bal /** * Create a packet of {@link PacketType.Type#ADD_SETTING}. - * + * * @param source * @param destination * @param language @@ -919,7 +950,7 @@ public static Packet createAddSetting(ClientId source, ClientId destination, Pro /** * Create a packet of {@link PacketType.Type#ADD_SETTING}. - * + * * @param source * @param destination * @param judgement @@ -943,7 +974,7 @@ public static Packet createAddSetting(ClientId source, ClientId destination, Pro /** * Create a packet for a list of problems. - * + * * @param source * @param destination * @param problems @@ -957,12 +988,12 @@ public static Packet createAddSetting(ClientId source, ClientId destination, Pro return packet; } - /** + /** * Create start contest to send to server. * @param source * @param destination * @param siteNumber - * @param who + * @param who */ public static Packet createStartContestClock(ClientId source, ClientId destination, int siteNumber, ClientId who) { Properties prop = new Properties(); @@ -975,11 +1006,11 @@ public static Packet createStartContestClock(ClientId source, ClientId destinati /** * Create a stop contest to send to server. - * + * * @param source * @param destination * @param siteNumber - * @param who + * @param who */ public static Packet createStopContestClock(ClientId source, ClientId destination, int siteNumber, ClientId who) { Properties prop = new Properties(); @@ -988,10 +1019,10 @@ public static Packet createStopContestClock(ClientId source, ClientId destinatio Packet packet = new Packet(Type.STOP_CONTEST_CLOCK, source, destination, prop); return packet; } - + /** * Create a stop contest to send to clients. - * + * * @param source * @param destination * @param inSiteNumber @@ -1006,7 +1037,7 @@ public static Packet createContestStopped(ClientId source, ClientId destination, /** * Create a start contest to send to clients. - * + * * @param source * @param destination * @param inSiteNumber @@ -1025,7 +1056,7 @@ public static Packet createContestStarted(ClientId source, ClientId destination, /** * Create a packet of {@link PacketType.Type#UPDATE_CONTEST_CLOCK}. - * + * * @param source * @param destination * @param contestTime @@ -1042,7 +1073,7 @@ public static Packet createUpdateContestTime(ClientId source, ClientId destinati /** * Create a packet of {@link PacketType.Type#ACCOUNT_LOGIN}. - * + * * @param source * @param destination * @param connectionHandlerID @@ -1057,7 +1088,7 @@ public static Packet createAccountLogin(ClientId source, ClientId destination, C /** * Create a packet of {@link PacketType.Type#LOGOUT}. - * + * * @param source * @param destination * @param userId @@ -1071,7 +1102,7 @@ public static Packet createLogoff(ClientId source, ClientId destination, ClientI /** * Create a packet of {@link PacketType.Type#CLARIFICATION_SUBMISSION_CONFIRM}. - * + * * @param source * @param destination * @param newClarification @@ -1085,7 +1116,7 @@ public static Packet createClarSubmissionConfirm(ClientId source, ClientId desti /** * Create a packet of {@link PacketType.Type#CLARIFICATION_SUBMISSION}. - * + * * @param source * @param destination * @param clarification2 @@ -1100,7 +1131,7 @@ public static Packet createClarificationSubmission(ClientId source, ClientId des /** * Create a packet of {@link PacketType.Type#RUN_SUBMISSION_CONFIRM}. - * + * * @param source * @param destination * @param run @@ -1117,7 +1148,7 @@ public static Packet createRunSubmissionConfirm(ClientId source, ClientId destin * @param destination * @param connectionHandlerID * @param loggedInClientId - * @param settings + * @param settings */ public static Packet createLogin(ClientId source, ClientId destination, ConnectionHandlerID connectionHandlerID, ClientId loggedInClientId, ClientSettings settings) { Properties prop = new Properties(); @@ -1130,28 +1161,28 @@ public static Packet createLogin(ClientId source, ClientId destination, Connecti /** * Create packet for {@link PacketType.Type#LOGIN_SUCCESS}. - * + * * Sent to a client or server on successful login. This packet * has all contest data. - * + * * @param source * @param destination * @param contestTime * @param siteNumber - * @param information - * @param data + * @param information + * @param data */ public static Packet createLoginSuccess(ClientId source, ClientId destination, ContestTime contestTime, int siteNumber, ContestInformation information, ContestLoginSuccessData data) { try { Properties prop = new Properties(); - + prop.put(SITE_NUMBER, new Integer(siteNumber)); prop.put(CONTEST_TIME, contestTime); prop.put(CLIENT_ID, destination); prop.put(CONTEST_INFORMATION, information); - + addContestData(prop, data); - + TimeZone timeZone = TimeZone.getTimeZone("GMT"); GregorianCalendar gregorianCalendar = new GregorianCalendar(timeZone); prop.put(SERVER_CLOCK_OFFSET, gregorianCalendar); @@ -1165,17 +1196,17 @@ public static Packet createLoginSuccess(ClientId source, ClientId destination, C throw new SecurityException(e.getMessage()); } } - + /** * Add Contest Data into a Properties. - * + * * Can be used in a Packet. - * + * * @param prop * @param data */ private static void addContestData(Properties prop, ContestLoginSuccessData data) { - + prop.put(CONTEST_TIME_LIST, data.getContestTimes()); prop.put(PROBLEM_LIST, data.getProblems()); @@ -1199,15 +1230,15 @@ private static void addContestData(Properties prop, ContestLoginSuccessData data prop.put(SITE_NUMBER, new Integer(data.getSiteNumber())); prop.put(CONTEST_TIME, data.getContestTime()); prop.put(CONTEST_INFORMATION, data.getContestInformation()); - + if (data.getFinalizeData() != null) { prop.put(FINALIZE_DATA, data.getFinalizeData()); } - + if (data.getContestSecurityPassword() != null) { prop.put(CONTEST_PASSWORD, data.getContestSecurityPassword()); } - + if (data.getCategories() != null){ prop.put(CATEGORY_LIST, data.getCategories()); } @@ -1215,7 +1246,7 @@ private static void addContestData(Properties prop, ContestLoginSuccessData data /** * A contest settings packet. - * + * * @param source * @param destination * @param loginSuccessPacket @@ -1241,12 +1272,12 @@ public static Packet createContestSettingsPacket(ClientId source, ClientId desti } } - - + + /** * Create a packet of {@link PacketType.Type#SETTINGS}. - * + * * @param source * @param destination * @param props @@ -1258,7 +1289,7 @@ public static Packet createSettings(ClientId source, ClientId destination, Prope /** * Create packet for {@link PacketType.Type#LOGIN_FAILED}. - * + * * @param source * @param destination * @param string @@ -1273,7 +1304,7 @@ public static Packet createLoginDenied(ClientId source, ClientId destination, St /** * Create packet for {@link PacketType.Type#RUN_REQUEST}. - * + * * @param source * @param destination * @param run @@ -1289,7 +1320,7 @@ public static Packet createRunRequest(ClientId source, ClientId destination, Run Packet packet = new Packet(Type.RUN_REQUEST, source, destination, props); return packet; } - + /** * Create a request to fetch a run from the server. * @param source @@ -1305,12 +1336,12 @@ public static Packet createFetchRun(ClientId source, ClientId destination, Run r Packet packet = new Packet(Type.FETCH_RUN, source, destination, props); return packet; } - + /** * Create a run fetched (but not checked out) from server packet. - * + * * Response to createFetchRun. - * + * * @param source * @param destination * @param run @@ -1333,7 +1364,7 @@ public static Packet createFetchedRun(ClientId source, ClientId destination, Run /** * Create packet for {@link PacketType.Type#CLARIFICATION_REQUEST}. - * + * * @param source * @param destination * @param elementId @@ -1346,12 +1377,12 @@ public static Packet createClarificationRequest(ClientId source, ClientId destin Packet packet = new Packet(Type.CLARIFICATION_REQUEST, source, destination, props); return packet; } - - + + /** * Create packet for {@link PacketType.Type#CLARIFICATION_CHECKOUT}. - * + * * @param source * @param destination * @param clarification @@ -1368,7 +1399,7 @@ public static Packet createCheckedOutClarification(ClientId source, ClientId des /** * Create packet for {@link PacketType.Type#CLARIFICATION_UNCHECKOUT}. - * + * * @param source * @param destination * @param clarification @@ -1383,7 +1414,7 @@ public static Packet createUnCheckoutClarification(ClientId source, ClientId des /** * Create packet for {@link PacketType.Type#CLARIFICATION_AVAILABLE}. - * + * * @param source * @param destination * @param clarification @@ -1394,7 +1425,7 @@ public static Packet createClarificationAvailable(ClientId source, ClientId dest Packet packet = new Packet(Type.CLARIFICATION_AVAILABLE, source, destination, prop); return packet; } - + public static Packet createClarificationRevoked(ClientId source, ClientId destination, Clarification clarification, ClientId revokedFrom) { Properties prop = new Properties(); prop.put(CLARIFICATION, clarification); @@ -1406,7 +1437,7 @@ public static Packet createClarificationRevoked(ClientId source, ClientId destin /** * Create packet for {@link PacketType.Type#CLARIFICATION_UPDATE}. - * + * * @param source * @param destination * @param clarification @@ -1420,7 +1451,7 @@ public static Packet createClarificationUpdate(ClientId source, ClientId destina /** * Create packet for {@link PacketType.Type#CLARIFICATION_ANSWER}. - * + * * @param source * @param destination * @param clarification @@ -1438,7 +1469,7 @@ public static Packet createAnsweredClarification(ClientId source, ClientId desti /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param site @@ -1452,7 +1483,7 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, /** * Create packet for {@link PacketType.Type#ADD_SETTING}. - * + * * @param source * @param destination * @param account @@ -1463,7 +1494,7 @@ public static Packet createAddSetting(ClientId source, ClientId destination, Acc Packet packet = new Packet(Type.ADD_SETTING, source, destination, prop); return packet; } - + public static Packet createUpdateSetting(ClientId source, ClientId destination, Account [] accounts) { Properties prop = new Properties(); prop.put(CLIENT_ID, source); @@ -1485,7 +1516,7 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, /** * Create packet for {@link PacketType.Type#ADD_SETTING }. - * + * * @param source * @param destination * @param type @@ -1507,7 +1538,7 @@ public static Packet createGenerateAccounts(ClientId source, ClientId destinatio /** * Create packet for {@link PacketType.Type#ADD_SETTING }. - * + * * @param source * @param destination * @param type @@ -1523,7 +1554,7 @@ public static Packet createAddSetting(ClientId source, ClientId destination, Cli /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param account @@ -1537,7 +1568,7 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param group @@ -1548,10 +1579,10 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, Packet packet = new Packet(Type.UPDATE_SETTING, source, destination, prop); return packet; } - + /** * Create packet for {@link PacketType.Type#RUN_REJUDGE_REQUEST}. - * + * * @param source * @param destination * @param run @@ -1567,7 +1598,7 @@ public static Packet createRunRejudgeRequest(ClientId source, ClientId destinati /** * Create packet for {@link PacketType.Type#RUN_REJUDGE_CHECKOUT}. - * + * * @param source * @param destination * @param run @@ -1588,7 +1619,7 @@ public static Packet createRejudgeCheckedOut(ClientId source, ClientId destinati /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param timeValue @@ -1604,7 +1635,7 @@ public static Packet createUpdateContestLengthTime(ClientId source, ClientId des /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param timeValue @@ -1620,7 +1651,7 @@ public static Packet createUpdateContestRemainingTime(ClientId source, ClientId /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param timeValue @@ -1636,7 +1667,7 @@ public static Packet createUpdateContestElapsedTime(ClientId source, ClientId de /** * Create packet for {@link PacketType.Type#DROPPED_CONNECTION}. - * + * * @param source * @param destination * @param connectionHandlerID @@ -1650,7 +1681,7 @@ public static Packet createDroppedConnection(ClientId source, ClientId destinati /** * Create packet for {@link PacketType.Type#ESTABLISHED_CONNECTION}. - * + * * @param source * @param destination * @param connectionHandlerID @@ -1673,7 +1704,7 @@ public static Packet createEstablishedConnection(ClientId source, ClientId desti /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param run @@ -1690,7 +1721,7 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param run @@ -1714,7 +1745,7 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, /** * Create packet for {@link PacketType.Type#FORCE_DISCONNECTION}. - * + * * @param source * @param destination * @param userLoginId @@ -1728,7 +1759,7 @@ public static Packet createForceLogoff(ClientId source, ClientId destination, Cl /** * Create packet for {@link PacketType.Type#FORCE_DISCONNECTION}. - * + * * @param source * @param destination * @param connectionHandlerID @@ -1742,7 +1773,7 @@ public static Packet createForceLogoff(ClientId source, ClientId destination, Co /** * Create packet for {@link PacketType.Type#START_ALL_CLOCKS}. - * + * * @param source * @param destination * @param userLoginId @@ -1756,7 +1787,7 @@ public static Packet createStartAllClocks(ClientId source, ClientId destination, // /** // * Create packet for {@link PacketType.Type#RESET_CONTEST}. -// * +// * // * @param source // * @param destination // * @param siteNumber @@ -1773,7 +1804,7 @@ public static Packet createStartAllClocks(ClientId source, ClientId destination, /** * Create packet for {@link PacketType.Type#RESET_ALL_CONTESTS}. - * + * * @param source * @param destination * @param userLoginId @@ -1787,7 +1818,7 @@ public static Packet createResetAllSites(ClientId source, ClientId destination, /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param languageDisplayList @@ -1804,7 +1835,7 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param problemDisplayList @@ -1821,7 +1852,7 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param answer @@ -1838,7 +1869,7 @@ public static Packet createUpdateSettingDefaultClarificationAnswer(ClientId sour /** * Create packet for {@link PacketType.Type#STOP_ALL_CLOCKS}. - * + * * @param source * @param destination * @param userLoginId @@ -1861,7 +1892,7 @@ public static Packet createStopAllClocks(ClientId source, ClientId destination, /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param clarification @@ -1887,7 +1918,7 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, /** * Create packet for {@link PacketType.Type#UPDATE_SETTING}. - * + * * @param source * @param destination * @param clarification @@ -1908,7 +1939,7 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, /** * Create packet for {@link PacketType.Type#CONTEST_TIME}. - * + * * @param source * @param destination * @param inContestTime @@ -1927,26 +1958,26 @@ public static Packet createAddSetting(ClientId source, ClientId destination, Acc prop.put(ACCOUNT_ARRAY, accounts); return createPacket(PacketType.Type.ADD_SETTING, source, destination, prop); } - + public static Packet createAddSetting(ClientId source, ClientId destination, ClientSettings clientSettings) { Properties prop = new Properties(); prop.put(CLIENT_SETTINGS, clientSettings); Packet packet = new Packet(Type.ADD_SETTING, source, destination, prop); return packet; } - + public static Packet createRunJudgmentUpdate(ClientId source, ClientId destination, Run run, ClientId whoJudgedId) { Properties prop = new Properties(); prop.put(CLIENT_ID, whoJudgedId); prop.put(RUN, run); return createPacket(PacketType.Type.RUN_JUDGEMENT_UPDATE, source, destination, prop); } - + /** * Clone packet from existing packet. - * + * * Can reassign source and destination with affecting contents. - * + * * @param source * @param destination * @param packet @@ -1958,12 +1989,12 @@ public static Packet clonePacket(ClientId source, ClientId destination, Packet p newPacket.setOriginalSourceId(packet.getOriginalSourceId()); return newPacket; } - + /** * Clone packet and change packet type. - * + * * Can reassign type, source, and destination with affecting contents. - * + * * @param type * @param source * @param destination @@ -2013,7 +2044,7 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, Packet packet = new Packet(Type.UPDATE_SETTING, source, destination, prop); return packet; } - + public static Packet createUpdateSetting(ClientId source, ClientId destination, Judgement[] judgements) { Properties prop = new Properties(); prop.put(JUDGEMENT_LIST, judgements); @@ -2050,7 +2081,7 @@ public static Packet createReconnectPacket(ClientId source, ClientId destination return packet; } - public static Packet createSecurityMessagePacket(ClientId source, ClientId destination, String message, ClientId whoCanceledRun, + public static Packet createSecurityMessagePacket(ClientId source, ClientId destination, String message, ClientId whoCanceledRun, ConnectionHandlerID connectionHandlerID, ContestSecurityException contestSecurityException, Packet inPacket) { Properties prop = new Properties(); if (whoCanceledRun != null){ @@ -2061,12 +2092,12 @@ public static Packet createSecurityMessagePacket(ClientId source, ClientId desti prop.put(CONNECTION_HANDLE_ID, connectionHandlerID); } if (inPacket != null){ - prop.put(PACKET, inPacket); + prop.put(PACKET, inPacket); } if (contestSecurityException != null){ prop.put(EXCEPTION, contestSecurityException); } - + Packet packet = new Packet(Type.SECURITY_MESSAGE, source, destination, prop); return packet; } @@ -2086,9 +2117,9 @@ public static Packet createResetAllSitesPacket(ClientId source, ClientId destina prop.put(DELETE_LANGUAGE_DEFINITIONS, new Boolean(eraseLanguages)); prop.put(PROFILE, newProfile); return createPacket(PacketType.Type.RESET_ALL_CONTESTS, source, destination, prop); - + } - + public static Packet createCloneProfilePacket(ClientId source, ClientId destination, Profile profile2, ProfileCloneSettings settings, boolean switchNow) { Properties prop = new Properties(); prop.put(CLIENT_ID, source); @@ -2106,24 +2137,24 @@ public static Packet createSwitchProfilePacket(ClientId source, ClientId destina prop.put(CONTEST_PASSWORD, contestPassword); return createPacket(PacketType.Type.SWITCH_PROFILE, source, destination, prop); } - + // TODO fold contestTime and ContestInformation into ContestLoginSuccessData public static Packet createUpdateProfileClientPacket(ClientId source, ClientId destination, Profile currentProfile, Profile switchToProfile, ContestLoginSuccessData data) { try { - + Properties prop = new Properties(); - + prop.put(PROFILE, currentProfile); prop.put(NEW_PROFILE, switchToProfile); - + prop.put(CLIENT_ID, destination); - prop.put(PROFILE_LIST, data.getProfiles()); + prop.put(PROFILE_LIST, data.getProfiles()); if (data.getContestSecurityPassword() != null) { prop.put(CONTEST_PASSWORD, data.getContestSecurityPassword()); } - + addContestData(prop, data); TimeZone timeZone = TimeZone.getTimeZone("GMT"); @@ -2136,7 +2167,7 @@ public static Packet createUpdateProfileClientPacket(ClientId source, ClientId d Packet packet = new Packet(Type.UPDATE_CLIENT_PROFILE, source, destination, prop); return packet; - + } catch (Exception e) { System.err.println("Exception creating UPDATE_CLIENT_PROFILE"); e.printStackTrace(System.err); @@ -2152,7 +2183,7 @@ public static Packet createFetchRunFilesPacket(ClientId source, ClientId destina Packet packet = new Packet(Type.FETCH_RUN_FILES, source, destination, prop); return packet; } - + public static Packet createRequestRemoteDataPacket(ClientId source, ClientId destination) { Properties prop = new Properties(); prop.put(CLIENT_ID, source); @@ -2167,7 +2198,7 @@ public static Packet createRunFilesPacket(ClientId source, ClientId destination, Packet packet = new Packet(Type.UPDATE_RUN_FILES, source, destination, prop); return packet; } - + public static Packet createRequestServerStatusPacket(ClientId source, ClientId destination, Profile currentProfile) { Properties prop = new Properties(); prop.put(CLIENT_ID, source); @@ -2240,7 +2271,7 @@ public static Packet createStartPlayback(ClientId source, ClientId destination, Packet packet = new Packet(Type.START_PLAYBACK, source, destination, prop); return packet; } - + public static Packet createUpdateSetting(ClientId source, ClientId destination, PlaybackInfo playbackInfo) { Properties prop = new Properties(); prop.put(CLIENT_ID, source); @@ -2296,10 +2327,10 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, Packet packet = new Packet(Type.UPDATE_SETTING, source, destination, prop); return packet; } - + /** * List of team source files. - * + * *

    * This is a response/reply to a {@link #createRunSourceFetchRequest(ClientId, ClientId, Run[])}. */ @@ -2310,7 +2341,7 @@ public static Packet createUpdateSetting(ClientId source, ClientId destination, Packet packet = new Packet(Type.UPDATE_SETTING, source, destination, prop); return packet; } - + /** * Request a list of team source files. */ @@ -2321,5 +2352,5 @@ public static Packet createRunSourceFetchRequest(ClientId source, ClientId desti Packet packet = new Packet(Type.REQUEST_FETCH_TEAMS_SUBMISSION_FILES, source, destination, prop); return packet; } - + } diff --git a/src/edu/csus/ecs/pc2/list/ListUtilities.java b/src/edu/csus/ecs/pc2/list/ListUtilities.java index faa5d5026..ab3e1128e 100644 --- a/src/edu/csus/ecs/pc2/list/ListUtilities.java +++ b/src/edu/csus/ecs/pc2/list/ListUtilities.java @@ -31,13 +31,19 @@ public class ListUtilities { public static List filterByJudgingTypes(List files, List submissionSolutionList) { List newFileList = new ArrayList(); + int idx; for (File file : files) { - submissionSolutionList.forEach((subSol) -> { - if (file.getAbsolutePath().contains(File.separator + subSol + File.separator)) { + String filePath = file.getAbsolutePath(); + for(String subSol : submissionSolutionList) { + idx = subSol.indexOf(':'); + if(idx > 0) { + subSol = subSol.substring(0, idx).trim(); + } + if (filePath.contains(File.separator + subSol + File.separator)) { newFileList.add(file); } - }); + } } return newFileList; diff --git a/src/edu/csus/ecs/pc2/ui/SampleResultsTableModel.java b/src/edu/csus/ecs/pc2/ui/SampleResultsTableModel.java index e8a17deef..78e1a7405 100644 --- a/src/edu/csus/ecs/pc2/ui/SampleResultsTableModel.java +++ b/src/edu/csus/ecs/pc2/ui/SampleResultsTableModel.java @@ -9,6 +9,7 @@ import edu.csus.ecs.pc2.core.Utilities; import edu.csus.ecs.pc2.core.model.ElementId; import edu.csus.ecs.pc2.core.model.IInternalContest; +import edu.csus.ecs.pc2.core.model.Judgement; import edu.csus.ecs.pc2.core.model.Problem; import edu.csus.ecs.pc2.core.model.Run; import edu.csus.ecs.pc2.core.model.RunTestCase; @@ -75,7 +76,14 @@ public SampleResultsTableModel(IInternalContest contest, RunTestCase[] testCaseR if (passed) { resultString = "Pass"; } else { + ElementId judgmentId = testCaseResults[row].getJudgementId(); resultString = "Fail"; + if(judgmentId != null) { + Judgement judgment = contest.getJudgement(judgmentId); + if(judgment != null) { + resultString = String.format("Fail - %s : %s", judgment.getDisplayName(), judgment.getAcronym()); + } + } } } JLabel resultLabel = new JLabel(resultString); diff --git a/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java b/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java index 302a66233..bc64c763b 100644 --- a/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java +++ b/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java @@ -22,6 +22,7 @@ import java.util.logging.Level; import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; @@ -116,6 +117,8 @@ public class SubmitSampleRunsPane extends JPanePlugin { private JPanel messagePanel = null; private JLabel rowCountLabel = null; + private JCheckBox overrideStopOnError = null; + /** * User filter */ @@ -272,6 +275,11 @@ public void actionPerformed(ActionEvent e) { } }); + overrideStopOnError = new JCheckBox("Stop on first failure"); + overrideStopOnError.setSelected(false); + overrideStopOnError.setToolTipText("Use this checkbox to override the problem defined behaviour of judging when a testcase fails."); + bottomPane.add(overrideStopOnError); + resetButton.setToolTipText("Reset back to default settings"); bottomPane.add(resetButton); submitRunButton.setToolTipText("Submit selected sample runs"); @@ -521,7 +529,7 @@ public void run() { submissionWaitTimer = new Timer("Submission Wait Timer " + currentSubmission); submissionWaitTimer.schedule(submissionTimerTask, SUBMISSION_WAIT_TIMEOUT_MS); - SubmissionSample sub = submitter.sendSubmission(file); + SubmissionSample sub = submitter.sendSubmission(file, !overrideStopOnError.isSelected()); if(sub != null) { submissionList.add(sub); updateRunRow(sub, getContest().getClientId(), true); diff --git a/src/edu/csus/ecs/pc2/ui/cellRenderer/TestCaseResultCellRenderer.java b/src/edu/csus/ecs/pc2/ui/cellRenderer/TestCaseResultCellRenderer.java index 0877eba02..d1e422928 100644 --- a/src/edu/csus/ecs/pc2/ui/cellRenderer/TestCaseResultCellRenderer.java +++ b/src/edu/csus/ecs/pc2/ui/cellRenderer/TestCaseResultCellRenderer.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.ui.cellRenderer; import java.awt.Color; @@ -8,31 +8,32 @@ import javax.swing.SwingConstants; import javax.swing.border.EmptyBorder; import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; /** * A {@link TableCellRenderer} that renders cells showing the result of executing a submission against a single "test case". * Test cases that passed (correctly solved the problem) are rendering with a green background containing the word "Pass"; - * test cases that failed to solve the problem (or during whose execution there was an issue of some kind) are rendered - * with a red background containing the word "Fail". + * test cases that failed to solve the problem (or during whose execution there was an issue of some kind) are rendered + * with a red background containing the word "Fail". * Test cases for which there was no validator assigned to the problem are rendered with a yellow background containing the * label "No Validator"; test cases which were never executed (e.g. due to "stop on first failure" being set) are rendered * with a yellow background containing the label "Not Executed". - * + * * The {@link #setValue(Object)} method (which is what clients use to put a value in * the cell being rendered) checks the type of the Object it receives, and renders the cell * as follows: *

    * If the Object is a Boolean, the cell is rendered Pass/Fail (green/red) based on the value of the Boolean (true==pass, false==fail). *

    - * If the received Object is a String containing either "pass", "fail", "no validator", or "not executed" then the cell is + * If the received Object is a String containing either "pass", "fail", "no validator", or "not executed" then the cell is * rendered based on the text of the string as described above. The check for the value of the String is not case-sensitive. *

    * If the received Object is a JLabel, the String text in the JLabel is fetched and then the cell is rendered in the same way - * as for Strings, above. + * as for Strings, above. * - * If the value passed to the {@link #setValue(Object)} method is anything not covered of the above-listed steps then + * If the value passed to the {@link #setValue(Object)} method is anything not covered of the above-listed steps then * the cell is rendered with a yellow background containing question marks. - * + * * @author pc2@ecs.csus.edu * */ @@ -40,8 +41,9 @@ public class TestCaseResultCellRenderer extends DefaultTableCellRenderer { private static final long serialVersionUID = 2L; + @Override public void setValue(Object value) { - + // default values setBackground(Color.yellow); setText("???"); @@ -53,13 +55,13 @@ public void setValue(Object value) { if (passed) { setPass(); } else { - setFail(); + setFail(null); } - + } else if (value instanceof String) { String text = (String)value; updateCellText(text); - + } else if (value instanceof JLabel) { String text = ((JLabel)value).getText(); updateCellText(text); @@ -69,12 +71,14 @@ public void setValue(Object value) { setBorder(new EmptyBorder(0, 0, 0, 0)); } - + private void updateCellText (String text) { if (text.equalsIgnoreCase("pass")) { setPass(); } else if (text.equalsIgnoreCase("fail")) { - setFail(); + setFail(null); + } else if (text.substring(0, 4).equalsIgnoreCase("fail")) { + setFail(text); } else if (text.equalsIgnoreCase("no validator")) { setNoValidator(); } else if (text.equalsIgnoreCase("not executed")) { @@ -83,40 +87,43 @@ private void updateCellText (String text) { setJudgingResult(); } } - + private void setPass() { setBackground(Color.green); setForeground(Color.black); setFont(new Font(getFont().getName(),Font.PLAIN, 12)); setText("Pass"); } - - private void setFail() { + + private void setFail(String text) { setBackground(Color.red); setForeground(Color.white); setFont(new Font(getFont().getName(),Font.ITALIC+Font.BOLD, 12)); - setText("Fail"); + if(text == null) { + text = "Fail"; + } + setText(text); } private void setNoValidator() { setBackground(Color.yellow); setForeground(Color.black); setFont(new Font(getFont().getName(),Font.PLAIN, 12)); - setText(""); + setText(""); } - + private void setNotExecuted() { setBackground(Color.yellow); setForeground(Color.black); setFont(new Font(getFont().getName(),Font.ITALIC, 12)); - setText("(Not Executed)"); + setText("(Not Executed)"); } - + private void setJudgingResult() { setBackground(Color.cyan); setForeground(Color.black); setFont(new Font(getFont().getName(),Font.ITALIC, 12)); - setText("(Judging)"); + setText("(Judging)"); } } diff --git a/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java b/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java index d3f1b5b91..196ecfe97 100644 --- a/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java +++ b/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java @@ -134,6 +134,22 @@ public List sendSubmissions(List filesToSubmit) { * @return the SubmissionSample if it was submitted, null otherwise */ public SubmissionSample sendSubmission(File file) { + return(sendSubmission(file, false)); + } + + /** + * submit a single run + * + * Will guess langauge and problem based on path + * + * @see #guessLanguage(IInternalContest, String) + * @see #guessProblem(IInternalContest, String) + * + * @param File object to submit + * @param Boolean overrideStopOnFailure - to override iff a problem has stop on failiure set. + * @return the SubmissionSample if it was submitted, null otherwise + */ + public SubmissionSample sendSubmission(File file, boolean overrideStopOnFailure) { SubmissionSample subResult = null; String filePath = file.getAbsolutePath(); @@ -146,7 +162,7 @@ public SubmissionSample sendSubmission(File file) { } else { Problem problem = guessProblem(getContest(), filePath); try { - controller.submitJudgeRun(problem, language, filePath, null); + controller.submitJudgeRun(problem, language, filePath, null, overrideStopOnFailure); log.log(Level.INFO, "submitted run with language " + language + " and problem " + problem + " source: " + filePath); subResult = new SubmissionSample(problem.getShortName(), problem.getElementId(), language.getDisplayName(), language.getElementId(), guessSubmissionType(file.getParent()), file); From a7ef93787d0080656dbc9fbd1d051aab0f38b027 Mon Sep 17 00:00:00 2001 From: John Buck Date: Thu, 20 Jun 2024 15:20:35 -0400 Subject: [PATCH 06/10] i_232 Should not include config files in a PR Inadvertently added , removed now. --- reject.ini | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 reject.ini diff --git a/reject.ini b/reject.ini deleted file mode 100644 index 1327f11e9..000000000 --- a/reject.ini +++ /dev/null @@ -1,21 +0,0 @@ -# -# Purpose: reject.ini judgements for GNY Regional 2023 Fall -# -# with CLICS Validator judgements at bottom -# -Yes|AC -yes|ac -correct|AC -compiler error|CE -run error|RTE -timelimit|TLE -wrong answer|WA -memory limit|MLE -no output|NO -output limit|OLE -Wrong Answer|WA -No - Wrong answer|WA -Incomplete output|WA -incomplete output|WA -incorrect output format|WA -Undetermined|WA From 43bd9feac19752d518b307ab5fb1096ac88705cf Mon Sep 17 00:00:00 2001 From: John Buck Date: Thu, 20 Jun 2024 15:36:45 -0400 Subject: [PATCH 07/10] i_232 Updated comments/copyrights --- .../ecs/pc2/core/packet/PacketFactory.java | 2 +- .../csus/ecs/pc2/list/SubmissionSample.java | 6 + src/edu/csus/ecs/pc2/ui/EditFilterFrame.java | 2 +- src/edu/csus/ecs/pc2/ui/FrameUtilities.java | 128 +++++++++--------- .../csus/ecs/pc2/ui/ISelectedListsSetter.java | 8 +- src/edu/csus/ecs/pc2/ui/JListFrame.java | 22 +-- src/edu/csus/ecs/pc2/ui/JListPane.java | 26 ++-- .../ecs/pc2/ui/admin/AdministratorView.java | 2 +- .../csus/ecs/pc2/ui/server/ServerView.java | 6 +- .../csus/ecs/pc2/ui/team/QuickSubmitter.java | 2 +- 10 files changed, 105 insertions(+), 99 deletions(-) diff --git a/src/edu/csus/ecs/pc2/core/packet/PacketFactory.java b/src/edu/csus/ecs/pc2/core/packet/PacketFactory.java index f1e38ecdb..f6fd31700 100644 --- a/src/edu/csus/ecs/pc2/core/packet/PacketFactory.java +++ b/src/edu/csus/ecs/pc2/core/packet/PacketFactory.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2019 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.core.packet; import java.io.PrintStream; diff --git a/src/edu/csus/ecs/pc2/list/SubmissionSample.java b/src/edu/csus/ecs/pc2/list/SubmissionSample.java index 5234d2d68..77cd40f02 100644 --- a/src/edu/csus/ecs/pc2/list/SubmissionSample.java +++ b/src/edu/csus/ecs/pc2/list/SubmissionSample.java @@ -1,5 +1,11 @@ +// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.list; +/** + * A judge's submission sample + * + * @author John Buck, PC^2 Team, pc2@ecs.csus.edu + */ import java.io.File; import edu.csus.ecs.pc2.core.model.ElementId; diff --git a/src/edu/csus/ecs/pc2/ui/EditFilterFrame.java b/src/edu/csus/ecs/pc2/ui/EditFilterFrame.java index 8952d79c4..c42259267 100644 --- a/src/edu/csus/ecs/pc2/ui/EditFilterFrame.java +++ b/src/edu/csus/ecs/pc2/ui/EditFilterFrame.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2019 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.ui; import java.awt.BorderLayout; diff --git a/src/edu/csus/ecs/pc2/ui/FrameUtilities.java b/src/edu/csus/ecs/pc2/ui/FrameUtilities.java index b4dca55f3..3861f6d5a 100644 --- a/src/edu/csus/ecs/pc2/ui/FrameUtilities.java +++ b/src/edu/csus/ecs/pc2/ui/FrameUtilities.java @@ -1,18 +1,17 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.ui; +import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Frame; -import java.awt.Rectangle; -import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; +import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; - import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; @@ -25,15 +24,15 @@ import java.util.ArrayList; import java.util.List; +import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JDialog; import javax.swing.JFrame; +import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.UIManager; -import javax.swing.Icon; -import javax.swing.JLabel; import javax.swing.border.EmptyBorder; import edu.csus.ecs.pc2.VersionInfo; @@ -47,14 +46,14 @@ /** * Methods to center frame, change cursor, etc.
    * Contains method to change look and feel, set cursor state, center windows and a yes no dialog with cancel as default. - * + * * @author pc2@ecs.csus * @version $Id$ */ // $HeadURL$ public final class FrameUtilities { - + public static final String PC2_LOGO_FILENAME = "PC2Logo.png"; public static final String ICPC_BANNER_FILENAME = "ICPCWebMast_small.png"; public static final String CSUS_LOGO_FILENAME = "csus_logo.png"; @@ -62,7 +61,7 @@ public final class FrameUtilities { /** - * + * * @author pc2@ecs.csus.edu * @version $Id$ */ @@ -71,7 +70,7 @@ public enum HorizontalPosition { }; /** - * + * * @author pc2@ecs.csus.edu * @version $Id$ */ @@ -86,7 +85,7 @@ private FrameUtilities() { /** * Set Native Look and Feel. - * + * */ public static void setNativeLookAndFeel() { try { @@ -98,7 +97,7 @@ public static void setNativeLookAndFeel() { /** * Set Java Look and Feel. - * + * */ public static void setJavaLookAndFeel() { try { @@ -110,7 +109,7 @@ public static void setJavaLookAndFeel() { /** * Center this frame/component on the screen. - * + * * @param component */ public static void centerFrame(Component component) { @@ -120,7 +119,7 @@ public static void centerFrame(Component component) { /** * Center frame/component at top of screen. - * + * * @param component */ public static void centerFrameTop(Component component) { @@ -129,10 +128,10 @@ public static void centerFrameTop(Component component) { } /** - * + * * Center frame/component over a parentFrame. If parentFrame is null * centers across screen. If the parent is smaller, match the x and/or y. - * + * * @param parentFrame * @param component */ @@ -159,7 +158,7 @@ public static void centerFrameOver(Component parentFrame, Component component) { } /** * Center frame at top of screen. - * + * * @param component */ public static void setFrameWindowWidth(Component component) { @@ -169,7 +168,7 @@ public static void setFrameWindowWidth(Component component) { /** * Display mouse Busy or Wait cusor (usually hourglass) - * + * * @param component */ public static void waitCursor(Component component) { @@ -178,7 +177,7 @@ public static void waitCursor(Component component) { /** * Display mouse Default cursor (usually pointer) - * + * * @param component */ public static void regularCursor(Component component) { @@ -187,7 +186,7 @@ public static void regularCursor(Component component) { /** * Puts this frame/component to right of input frame. - * + * * @param sourceComponent * component relative to otherComponent * @param otherComponent @@ -200,9 +199,9 @@ public static void windowToRight(Component sourceComponent, Component otherCompo /** * Yes No Cancel dialog, default selection is Cancel. - * + * * Unlike showConfirmDialog, this dialog defaults to Cancel. - * + * * @see JOptionPane#showConfirmDialog(java.awt.Component, java.lang.Object, java.lang.String, int, int, javax.swing.Icon) * @param title * @param message @@ -241,7 +240,7 @@ public static void setFramePosition(Component component, HorizontalPosition hori int newX = component.getX(); int newY = component.getY(); - + if (verticalPosition == VerticalPosition.TOP){ newY = 20; } else if (verticalPosition == VerticalPosition.BOTTOM){ @@ -266,6 +265,7 @@ public static void showMessage(JFrame parentFrame, String strTitle, String displ final JOptionPane optionPane = new JOptionPane(displayString, JOptionPane.INFORMATION_MESSAGE); dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); optionPane.addPropertyChangeListener(new PropertyChangeListener() { + @Override public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); @@ -282,16 +282,16 @@ public void propertyChange(PropertyChangeEvent e) { centerFrameOver(parentFrame, dialog); dialog.setVisible(true); } - + /** * Set a PC^2 Frame title. - * + * * Form: * PC^2 moduleName [clockstate] ver#-build# *
    * Example: PC^2 Server (Site 1) [STOPPED] 9.1.4-1908
    * PC^2 TEAM 1 (Site 1) [STARTED] 9.1.4-1908
    - * + * * @param frame * @param moduleName * @param versionInfo @@ -314,17 +314,17 @@ public static void setFrameTitle(Frame frame, String moduleName, boolean clockSt /** * Show message to user. * @param component - * @param title + * @param title * @param message */ public static void showMessage(Component component, String title, String message) { JOptionPane.showMessageDialog(component, message, title, JOptionPane.INFORMATION_MESSAGE); } - - + + /** * Creates a frame with the input plugin. - * + * * @param plugin * @param contest * @param controller @@ -336,7 +336,7 @@ public static JFramePlugin createPluginFrame(JPanePlugin plugin, IInternalContes frame.setContestAndController(contest, controller); return frame; } - + public static void viewFile(String filename, String title, Log log) { MultipleFileViewer multipleFileViewer = new MultipleFileViewer(log); multipleFileViewer.addFilePane(title, filename); @@ -344,7 +344,7 @@ public static void viewFile(String filename, String title, Log log) { FrameUtilities.centerFrameFullScreenHeight(multipleFileViewer); multipleFileViewer.setVisible(true); } - + public static void updateRowHeights(JTable table) { try { for (int row = 0; row < table.getRowCount(); row++) { @@ -362,15 +362,15 @@ public static void updateRowHeights(JTable table) { System.out.println("Ignore "+e.getMessage()); } } - + /** * This method returns an {@link ImageIcon} for the image contained in the file whose name is specified. * It first attempts to find the file as a resource in the current jars; if not found there it falls back to looking * for the file in the file system. * If the file is found (in either place) then its checksum is verified before returning a result. - * + * * @param the name of the image file to be loaded - * + * * @return an ImageIcon for the image file, or null if the file cannot be found or if it fails checksum verification */ public static ImageIcon loadAndVerifyImageFile(String inFileName) { @@ -410,29 +410,29 @@ public static ImageIcon loadAndVerifyImageFile(String inFileName) { /** * This method verifies that the file whose filename and corresponding URL are provided are legitimate -- - * that is, that the files have the expected SHA checksum values. It first reads the file from the + * that is, that the files have the expected SHA checksum values. It first reads the file from the * specified URL, then uses the {@link MessageDigest} class to compute an SHA checksum for that file. * It then uses the given String filename to select the "correct" checksum for the file, * returning true if the checksums match, false otherwise. - * + * * @param inFileName the name of the file to be verified * @param url a URL pointing to an ImageIcon for the file - * + * * @return true if the SHA checksum for the image at the URL matches the expected checksum; false if not */ private static boolean verifyImage(String inFileName, URL url) { - + // these are the real (correct) checksums for the specified files: - + //csus_logo.png (SHA1 = 3E1762112204E9032C45D57D14BB299F9D9ECD42) byte[] csuslogoChecksum = {62, 23, 98, 17, 34, 4, -23, 3, 44, 69, -43, 125, 20, -69, 41, -97, -99, -98, -51, 66}; - + //PC2Logo.png: (SHA1 = C0D5C36C310EC7092A74A651311FC9D7B987A27D) byte[] pc2logoChecksum = {-64, -43, -61, 108, 49, 14, -57, 9, 42, 116, -90, 81, 49, 31, -55, -41, -71, -121, -94, 125}; - + //ICPCWebMast_small.png (SHA1 = D5047FE7093E1DB3281F53A83BC02B743A9DA7A4 byte[] icpcbannerChecksum = {-43, 4, 127, -25, 9, 62, 29, -77, 40, 31, 83, -88, 59, -64, 43, 116, 58, -99, -89, -92}; - + //icpc_logo.png (SHA1 = 1BFEE495B8862445370FF2CB82884FD286D63C4B) byte[] icpclogoChecksum = {27, -2, -28, -107, -72, -122, 36, 69, 55, 15, -14, -53, -126, -120, 79, -46, -122, -42, 60, 75}; @@ -441,13 +441,13 @@ private static boolean verifyImage(String inFileName, URL url) { InputStream is = url.openStream(); MessageDigest md = MessageDigest.getInstance("SHA"); md.reset(); - + // //old code: // byte[] b = new byte[1024]; // while(is.read(b) > 0) { // md.update(b); <--this produces unpredictable results depending on timing of the read; this is why the old version needed multiple "SHA checksums" // } - + //new code 27March2020 (from Tim deBoer): byte[] b = new byte[1024]; int n = is.read(b); @@ -455,13 +455,13 @@ private static boolean verifyImage(String inFileName, URL url) { md.update(b, 0, n); //<--this version updates the digest with exactly (and ONLY) the NEW bytes read... (thanks Tim) n = is.read(b); } - + byte[] digested = md.digest(); //"digested" now holds the image checksum - + //find the appropriate "correctChecksum" for the current image file byte[] correctChecksum = { -1 }; //default to a nonsensical value (must have at least one byte to avoid index-out-of-range, below) - + if (inFileName.equals("images/" + CSUS_LOGO_FILENAME)) { correctChecksum = csuslogoChecksum; } else if (inFileName.equalsIgnoreCase("images/" + PC2_LOGO_FILENAME)) { @@ -471,17 +471,17 @@ private static boolean verifyImage(String inFileName, URL url) { } else if (inFileName.equals("images/" + ICPC_LOGO_FILENAME)) { correctChecksum = icpclogoChecksum; } else { - //if we get here, the file we were given doesn't match any of the expected/known files we want to check; + //if we get here, the file we were given doesn't match any of the expected/known files we want to check; // use the (nonsensical) default (above) which should cause the checksum verification (below) to fail StaticLog.warning("FrameUtilities.verifyImage(): unrecognized image file name: '" + inFileName +"'"); } - + //if in debug mode, print out the calculated checksum values for the specified image if (edu.csus.ecs.pc2.core.Utilities.isDebugMode()) { System.out.println (); System.out.println (inFileName); System.out.print ("byte[] ChecksumX = {"); - + for (int i = 0; i < digested.length; i++) { System.out.print(digested[i]); if (i < digested.length -1) { @@ -490,7 +490,7 @@ private static boolean verifyImage(String inFileName, URL url) { } System.out.println("};"); } - + //count the number of byte in the calculated checksum which match the expected checksum int matchedBytes = 0; for (int i = 0; i < digested.length; i++) { @@ -500,28 +500,28 @@ private static boolean verifyImage(String inFileName, URL url) { break; } } - + return(matchedBytes == correctChecksum.length); - + } catch (IOException e) { StaticLog.log("verifyImage("+inFileName+")", e); } catch (NoSuchAlgorithmException e) { StaticLog.log("verifyImage("+inFileName+")", e); } - + return false; } - + public static String getExceptionMessageAndStackTrace(Exception ex, String delimiter) { StringBuffer buff = new StringBuffer(); - + if (ex != null) { buff.append("Message: " + ex.getMessage()); buff.append(Constants.NL); buff.append("Class: " + ex.getClass().getName()); buff.append(Constants.NL); - + List stackTraceLines = fetchStackTraceElements(ex, "csus"); for (String string : stackTraceLines) { buff.append(string); @@ -555,8 +555,9 @@ public static List fetchStackTraceElements(Throwable e, String pattern) } public static void showExceptionMessage(Component component, final String message, Exception ex) { - + SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { JOptionPane.showMessageDialog(null, message + Constants.NL + getExceptionMessageAndStackTrace(ex, Constants.NL)); } @@ -565,6 +566,7 @@ public void run() { public static void showExceptionMessage(Component component, final String title, String message, Exception ex) { SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { JOptionPane.showMessageDialog(component, message, title, JOptionPane.ERROR_MESSAGE); } @@ -583,7 +585,7 @@ private static Image getScaledImage(Image srcImg, int w, int h) { /** * create a label with question mark and on click shows a message dialog. - * + * * @param messageTitle dialog title * @param messageLines dialog message lines * @return @return a What's this? label. @@ -595,7 +597,7 @@ public static JLabel getWhatsThisLabel(String messageTitle, String[] messageLine /** * create a label with question mark and on click shows a message dialog. - * + * * @param messageTitle dialog title * @param message dialog message * @return a What's this JLabel @@ -608,7 +610,7 @@ public static JLabel getWhatsThisLabel(String messageTitle, String message) { /** * create a label with question mark and on click shows a message dialog. - * + * * @param buttonName * @param toolTip * @param messageTitle @@ -621,7 +623,7 @@ public static JLabel getToolTipLabel(String buttonName, String toolTip, String m /** * create a label with question mark and on click shows a message dialog. - * + * * @param buttonName name for button * @param toolTip tooltip for button * @param messageTitle diff --git a/src/edu/csus/ecs/pc2/ui/ISelectedListsSetter.java b/src/edu/csus/ecs/pc2/ui/ISelectedListsSetter.java index 42b720f00..4e38167d3 100644 --- a/src/edu/csus/ecs/pc2/ui/ISelectedListsSetter.java +++ b/src/edu/csus/ecs/pc2/ui/ISelectedListsSetter.java @@ -1,19 +1,19 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.ui; import java.util.List; /** * Interface for callbacks/observers. - * + * * @author Douglas A. Lane * */ public interface ISelectedListsSetter { /** - * Provide observers a list of selected values. - * + * Provide observers a list of selected values. + * * @param selectedValuesList list of selected values * @param selectedIndices list of selected indexes */ diff --git a/src/edu/csus/ecs/pc2/ui/JListFrame.java b/src/edu/csus/ecs/pc2/ui/JListFrame.java index 9ada2d03a..f2e3555a6 100644 --- a/src/edu/csus/ecs/pc2/ui/JListFrame.java +++ b/src/edu/csus/ecs/pc2/ui/JListFrame.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.ui; import java.awt.BorderLayout; @@ -11,16 +11,16 @@ /** * Generic List frame. - * + * * @see JListPane - * - * + * + * * @author Douglas A. Lane */ public class JListFrame extends JFrame { /** - * - * + * + * */ private static final long serialVersionUID = -5073426131461967909L; @@ -32,20 +32,20 @@ public JListFrame(String title, Object [] items, int[] selecteditems, ISelectedL setName("JListFrame"); setTitle(title); setPreferredSize(new Dimension(400, 400)); - + listPane = new JListPane(this, items, selecteditems, selectedListsSetter); getContentPane().add(listPane, BorderLayout.CENTER); FrameUtilities.centerFrame(this); } - + /** * Used for unit testing. - * + * * @param args */ public static void main(String[] args) { - - + + Object[] items2 = { "One", "Two", "Three", "Four" }; JListFrame f = new JListFrame("hi", items2, new int[0], new ISelectedListsSetter() { diff --git a/src/edu/csus/ecs/pc2/ui/JListPane.java b/src/edu/csus/ecs/pc2/ui/JListPane.java index 569b82be8..62ae7a08c 100644 --- a/src/edu/csus/ecs/pc2/ui/JListPane.java +++ b/src/edu/csus/ecs/pc2/ui/JListPane.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.ui; import java.awt.BorderLayout; @@ -17,22 +17,22 @@ * A Pane that presents the user with a list of items and provides a way to identify * which list items are selected. On Update will return the selected items via * the callback ISelectedListsSetter. - * + * * Provides a way to show the user a list of items to select, then * use ISelectedListsSetter to return the selected values to the calling method. - * + * * As input takes a list of items and corresponding (if any) indexes of selected items. - * + * * When a user selects items and clicks Update will call the ISelectedListsSetter with * the item list and (new) list of selected indexes within that list. - * + * * @author Douglas A. Lane * */ // TODO NOW 232 fix bug where says there is a change, when not selection change has been made. public class JListPane extends JPanePlugin { /** - * + * */ private static final long serialVersionUID = -1383088589409036086L; @@ -60,7 +60,8 @@ public JListPane() { JButton saveButton = new JButton("Save"); saveButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + @Override + public void actionPerformed(ActionEvent e) { saveAndClose(); } }); @@ -68,7 +69,8 @@ public void actionPerformed(ActionEvent e) { JButton cancelButton = new JButton("Cancel"); cancelButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + @Override + public void actionPerformed(ActionEvent e) { closeTheWindow(); } }); @@ -77,8 +79,8 @@ public void actionPerformed(ActionEvent e) { /** * Create a pane that has a list of objects. - * - * + * + * * @param parentFrame parent frame for JPanel, used to close parent frame * @param items list of items to display, must be at least one * item @@ -89,7 +91,7 @@ public void actionPerformed(ActionEvent e) { @SuppressWarnings("unchecked") public JListPane(JFrame parentFrame, Object [] items, int[] selectedItemsIndexes, ISelectedListsSetter selectedListsSetter) { this(); - + if (selectedListsSetter == null) { throw new IllegalArgumentException("selectedListsSetter is null"); } @@ -145,7 +147,7 @@ private boolean isChanged() { protected void saveAndClose() { selectedListsSetter.setSelectedValuesList(theList.getSelectedValuesList(), theList.getSelectedIndices()); - + if (parentFrame != null) { parentFrame.setVisible(false); parentFrame.dispose(); diff --git a/src/edu/csus/ecs/pc2/ui/admin/AdministratorView.java b/src/edu/csus/ecs/pc2/ui/admin/AdministratorView.java index e287f62ec..b5865b047 100644 --- a/src/edu/csus/ecs/pc2/ui/admin/AdministratorView.java +++ b/src/edu/csus/ecs/pc2/ui/admin/AdministratorView.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.ui.admin; import java.awt.BorderLayout; diff --git a/src/edu/csus/ecs/pc2/ui/server/ServerView.java b/src/edu/csus/ecs/pc2/ui/server/ServerView.java index 11fec4fb5..a9299fe90 100644 --- a/src/edu/csus/ecs/pc2/ui/server/ServerView.java +++ b/src/edu/csus/ecs/pc2/ui/server/ServerView.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2019 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.ui.server; import java.awt.BorderLayout; @@ -59,7 +59,6 @@ import edu.csus.ecs.pc2.ui.ProfilesPane; import edu.csus.ecs.pc2.ui.ReportPane; import edu.csus.ecs.pc2.ui.SitesPane; -import edu.csus.ecs.pc2.ui.SubmitSampleRunsPane; import edu.csus.ecs.pc2.ui.UIPlugin; /** @@ -557,9 +556,6 @@ public void setContestAndController(IInternalContest inContest, IInternalControl if (Utilities.isDebugMode()) { try { - SubmitSampleRunsPane submitSampleRunsPane = new SubmitSampleRunsPane(); - addUIPlugin(getMainTabbedPane(), "Submit Judges", submitSampleRunsPane); - PacketMonitorPane packetMonitorPane = new PacketMonitorPane(); addUIPlugin(getMainTabbedPane(), "Packets", packetMonitorPane); diff --git a/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java b/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java index 196ecfe97..8df1ef637 100644 --- a/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java +++ b/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java @@ -1,4 +1,4 @@ -// Copyright (C) 1989-2023 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. +// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau. package edu.csus.ecs.pc2.ui.team; import java.io.File; From cce5b9fd8789a68f3924b2138ead9104bcf442a7 Mon Sep 17 00:00:00 2001 From: John Buck Date: Thu, 20 Jun 2024 16:33:16 -0400 Subject: [PATCH 08/10] i_232 Fix missing abstract methods Added new methods to NullController and MockController from IInternalController. --- src/edu/csus/ecs/pc2/core/MockController.java | 172 +++++++++++++++--- src/edu/csus/ecs/pc2/core/NullController.java | 148 +++++++++++++-- 2 files changed, 288 insertions(+), 32 deletions(-) diff --git a/src/edu/csus/ecs/pc2/core/MockController.java b/src/edu/csus/ecs/pc2/core/MockController.java index 5662325a9..69017228e 100644 --- a/src/edu/csus/ecs/pc2/core/MockController.java +++ b/src/edu/csus/ecs/pc2/core/MockController.java @@ -41,290 +41,358 @@ /** * Mock Controller. - * + * * Some data is mock data some methods implement the controller/contest. - * + * */ public class MockController implements IInternalController { private IInternalContest contest; - + private PacketHandler handler = null; - + private Log log; + @Override public void addNewAccount(Account account) { contest.addAccount(account); } + @Override public void addNewAccounts(Account[] accounts) { contest.addAccounts(accounts); } + @Override public void addNewBalloonSettings(BalloonSettings newBalloonSettings) { } + @Override public void addNewCategory(Category newCategory) { } + @Override public void addNewClientSettings(ClientSettings newClientSettings) { contest.addClientSettings(newClientSettings); } + @Override public void addNewGroup(Group group) { contest.addGroup(group); } + @Override public void addNewJudgement(Judgement judgement) { contest.addJudgement(judgement); } + @Override public void addNewLanguage(Language language) { contest.addLanguage(language); } + @Override public void addNewProblem(Problem problem, ProblemDataFiles problemDataFiles) { contest.addProblem(problem, problemDataFiles); } + @Override public void addNewProblem(Problem[] problem, ProblemDataFiles[] problemDataFiles) { for (int i = 0; i < problemDataFiles.length; i++) { contest.addProblem(problem[i], problemDataFiles[i]); } } + @Override public void addNewSite(Site site) { contest.addSite(site); } + @Override public void addPacketListener(IPacketListener packetListener) { } + @Override public void addProblem(Problem problem) { contest.addProblem(problem); } + @Override public void autoRegister(String teamInformation) { } + @Override public void cancelClarification(Clarification clarification) { } + @Override public void cancelRun(Run run) { } + @Override public void checkOutClarification(Clarification clarification, boolean readOnly) { } + @Override public void checkOutRejudgeRun(Run theRun) { } + @Override public void checkOutRun(Run run, boolean readOnly, boolean computerJudge) { } + @Override public IInternalContest clientLogin(IInternalContest internalContest, String loginName, String password) throws Exception { return null; } + @Override public void cloneProfile(Profile profile, ProfileCloneSettings settings, boolean switchNow) { } + @Override public void fetchRun(Run run) throws IOException, ClassNotFoundException, FileSecurityException { } + @Override public void forceConnectionDrop(ConnectionHandlerID connectionHandlerID) { } + @Override public void generateNewAccounts(String clientTypeName, int count, int startNumber, boolean active) { } + @Override public void generateNewAccounts(String clientTypeName, int siteNumber, int count, int startNumber, boolean active) { } + @Override public String getHostContacted() { return null; } + @Override public Log getLog() { return log; } + @Override public UIPlugin[] getPluginList() { return null; } + @Override public int getPortContacted() { return 0; } + @Override public ProblemDataFiles getProblemDataFiles(Problem problem) { return null; } + @Override public int getSecurityLevel() { return 0; } + @Override public void incomingPacket(Packet packet) { } + @Override public void initializeServer(IInternalContest contest) throws IOException, ClassNotFoundException, FileSecurityException { - + setContest(contest); } + @Override public void initializeStorage(IStorage storage) { } + @Override public boolean isClientAutoShutdown() { return false; } + @Override public boolean isLogWindowVisible() { return false; } + @Override public boolean isUsingGUI() { return false; } + @Override public void login(String loginName, String password) { } + @Override public void logoffUser(ClientId clientId) { } + @Override public void logWarning(String string, Exception e) { } + @Override public void outgoingPacket(Packet packet) { } + @Override public void register(UIPlugin plugin) { } + @Override public void removeConnection(ConnectionHandlerID connectionHandlerID) { } + @Override public void removeJudgement(Judgement judgement) { } + @Override public void removeLogin(ClientId clientId) { } + @Override public void removePacketListener(IPacketListener packetListener) { } + @Override public void requestChangePassword(String oldPassword, String newPassword) { } + @Override public void resetContest(ClientId clientResettingContest, boolean eraseProblems, boolean eraseLanguages) { } + @Override public void sendCompilingMessage(Run run) { } + @Override public void sendExecutingMessage(Run run) { } + @Override public void sendRunToSubmissionInterface(Run run, RunFiles runFiles) { } + @Override public void sendSecurityMessage(String event, String message, ContestSecurityException contestSecurityException) { } + @Override public void sendServerLoginRequest(int inSiteNumber) throws Exception { } + @Override public void sendShutdownAllSites() { } + @Override public void sendShutdownSite(int siteNumber) { } + @Override public void sendToAdministrators(Packet packet) { } + @Override public void sendToClient(Packet packet) { } + @Override public void sendToJudges(Packet packet) { } + @Override public void sendToJudgesAndOthers(Packet packet, boolean sendToServers) { } + @Override public void sendToLocalServer(Packet packet) { } + @Override public void sendToRemoteServer(int siteNumber, Packet packet) { } + @Override public void sendToScoreboards(Packet packet) { } + @Override public void sendToServers(Packet packet) { } + @Override public void sendToSpectators(Packet packet) { } + @Override public void sendToTeams(Packet packet) { } + @Override public void sendValidatingMessage(Run run) { } + @Override public void setClientAutoShutdown(boolean clientAutoShutdown) { } + @Override public void setContest(IInternalContest newContest) { this.contest = newContest; log = new Log("log", getLogName(contest.getClientId())); @@ -335,93 +403,127 @@ private String getLogName(ClientId clientId) { return "mock." + stripChar(clientId.toString(), ' '); } + @Override public void setContestTime(ContestTime contestTime) { - + } + @Override public void setJudgementList(Judgement[] judgementList) { } + @Override public void setSecurityLevel(int securityLevel) { } + @Override public void setSiteNumber(int i) { } + @Override public void setUsingGUI(boolean usingGUI) { } + @Override public void showLogWindow(boolean showWindow) { } + @Override public void shutdownRemoteServers(ClientId requestor) { } + @Override public void shutdownServer(ClientId requestor) { } + @Override public void shutdownServer(ClientId requestor, int siteNumber) { } + @Override public void shutdownTransport() { } + @Override public void start(String[] stringArray) { } + @Override public void startAllContestTimes() { } + @Override public void startContest(int inSiteNumber) { } + @Override public ILogWindow startLogWindow(IInternalContest contest) { return null; } + @Override public void startMainUI(ClientId clientId) { } + @Override public void startPlayback(PlaybackInfo playbackInfo) { } + @Override public void stopAllContestTimes() { } + @Override public void stopContest(int inSiteNumber) { } + @Override public void submitClarification(Problem problem, String question) { } + @Override public void submitClarificationAnswer(Clarification clarification) { } + @Override public void submitJudgeRun(Problem problem, Language language, String filename, SerializedFile[] otherFiles) throws Exception { submitJudgeRun(problem, language, filename, otherFiles, 0, 0); } + @Override + public void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, boolean overrideStopOnFailure) throws Exception { + submitJudgeRun(problem, language, mainFileName, otherFiles, 0, 0, overrideStopOnFailure); + } + + @Override public void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] auxFileList, long overrideSubmissionTimeMS, long overrideRunId) throws Exception { - + submitJudgeRun(problem, language, mainFileName, auxFileList, overrideSubmissionTimeMS, overrideRunId, false); + } + + @Override + public void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, + long overrideSubmissionTimeMS, long overrideRunId, boolean overrideStopOnFailure) throws Exception { + Run submittedRun = new Run(contest.getClientId(), language, problem); + submittedRun.setOverrideStopOnFailure(overrideStopOnFailure); submittedRun.setOverRideElapsedTimeMS(overrideSubmissionTimeMS); submittedRun.setOverRideNumber(new Long(overrideRunId).intValue()); RunFiles runFiles = new RunFiles(submittedRun, mainFileName); @@ -433,120 +535,148 @@ public void submitJudgeRun(Problem problem, Language language, SerializedFile ma String mainFileName = mainFile.getName(); submitJudgeRun(problem, language, mainFileName, otherFiles, overrideSubmissionTimeMS, overrideRunId); } - + + @Override + public void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, SerializedFile[] otherFiles, + long overrideSubmissionTimeMS, long overrideRunId, boolean overrideStopOnFailure) throws Exception { + String mainFileName = mainFile.getName(); + submitJudgeRun(problem, language, mainFileName, otherFiles, overrideSubmissionTimeMS, overrideRunId, overrideStopOnFailure); + } + + @Override public void submitRunJudgement(Run run, JudgementRecord judgementRecord, RunResultFiles runResultFiles) { } + @Override public void switchProfile(Profile currentProfile, Profile switchToProfile, String contestPassword) { } + @Override public void syncProfileSubmissions(Profile profile) { } + @Override public void updateAccount(Account account) { } + @Override public void updateAccounts(Account[] account) { } + @Override public void updateBalloonSettings(BalloonSettings newBalloonSettings) { } + @Override public void updateCategories(Category[] categories) { } + @Override public void updateCategory(Category newCategory) { } + @Override public void updateClientSettings(ClientSettings clientSettings) { } + @Override public void updateContestController(IInternalContest inContest, IInternalController inController) { } + @Override public void updateContestInformation(ContestInformation contestInformation) { } + @Override public void updateContestTime(ContestTime newContestTime) { } + @Override public void updateFinalizeData(FinalizeData data) { } + @Override public void updateGroup(Group group) { } + @Override public void updateJudgement(Judgement newJudgement) { } + @Override public void updateLanguage(Language language) { } + @Override public void updateProblem(Problem problem) { } + @Override public void updateProblem(Problem problem, ProblemDataFiles problemDataFiles) { } + @Override public void updateProfile(Profile profile) { } + @Override public void updateRun(Run run, JudgementRecord judgementRecord, RunResultFiles runResultFiles) { } + @Override public void updateSite(Site newSite) { } @Override public void setConnectionManager(ITransportManager connectionManager) { - + } @Override public void addNewLanguages(Language[] languages) { - + } @Override public void updateLanguages(Language[] languages) { - + } @Override public void addNewGroups(Group[] groups) { - + } @Override public void updateGroups(Group[] groups) { - + } /** * Creates an {@link AutoStarter} if none exists, and then instructs the AutoStarter to update its Scheduled Start Task to correspond to the Scheduled Start Time information in the * {@link ContestInformation} object in the received {@link IInternalContest}. - * + * * @param theContest * - the Contest (Model) containing the Scheduled Start Time information * @param theController @@ -565,12 +695,12 @@ public IInternalContest getContest() { @Override public void submitRun(ClientId submitter, Problem problem, Language language, SerializedFile mainSubmissionFile, SerializedFile[] additionalFiles, long overrideTimeMS, long overrideRunId) { System.out.println("submitRun "+submitter+" "+problem+" "+language+" " +mainSubmissionFile.getName()+" aux file count "+additionalFiles.length+" time ="+overrideTimeMS+" run id ="+overrideRunId); - + ClientId serverClientId = new ClientId(contest.getSiteNumber(), Type.SERVER, 0); Run run = new Run(submitter, language, problem); try { - + RunFiles runFiles = new RunFiles(run, mainSubmissionFile, additionalFiles); Packet packet = PacketFactory.createSubmittedRun(contest.getClientId(), serverClientId, run, runFiles, overrideTimeMS, overrideRunId); handler.handlePacket(packet, null); @@ -579,19 +709,19 @@ public void submitRun(ClientId submitter, Problem problem, Language language, Se rethrow (e); } // sendToLocalServer(packet); - + } @Override public void submitRun(ClientId submitter, Problem problem, Language language, String entry_point, SerializedFile mainSubmissionFile, SerializedFile[] additionalFiles, long overrideTimeMS, long overrideRunId) { System.out.println("submitRun "+submitter+" "+problem+" "+language+" " +mainSubmissionFile.getName()+" aux file count "+additionalFiles.length+" entry_point ="+entry_point+" time ="+overrideTimeMS+" run id ="+overrideRunId); - + ClientId serverClientId = new ClientId(contest.getSiteNumber(), Type.SERVER, 0); Run run = new Run(submitter, language, problem); run.setEntryPoint(entry_point); - + try { - + RunFiles runFiles = new RunFiles(run, mainSubmissionFile, additionalFiles); Packet packet = PacketFactory.createSubmittedRun(contest.getClientId(), serverClientId, run, runFiles, overrideTimeMS, overrideRunId); handler.handlePacket(packet, null); @@ -604,7 +734,7 @@ public void submitRun(ClientId submitter, Problem problem, Language language, St private void rethrow(Exception e) { throw new RuntimeException(e); } - + protected String stripChar(String s, char ch) { int idx = s.indexOf(ch); while (idx > -1) { diff --git a/src/edu/csus/ecs/pc2/core/NullController.java b/src/edu/csus/ecs/pc2/core/NullController.java index 46d4050e9..9c8b3fb3c 100644 --- a/src/edu/csus/ecs/pc2/core/NullController.java +++ b/src/edu/csus/ecs/pc2/core/NullController.java @@ -39,9 +39,9 @@ /** * Null Controller, does nothing, nada, zip. - * + * * A skeleton implementation of the IInternalController. - * + * * @author pc2@ecs.csus.edu * @version $Id$ */ @@ -49,479 +49,605 @@ // $HeadURL$ public class NullController implements IInternalController { + @Override public void addNewAccount(Account account) { } + @Override public void addNewAccounts(Account[] account) { } + @Override public void addNewBalloonSettings(BalloonSettings newBalloonSettings) { } + @Override public void addNewCategory(Category newCategory) { } + @Override public void addNewClientSettings(ClientSettings newClientSettings) { } + @Override public void addNewGroup(Group group) { } + @Override public void addNewJudgement(Judgement judgement) { } + @Override public void addNewLanguage(Language language) { } + @Override public void addNewProblem(Problem problem, ProblemDataFiles problemDataFiles) { } + @Override public void addNewProblem(Problem[] problem, ProblemDataFiles[] problemDataFiles) { } + @Override public void addNewSite(Site site) { } + @Override public void addPacketListener(IPacketListener packetListener) { } + @Override public void addProblem(Problem problem) { } + @Override public void autoRegister(String teamInformation) { } + @Override public void cancelClarification(Clarification clarification) { } + @Override public void cancelRun(Run run) { } + @Override public void checkOutClarification(Clarification clarification, boolean readOnly) { } + @Override public void checkOutRejudgeRun(Run theRun) { } + @Override public void checkOutRun(Run run, boolean readOnly, boolean computerJudge) { } + @Override public IInternalContest clientLogin(IInternalContest internalContest, String loginName, String password) throws Exception { return null; } + @Override public void cloneProfile(Profile profile, ProfileCloneSettings settings, boolean switchNow) { } + @Override public void fetchRun(Run run) throws IOException, ClassNotFoundException, FileSecurityException { } + @Override public void forceConnectionDrop(ConnectionHandlerID connectionHandlerID) { } + @Override public void generateNewAccounts(String clientTypeName, int count, int startNumber, boolean active) { } + @Override public void generateNewAccounts(String clientTypeName, int siteNumber, int count, int startNumber, boolean active) { } + @Override public String getHostContacted() { return null; } + @Override public Log getLog() { return null; } + @Override public UIPlugin[] getPluginList() { return null; } + @Override public int getPortContacted() { return 0; } + @Override public ProblemDataFiles getProblemDataFiles(Problem problem) { return null; } + @Override public int getSecurityLevel() { return 0; } + @Override public void incomingPacket(Packet packet) { } + @Override public void initializeServer(IInternalContest contest) throws IOException, ClassNotFoundException, FileSecurityException { } + @Override public void initializeStorage(IStorage storage) { } + @Override public boolean isClientAutoShutdown() { return false; } + @Override public boolean isLogWindowVisible() { return false; } + @Override public boolean isUsingGUI() { return false; } + @Override public void login(String loginName, String password) { } + @Override public void logoffUser(ClientId clientId) { } + @Override public void logWarning(String string, Exception e) { } + @Override public void outgoingPacket(Packet packet) { } + @Override public void register(UIPlugin plugin) { } + @Override public void removeConnection(ConnectionHandlerID connectionHandlerID) { } + @Override public void removeJudgement(Judgement judgement) { } + @Override public void removeLogin(ClientId clientId) { } + @Override public void removePacketListener(IPacketListener packetListener) { } + @Override public void requestChangePassword(String oldPassword, String newPassword) { } + @Override public void resetContest(ClientId clientResettingContest, boolean eraseProblems, boolean eraseLanguages) { } + @Override public void sendCompilingMessage(Run run) { } + @Override public void sendExecutingMessage(Run run) { } + @Override public void sendRunToSubmissionInterface(Run run, RunFiles runFiles) { } + @Override public void sendSecurityMessage(String event, String message, ContestSecurityException contestSecurityException) { } + @Override public void sendServerLoginRequest(int inSiteNumber) throws Exception { } + @Override public void sendShutdownAllSites() { } + @Override public void sendShutdownSite(int siteNumber) { } + @Override public void sendToAdministrators(Packet packet) { } + @Override public void sendToClient(Packet packet) { } + @Override public void sendToJudges(Packet packet) { } + @Override public void sendToJudgesAndOthers(Packet packet, boolean sendToServers) { } + @Override public void sendToLocalServer(Packet packet) { } + @Override public void sendToRemoteServer(int siteNumber, Packet packet) { } + @Override public void sendToScoreboards(Packet packet) { } + @Override public void sendToServers(Packet packet) { } + @Override public void sendToSpectators(Packet packet) { } + @Override public void sendToTeams(Packet packet) { } + @Override public void sendValidatingMessage(Run run) { } + @Override public void setClientAutoShutdown(boolean clientAutoShutdown) { } + @Override public void setContest(IInternalContest newContest) { } + @Override public void setContestTime(ContestTime contestTime) { } + @Override public void setJudgementList(Judgement[] judgementList) { } + @Override public void setSecurityLevel(int securityLevel) { } + @Override public void setSiteNumber(int i) { } + @Override public void setUsingGUI(boolean usingGUI) { } + @Override public void showLogWindow(boolean showWindow) { } + @Override public void shutdownRemoteServers(ClientId requestor) { } + @Override public void shutdownServer(ClientId requestor) { } + @Override public void shutdownServer(ClientId requestor, int siteNumber) { } + @Override public void shutdownTransport() { } + @Override public void start(String[] stringArray) { } + @Override public void startAllContestTimes() { } + @Override public void startContest(int inSiteNumber) { } + @Override public ILogWindow startLogWindow(IInternalContest contest) { return null; } + @Override public void startMainUI(ClientId clientId) { } + @Override public void startPlayback(PlaybackInfo playbackInfo) { } + @Override public void stopAllContestTimes() { } + @Override public void stopContest(int inSiteNumber) { } + @Override public void submitClarification(Problem problem, String question) { } + @Override public void submitClarificationAnswer(Clarification clarification) { } + @Override public void submitJudgeRun(Problem problem, Language language, String filename, SerializedFile[] otherFiles) throws Exception { } + @Override public void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] auxFileList, long overrideSubmissionTimeMS, long overrideRunId) throws Exception { } + @Override public void submitRunJudgement(Run run, JudgementRecord judgementRecord, RunResultFiles runResultFiles) { } + @Override + public void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, boolean overrideStopOnFailure) throws Exception { + + } + + @Override + public void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, + long overrideSubmissionTimeMS, long overrideRunId, boolean overrideStopOnFailure) throws Exception { + + } + + @Override + public void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, SerializedFile[] otherFiles, + long overrideSubmissionTimeMS, long overrideRunId, boolean overrideStopOnFailure) throws Exception { + } + @Override public void switchProfile(Profile currentProfile, Profile switchToProfile, String contestPassword) { } + @Override public void syncProfileSubmissions(Profile profile) { } + @Override public void updateAccount(Account account) { } + @Override public void updateAccounts(Account[] account) { } + @Override public void updateBalloonSettings(BalloonSettings newBalloonSettings) { } + @Override public void updateCategories(Category[] categories) { } + @Override public void updateCategory(Category newCategory) { } + @Override public void updateClientSettings(ClientSettings clientSettings) { } + @Override public void updateContestController(IInternalContest inContest, IInternalController inController) { } + @Override public void updateContestInformation(ContestInformation contestInformation) { } + @Override public void updateContestTime(ContestTime newContestTime) { } + @Override public void updateFinalizeData(FinalizeData data) { } + @Override public void updateGroup(Group group) { } + @Override public void updateJudgement(Judgement newJudgement) { } + @Override public void updateLanguage(Language language) { } + @Override public void updateProblem(Problem problem) { } + @Override public void updateProblem(Problem problem, ProblemDataFiles problemDataFiles) { } + @Override public void updateProfile(Profile profile) { } + @Override public void updateRun(Run run, JudgementRecord judgementRecord, RunResultFiles runResultFiles) { } + @Override public void updateSite(Site newSite) { } @Override public void setConnectionManager(ITransportManager connectionManager) { - + } @Override public void addNewLanguages(Language[] languages) { - + } @Override public void updateLanguages(Language[] languages) { - + } @Override public void addNewGroups(Group[] groups) { - + } @Override public void updateGroups(Group[] groups) { - + } /** * Creates an {@link AutoStarter} if none exists, and then instructs the AutoStarter to update its Scheduled Start Task to correspond to the Scheduled Start Time information in the * {@link ContestInformation} object in the received {@link IInternalContest}. - * + * * @param theContest * - the Contest (Model) containing the Scheduled Start Time information * @param theController @@ -539,17 +665,17 @@ public IInternalContest getContest() { @Override public void submitRun(ClientId submitter, Problem problem, Language language, SerializedFile mainSubmissionFile, SerializedFile[] additionalFiles, long overrideTimeMS, long overrideRunId) { - + } @Override public void submitRun(ClientId submitter, Problem problem, Language language, String entry_point, SerializedFile mainSubmissionFile, SerializedFile[] additionalFiles, long overrideTimeMS, long overrideRunId) { - + } @Override public void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, SerializedFile[] otherFiles, long overrideSubmissionTimeMS, long overrideRunId) throws Exception { - + } @Override From 679d19c7f803ce4c776991c5d7bee2e5c6d21d3b Mon Sep 17 00:00:00 2001 From: John Buck Date: Sun, 23 Jun 2024 15:47:18 -0400 Subject: [PATCH 09/10] i_232 Fixes for Junit tests and indenting Changed that were in original code to spaces to fix indenting. Fixed bug in packethandler when overrideStopOnFailure is not present i the properties. Cosmetic/spacing changes added by Eclipse + @overrides Changes to support unit tests. Re-add legacy language support to LanguageUtilities. This should be deprecated, but there may be users out there that do not supply CLICS ID's in the language definition yaml, so for now we have to include it. This was found with unit testing. --- .../csus/ecs/pc2/core/InternalController.java | 2 +- .../csus/ecs/pc2/core/LanguageUtilities.java | 47 +- src/edu/csus/ecs/pc2/core/PacketHandler.java | 2 +- src/edu/csus/ecs/pc2/list/ListUtilities.java | 176 +++--- .../pc2/list/SubmissionSampleLocation.java | 90 +-- .../ecs/pc2/list/SubmissionSolutionList.java | 70 +-- .../csus/ecs/pc2/ui/SubmitSampleRunsPane.java | 528 +++++++++--------- .../csus/ecs/pc2/ui/team/QuickSubmitter.java | 2 +- .../csus/ecs/pc2/core/log/NullController.java | 156 +++++- .../pc2/shadow/RemoteRunSubmitterTest.java | 62 +- .../ecs/pc2/ui/team/QuickSubmitterTest.java | 13 +- 11 files changed, 663 insertions(+), 485 deletions(-) diff --git a/src/edu/csus/ecs/pc2/core/InternalController.java b/src/edu/csus/ecs/pc2/core/InternalController.java index b872912cf..c4b46c823 100644 --- a/src/edu/csus/ecs/pc2/core/InternalController.java +++ b/src/edu/csus/ecs/pc2/core/InternalController.java @@ -542,7 +542,7 @@ public void submitJudgeRun(Problem problem, Language language, String filename, /** * {@inheritDoc} * Calling this method is equivalent to calling - * {@link #submitJudgeRun(Problem, Language, String, SerializedFile[], long, long)} + * {@link #submitJudgeRun(Problem, Language, String, SerializedFile[], long, long, boolean)} * with zeroes as the last two parameters. */ @Override diff --git a/src/edu/csus/ecs/pc2/core/LanguageUtilities.java b/src/edu/csus/ecs/pc2/core/LanguageUtilities.java index 7f9d90867..ee02e2da6 100644 --- a/src/edu/csus/ecs/pc2/core/LanguageUtilities.java +++ b/src/edu/csus/ecs/pc2/core/LanguageUtilities.java @@ -11,8 +11,28 @@ */ public class LanguageUtilities { - /** + * Legacy list of language extensions and their full or partial language display name + * This should be deprecated and languages defined in system.pc2.yaml should be required to + * include the CLICS ID (as shown above) and optionally a list of extensions supported by the + * language. The list below is inadequate and out of date. For the moment, it is included for + * backward compatibility. JB + */ + public static final String[][] LANGUAGE_LIST = { // + { "java", "Java" }, // + { "kt", "Kotlin" }, // + { "cpp", "C++" }, // + { "cc", "C++" }, // + { "C", "C++" }, // + { "c++", "C++" }, // + { "py", "Python" }, // + { "cs", "Mono" }, // + { "pl", "Perl" }, // + // match c extension last, otherwisse would match C for C++ languages + { "c", "C" }, // + }; + + /** * get file extension. * * @param filename @@ -48,11 +68,36 @@ public static Language guessLanguage(IInternalContest myContest, String filename public static Language matchFirstLanguage(IInternalContest inContest, String extension) { Language[] allLangs = inContest.getLanguages(); + // first try the new way for(Language lang : allLangs) { if(lang.getExtensions().contains(extension)) { return(lang); } } + + // if all else fails, try the old way. This should be deprecated. JB + /** + * Partial or complete display name + */ + String displayName = extension; + + for (String[] row : LANGUAGE_LIST) { + String fileExtension = row[0]; + String dispName = row[1]; + + if (fileExtension.equals(extension)) { + displayName = dispName; + break; + } + } + + displayName = displayName.toLowerCase(); + + for (Language language : allLangs) { + if (language.getDisplayName().toLowerCase().indexOf(displayName) != -1) { + return language; + } + } return null; } diff --git a/src/edu/csus/ecs/pc2/core/PacketHandler.java b/src/edu/csus/ecs/pc2/core/PacketHandler.java index 6fb04a94e..7e0c76679 100644 --- a/src/edu/csus/ecs/pc2/core/PacketHandler.java +++ b/src/edu/csus/ecs/pc2/core/PacketHandler.java @@ -1606,7 +1606,7 @@ private void runSubmission(Packet packet, ClientId fromId, ConnectionHandlerID c updateRun = true; } - if(overrideStopOnFailure) { + if(overrideStopOnFailure != null && overrideStopOnFailure.booleanValue() == true) { run.setOverrideStopOnFailure(true); updateRun = true; } diff --git a/src/edu/csus/ecs/pc2/list/ListUtilities.java b/src/edu/csus/ecs/pc2/list/ListUtilities.java index ab3e1128e..1b22da552 100644 --- a/src/edu/csus/ecs/pc2/list/ListUtilities.java +++ b/src/edu/csus/ecs/pc2/list/ListUtilities.java @@ -21,7 +21,7 @@ */ public class ListUtilities { - /** + /** * Returns list of files that match the SubmissionSolutionList (judging types location/list) * * @param files list of files to be filtered @@ -55,7 +55,7 @@ public static List filterByJudgingTypes(List files, List sub * @param dirName location to fetch files from * @return list of files in and under dirName */ - // TODO REFACTOR replace findAll from QuickSubmitter with this method. + // TODO REFACTOR replace findAll from QuickSubmitter with this method. public static List findAllFiles(String dirName) { List files = new ArrayList<>(); @@ -79,92 +79,92 @@ public static List findAllFiles(String dirName) { return files; } - /** - * Get all CDP judge's sample submission filenames. - * - * Example files under config\sumit\submissions - * - * @param mycontest - * @param directoryName CDP config/ dir or CDP base directory - * @return list of judges sample submissions - */ - // TODO REFACTOR remove getAllCDPsubmissionFileNames from QuickSubmitter - public static List getAllJudgeSampleSubmissionFilenamesFromCDP(IInternalContest mycontest, String directoryName) { - - Problem[] problems = mycontest.getProblems(); - List files = new ArrayList<>(); - - String configDir = directoryName + File.separator + IContestLoader.CONFIG_DIRNAME; - if (new File(configDir).isDirectory()) { - directoryName = configDir; - } - - for (Problem problem : problems) { - - // config\sumit\submissions\accepted\ISumit.java - String probSubmissionDir = directoryName + File.separator + problem.getShortName() + File.separator - + IContestLoader.SUBMISSIONS_DIRNAME; - files.addAll(findAllFiles(probSubmissionDir)); - - } - - HashSet allExts = new HashSet(); - String ext, srcFile; - int ridx; - - // make up hashset of all language extensions - for(Language lang : mycontest.getLanguages()) { - allExts.addAll(lang.getExtensions()); - } - // Reverse scan for uninteresting files and remove them. - for(int i = files.size(); --i >= 0; ) { - srcFile = files.get(i).getName(); - ridx = srcFile.lastIndexOf('.'); - // if no extension on the file, or, it's not in our list of src extensions, drop the file. - if(ridx == -1 || !allExts.contains(srcFile.substring(ridx+1))) { - files.remove(i); - } - } - - return files; - } - - /** - * Gets a list of all the different types of judges' submissions by scanning the submissions folder for - * each problem. ex. accepted, wrong_answer, time_limit_exceeded, other, run_time_exception, etc. - * To qualify as a valid type, the particular folder must contain at least one source file with a known - * extension for the configurationed languages. - * - * @param mycontest The contest - * @param directoryName Where to start looking (config folder) - * @return List of folder basenames - */ - public static List getAllCDPSubmissionTypes(IInternalContest mycontest, String directoryName) { - List files = getAllJudgeSampleSubmissionFilenamesFromCDP(mycontest, directoryName); - String srcName; - int idx; - ArrayList types = new ArrayList(); - HashSet uniqTypes = new HashSet(); - - for(File src : files ) { - srcName = src.getParent(); - idx = srcName.lastIndexOf(File.separator); - if(idx != -1) { - srcName = srcName.substring(idx+1); - } - if(!uniqTypes.contains(srcName)) { - types.add(srcName); - uniqTypes.add(srcName); - } - } - types.sort(null); - return(types); - } - - /** - * Find files (in CDP) that contain one of the Problems in the list. - * - */ + /** + * Get all CDP judge's sample submission filenames. + * + * Example files under config\sumit\submissions + * + * @param mycontest + * @param directoryName CDP config/ dir or CDP base directory + * @return list of judges sample submissions + */ + // TODO REFACTOR remove getAllCDPsubmissionFileNames from QuickSubmitter + public static List getAllJudgeSampleSubmissionFilenamesFromCDP(IInternalContest mycontest, String directoryName) { + + Problem[] problems = mycontest.getProblems(); + List files = new ArrayList<>(); + + String configDir = directoryName + File.separator + IContestLoader.CONFIG_DIRNAME; + if (new File(configDir).isDirectory()) { + directoryName = configDir; + } + + for (Problem problem : problems) { + + // config\sumit\submissions\accepted\ISumit.java + String probSubmissionDir = directoryName + File.separator + problem.getShortName() + File.separator + + IContestLoader.SUBMISSIONS_DIRNAME; + files.addAll(findAllFiles(probSubmissionDir)); + + } + + HashSet allExts = new HashSet(); + String ext, srcFile; + int ridx; + + // make up hashset of all language extensions + for(Language lang : mycontest.getLanguages()) { + allExts.addAll(lang.getExtensions()); + } + // Reverse scan for uninteresting files and remove them. + for(int i = files.size(); --i >= 0; ) { + srcFile = files.get(i).getName(); + ridx = srcFile.lastIndexOf('.'); + // if no extension on the file, or, it's not in our list of src extensions, drop the file. + if(ridx == -1 || !allExts.contains(srcFile.substring(ridx+1))) { + files.remove(i); + } + } + + return files; + } + + /** + * Gets a list of all the different types of judges' submissions by scanning the submissions folder for + * each problem. ex. accepted, wrong_answer, time_limit_exceeded, other, run_time_exception, etc. + * To qualify as a valid type, the particular folder must contain at least one source file with a known + * extension for the configurationed languages. + * + * @param mycontest The contest + * @param directoryName Where to start looking (config folder) + * @return List of folder basenames + */ + public static List getAllCDPSubmissionTypes(IInternalContest mycontest, String directoryName) { + List files = getAllJudgeSampleSubmissionFilenamesFromCDP(mycontest, directoryName); + String srcName; + int idx; + ArrayList types = new ArrayList(); + HashSet uniqTypes = new HashSet(); + + for(File src : files ) { + srcName = src.getParent(); + idx = srcName.lastIndexOf(File.separator); + if(idx != -1) { + srcName = srcName.substring(idx+1); + } + if(!uniqTypes.contains(srcName)) { + types.add(srcName); + uniqTypes.add(srcName); + } + } + types.sort(null); + return(types); + } + + /** + * Find files (in CDP) that contain one of the Problems in the list. + * + */ public static List filterByProblems(List files, List selectedProblemList) { List newFileList = new ArrayList(); diff --git a/src/edu/csus/ecs/pc2/list/SubmissionSampleLocation.java b/src/edu/csus/ecs/pc2/list/SubmissionSampleLocation.java index 5889550bc..87c3d48bb 100644 --- a/src/edu/csus/ecs/pc2/list/SubmissionSampleLocation.java +++ b/src/edu/csus/ecs/pc2/list/SubmissionSampleLocation.java @@ -25,57 +25,57 @@ public class SubmissionSampleLocation implements Comparable 0) { - strVal = title + " ("+shortDirectoryName+")"; - } else { - strVal = shortDirectoryName; - } - if(!clicsAcronym.isEmpty()) { - strVal = strVal + " : " + clicsAcronym; - } - return strVal; - } + if (title.length() > 0) { + strVal = title + " ("+shortDirectoryName+")"; + } else { + strVal = shortDirectoryName; + } + if(!clicsAcronym.isEmpty()) { + strVal = strVal + " : " + clicsAcronym; + } + return strVal; + } - @Override - public int compareTo(SubmissionSampleLocation o) { - return o.toString().compareTo(toString()); - } + @Override + public int compareTo(SubmissionSampleLocation o) { + return o.toString().compareTo(toString()); + } } diff --git a/src/edu/csus/ecs/pc2/list/SubmissionSolutionList.java b/src/edu/csus/ecs/pc2/list/SubmissionSolutionList.java index cf49f21e8..52efbe81e 100644 --- a/src/edu/csus/ecs/pc2/list/SubmissionSolutionList.java +++ b/src/edu/csus/ecs/pc2/list/SubmissionSolutionList.java @@ -17,30 +17,30 @@ */ public class SubmissionSolutionList extends ArrayList { - /** - * - */ - private static final long serialVersionUID = 6231245379952020474L; + /** + * + */ + private static final long serialVersionUID = 6231245379952020474L; - private Hashtable submissionDirectoryToAcronym = new Hashtable(); + private Hashtable submissionDirectoryToAcronym = new Hashtable(); - public SubmissionSolutionList() { - super(); + public SubmissionSolutionList() { + super(); createSubmissionDirectoryMap(); - } + } - public SubmissionSolutionList(IInternalContest mycontest, String cdpPath) { - super(); - createSubmissionDirectoryMap(); - loadCDPSampleSubmissionList(mycontest, cdpPath); - } + public SubmissionSolutionList(IInternalContest mycontest, String cdpPath) { + super(); + createSubmissionDirectoryMap(); + loadCDPSampleSubmissionList(mycontest, cdpPath); + } - private void createSubmissionDirectoryMap() { + private void createSubmissionDirectoryMap() { // Create quick access to look up acronym for folder for(String [] subFolderRow : SubmissionSampleLocation.CLICS_SUBMISSION_TO_ACRONYM) { submissionDirectoryToAcronym.put(subFolderRow[0], subFolderRow[1]); } - } + } /** * get all directories and child directories (recurses). @@ -48,7 +48,7 @@ private void createSubmissionDirectoryMap() { * @param directory * @return list of directory names */ - // TODO REFACTOR move to FileUtilities.getAllDirectoryEntries + // TODO REFACTOR move to FileUtilities.getAllDirectoryEntries public static List getAllDirectoryEntries(String directory) { ArrayList list = new ArrayList<>(); @@ -57,14 +57,14 @@ public static List getAllDirectoryEntries(String directory) { if (files != null) { - for (File entry : files) { - if (entry.isDirectory()) { - list.add(directory + File.separator + entry.getName()); - if (!(entry.getName().equals(".") || entry.getName().equals(".."))) { - list.addAll(getAllDirectoryEntries(directory + File.separator + entry.getName())); - } - } - } + for (File entry : files) { + if (entry.isDirectory()) { + list.add(directory + File.separator + entry.getName()); + if (!(entry.getName().equals(".") || entry.getName().equals(".."))) { + list.addAll(getAllDirectoryEntries(directory + File.separator + entry.getName())); + } + } + } } return list; @@ -83,17 +83,17 @@ public String getAcronymForSubmissionDirectory(String dir) { return null; } - /** - * Load Judge's samples judgement types - * @param cdpPath - * @throws IOException - */ + /** + * Load Judge's samples judgement types + * @param cdpPath + * @throws IOException + */ // TODO NOW use FileUtilities.getAllDirectoryEntries - private void loadCDPSampleSubmissionList(IInternalContest contest, String cdpPath) { + private void loadCDPSampleSubmissionList(IInternalContest contest, String cdpPath) { - List types = ListUtilities.getAllCDPSubmissionTypes(contest, cdpPath); - for(String type : types) { - super.add(new SubmissionSampleLocation("", type, getAcronymForSubmissionDirectory(type))); - } - } + List types = ListUtilities.getAllCDPSubmissionTypes(contest, cdpPath); + for(String type : types) { + super.add(new SubmissionSampleLocation("", type, getAcronymForSubmissionDirectory(type))); + } + } } diff --git a/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java b/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java index bc64c763b..102299cf5 100644 --- a/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java +++ b/src/edu/csus/ecs/pc2/ui/SubmitSampleRunsPane.java @@ -89,25 +89,25 @@ public class SubmitSampleRunsPane extends JPanePlugin { private static final int ELAPSED_TIME_COLUMN = 5; - /** - * ClientSettings key for CDP Path - */ - private static final String CUSTOM_SUBMIT_SAMPLE_CDP_PATH = "CustomSubmitSampleCDPPath"; + /** + * ClientSettings key for CDP Path + */ + private static final String CUSTOM_SUBMIT_SAMPLE_CDP_PATH = "CustomSubmitSampleCDPPath"; - private static final long serialVersionUID = -8862440024499524533L; + private static final long serialVersionUID = -8862440024499524533L; - private JTextField cdpTextField; + private JTextField cdpTextField; - private JLabel messageLabel; + private JLabel messageLabel; - private QuickSubmitter submitter = new QuickSubmitter(); + private QuickSubmitter submitter = new QuickSubmitter(); - /** - * List of selected solutions names and dirs. - */ - private SubmissionSolutionList submissionSolutionList = null; + /** + * List of selected solutions names and dirs. + */ + private SubmissionSolutionList submissionSolutionList = null; - private JPanel centerPane = null; + private JPanel centerPane = null; private JButton filterButton = null; private JScrollPane scrollPane = null; @@ -155,15 +155,15 @@ public class SubmitSampleRunsPane extends JPanePlugin { // TODO On Admin update of Languages or Update of Problems - clear selected index arrays - public SubmitSampleRunsPane() { - super(); - setLayout(new BorderLayout()); + public SubmitSampleRunsPane() { + super(); + setLayout(new BorderLayout()); add(getMessagePanel(), BorderLayout.NORTH); add(getCenterPanel(), BorderLayout.CENTER); add(getBottomPanel(), BorderLayout.SOUTH); - } + } /** * This method initializes messagePanel @@ -288,156 +288,156 @@ public void actionPerformed(ActionEvent e) { } protected void updateCDPDirAndFields(String cdpConfigDir) { - try { + try { File configFile = new File(cdpConfigDir); String cdpRootDirectory = configFile.getAbsolutePath(); // if (configFile.getAbsolutePath().endsWith(IContestLoader.CONFIG_DIRNAME)) { // cdpRootDirectory = configFile.getParent(); // } - cdpTextField.setText(cdpRootDirectory); - updateClientCDPPath(cdpRootDirectory); + cdpTextField.setText(cdpRootDirectory); + updateClientCDPPath(cdpRootDirectory); } catch (Exception e) { log.log(Level.WARNING, "Problem updating CDP Dir", e); } } - /** - * Repopulate submissionSolutionList. - * - * @return - */ - public SubmissionSolutionList getSubmissionSolutionList() { - String cdpPath = cdpTextField.getText(); + /** + * Repopulate submissionSolutionList. + * + * @return + */ + public SubmissionSolutionList getSubmissionSolutionList() { + String cdpPath = cdpTextField.getText(); - submissionSolutionList = new SubmissionSolutionList(getContest(), cdpPath); + submissionSolutionList = new SubmissionSolutionList(getContest(), cdpPath); - return submissionSolutionList; - } + return submissionSolutionList; + } - private SubmissionSampleLocation[] toArray(SubmissionSolutionList list) { - return list.toArray(new SubmissionSampleLocation[list.size()]); - } + private SubmissionSampleLocation[] toArray(SubmissionSolutionList list) { + return list.toArray(new SubmissionSampleLocation[list.size()]); + } - protected void selectNewCDP() { + protected void selectNewCDP() { - File file = selectEntry("Select CDP"); + File file = selectEntry("Select CDP"); - File cdpDir = FileUtilities.findCDPConfigDirectory(file); + File cdpDir = FileUtilities.findCDPConfigDirectory(file); - if (cdpDir != null) { - updateCDPDirAndFields(cdpDir.getAbsolutePath()); - } else { + if (cdpDir != null) { + updateCDPDirAndFields(cdpDir.getAbsolutePath()); + } else { - int result = FrameUtilities.yesNoCancelDialog(this, - file.getAbsoluteFile() + " may not be a CDP directory, continue anyways?", "Select CDP"); - if (result == JOptionPane.YES_OPTION) { - updateCDPDirAndFields(file.getAbsolutePath()); - } - } - } + int result = FrameUtilities.yesNoCancelDialog(this, + file.getAbsoluteFile() + " may not be a CDP directory, continue anyways?", "Select CDP"); + if (result == JOptionPane.YES_OPTION) { + updateCDPDirAndFields(file.getAbsolutePath()); + } + } + } - /** - * Select yaml file/entry. - * - * @param dialogTitle - * @return - */ - protected File selectEntry(String dialogTitle) { + /** + * Select yaml file/entry. + * + * @param dialogTitle + * @return + */ + protected File selectEntry(String dialogTitle) { - JFileChooser chooser = new JFileChooser(cdpTextField.getText()); + JFileChooser chooser = new JFileChooser(cdpTextField.getText()); // chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - FileFilter filterYAML = new FileNameExtensionFilter("YAML document (*.yaml)", "yaml"); - chooser.addChoosableFileFilter(filterYAML); - - chooser.setAcceptAllFileFilterUsed(false); - chooser.setFileFilter(filterYAML); - - int action = chooser.showOpenDialog(this); - chooser.setDialogTitle(dialogTitle); - - switch (action) { - case JFileChooser.APPROVE_OPTION: - File file = chooser.getSelectedFile(); - return file; - case JFileChooser.CANCEL_OPTION: - case JFileChooser.ERROR_OPTION: - default: - break; - } - return null; - - } - - void updateClientCDPPath(String path) { - ClientSettings settings = getContest().getClientSettings(); - if (settings == null) { - settings = new ClientSettings(getContest().getClientId()); - } - settings.put(CUSTOM_SUBMIT_SAMPLE_CDP_PATH, path); - - getController().updateClientSettings(settings); - } - - protected String getClientCDPPath() { - - ClientSettings settings = getContest().getClientSettings(); - if (settings != null) { - String path = settings.getProperty(CUSTOM_SUBMIT_SAMPLE_CDP_PATH); - if (path != null) { - return path; - } - } - - return null; - } - - /** - * Reset fields back to default values - * - * @param usingGui - */ - protected void resetFields(boolean isUsingGui) { - String cdpPath = getContest().getContestInformation().getJudgeCDPBasePath(); - - String clientPath = getClientCDPPath(); - - if (clientPath != null && !clientPath.equals(cdpPath)) { - int result = FrameUtilities.yesNoCancelDialog(this, "Overwrite locally saved CDP path with this (default) " + cdpPath, - "Replace CDP Path?"); - if (result == JOptionPane.NO_OPTION) { - cdpPath = clientPath; - } - } - - submissionList = null; - stopSubmissionTimer(); - clearSubmissionFiles(); - clearAllRuns(); - - - cdpTextField.setText(cdpPath); - -// getController().updateClientSettings(settings); - - } - - /** - * Submit sample solutions. - */ - protected void submitSelectedJudgesSolutions() { - showMessage(""); - - if(submissionFileList != null) { - showMessage("Please wait until the previous files have finished being submitted (" + (submissionList.size() - currentSubmission) + " remain)"); - return; - } - String warningMessage = verifyCDP (cdpTextField.getText()); - if (warningMessage != null) { - // let the user know that the CDP selected may not work - FrameUtilities.showMessage(this, "Maybe the CDP is invalid?", warningMessage); - } + FileFilter filterYAML = new FileNameExtensionFilter("YAML document (*.yaml)", "yaml"); + chooser.addChoosableFileFilter(filterYAML); + + chooser.setAcceptAllFileFilterUsed(false); + chooser.setFileFilter(filterYAML); + + int action = chooser.showOpenDialog(this); + chooser.setDialogTitle(dialogTitle); + + switch (action) { + case JFileChooser.APPROVE_OPTION: + File file = chooser.getSelectedFile(); + return file; + case JFileChooser.CANCEL_OPTION: + case JFileChooser.ERROR_OPTION: + default: + break; + } + return null; + + } + + void updateClientCDPPath(String path) { + ClientSettings settings = getContest().getClientSettings(); + if (settings == null) { + settings = new ClientSettings(getContest().getClientId()); + } + settings.put(CUSTOM_SUBMIT_SAMPLE_CDP_PATH, path); + + getController().updateClientSettings(settings); + } + + protected String getClientCDPPath() { + + ClientSettings settings = getContest().getClientSettings(); + if (settings != null) { + String path = settings.getProperty(CUSTOM_SUBMIT_SAMPLE_CDP_PATH); + if (path != null) { + return path; + } + } + + return null; + } + + /** + * Reset fields back to default values + * + * @param usingGui + */ + protected void resetFields(boolean isUsingGui) { + String cdpPath = getContest().getContestInformation().getJudgeCDPBasePath(); + + String clientPath = getClientCDPPath(); + + if (clientPath != null && !clientPath.equals(cdpPath)) { + int result = FrameUtilities.yesNoCancelDialog(this, "Overwrite locally saved CDP path with this (default) " + cdpPath, + "Replace CDP Path?"); + if (result == JOptionPane.NO_OPTION) { + cdpPath = clientPath; + } + } + + submissionList = null; + stopSubmissionTimer(); + clearSubmissionFiles(); + clearAllRuns(); + + + cdpTextField.setText(cdpPath); + +// getController().updateClientSettings(settings); + + } + + /** + * Submit sample solutions. + */ + protected void submitSelectedJudgesSolutions() { + showMessage(""); + + if(submissionFileList != null) { + showMessage("Please wait until the previous files have finished being submitted (" + (submissionList.size() - currentSubmission) + " remain)"); + return; + } + String warningMessage = verifyCDP (cdpTextField.getText()); + if (warningMessage != null) { + // let the user know that the CDP selected may not work + FrameUtilities.showMessage(this, "Maybe the CDP is invalid?", warningMessage); + } List files = ListUtilities.getAllJudgeSampleSubmissionFilenamesFromCDP(getContest(), cdpTextField.getText()); @@ -480,27 +480,27 @@ protected void submitSelectedJudgesSolutions() { files = ListUtilities.filterByLanguages(files, getContest(), langList); } } - int count = 0; - - if(Utilities.isDebugMode()) { - for (File file : files) { - count++; - System.out.println("Will submit #" + count + " file = " + file.getAbsolutePath()); - } - } else { - count = files.size(); - } - if (count == 0) { - showMessage("There are no matching CDP sample source files under " + cdpTextField.getText()); - return; - } - - // check with the user to be sure they want to submit everything. + int count = 0; + + if(Utilities.isDebugMode()) { + for (File file : files) { + count++; + System.out.println("Will submit #" + count + " file = " + file.getAbsolutePath()); + } + } else { + count = files.size(); + } + if (count == 0) { + showMessage("There are no matching CDP sample source files under " + cdpTextField.getText()); + return; + } + + // check with the user to be sure they want to submit everything. int result = FrameUtilities.yesNoCancelDialog(this, "Submit " + count + " judge sample submissions?", "Submit CDP submissions"); - if (result != JOptionPane.YES_OPTION) { - return; - } + if (result != JOptionPane.YES_OPTION) { + return; + } showMessage("Submitting " + count + " runs."); submissionFileList = files; @@ -509,25 +509,25 @@ protected void submitSelectedJudgesSolutions() { currentSubmission = 0; submitNextSubmission(); - } - - private void submitNextSubmission() { - try { - File file = submissionFileList.get(currentSubmission); - - submissionTimerTask = new TimerTask() { - @Override - public void run() { - // Whoops! This means the submission never came in - log.severe("No submission was received from the server for #" + currentSubmission + "; cancelling remaining submissions"); - showMessage("Submission #" + currentSubmission + " not received from server"); - clearSubmissionFiles(); + } + + private void submitNextSubmission() { + try { + File file = submissionFileList.get(currentSubmission); + + submissionTimerTask = new TimerTask() { + @Override + public void run() { + // Whoops! This means the submission never came in + log.severe("No submission was received from the server for #" + currentSubmission + "; cancelling remaining submissions"); + showMessage("Submission #" + currentSubmission + " not received from server"); + clearSubmissionFiles(); stopSubmissionTimer(); - } - }; + } + }; - submissionWaitTimer = new Timer("Submission Wait Timer " + currentSubmission); - submissionWaitTimer.schedule(submissionTimerTask, SUBMISSION_WAIT_TIMEOUT_MS); + submissionWaitTimer = new Timer("Submission Wait Timer " + currentSubmission); + submissionWaitTimer.schedule(submissionTimerTask, SUBMISSION_WAIT_TIMEOUT_MS); SubmissionSample sub = submitter.sendSubmission(file, !overrideStopOnError.isSelected()); if(sub != null) { @@ -536,34 +536,34 @@ public void run() { } if(Utilities.isDebugMode()) { System.out.println("Submitted #" + currentSubmission + " for problem " + sub.toString()); - } - } catch(Exception e) { - log.log(Level.WARNING, "Error submitting submission #" + currentSubmission, e); - clearSubmissionFiles(); - stopSubmissionTimer(); - } - } - - private void clearSubmissionFiles() { - submissionFileList = null; - currentSubmission = -1; - runsAdded.clear(); - } - - private void stopSubmissionTimer() { - if(submissionWaitTimer != null) { - submissionWaitTimer.cancel(); - submissionWaitTimer = null; - submissionTimerTask = null; - } - } - - /** - * Check whether cdpDir and model match - * @param cdpDir base dir for CDP, parent dir for config/ dir - * @return null if no issues, else a warning message about a diffence between model and cdpDir - */ - private String verifyCDP(String cdpDir) { + } + } catch(Exception e) { + log.log(Level.WARNING, "Error submitting submission #" + currentSubmission, e); + clearSubmissionFiles(); + stopSubmissionTimer(); + } + } + + private void clearSubmissionFiles() { + submissionFileList = null; + currentSubmission = -1; + runsAdded.clear(); + } + + private void stopSubmissionTimer() { + if(submissionWaitTimer != null) { + submissionWaitTimer.cancel(); + submissionWaitTimer = null; + submissionTimerTask = null; + } + } + + /** + * Check whether cdpDir and model match + * @param cdpDir base dir for CDP, parent dir for config/ dir + * @return null if no issues, else a warning message about a diffence between model and cdpDir + */ + private String verifyCDP(String cdpDir) { Problem[] problems = getContest().getProblems(); List files = new ArrayList<>(); @@ -588,70 +588,70 @@ private String verifyCDP(String cdpDir) { if(!missingProbs.isEmpty()) { warningMsg = "No problem folder found for: " + missingProbs; } - return warningMsg; - } - - /** - * Returns the list of filenames that end in extension - * - * @param files - * @param extension - * @return - */ - public static List filterSource(List files, String extension) { - - List list = new ArrayList(); - for (File file : files) { - if (file.getName().endsWith(extension)) { - list.add(file); - } - } - return list; - } - - @Override - public String getPluginTitle() { - return "Submitter Pane"; - } - - @Override - public void setContestAndController(IInternalContest inContest, IInternalController inController) { - super.setContestAndController(inContest, inController); - - resetFields(false); - - String cdpPath = getContest().getContestInformation().getJudgeCDPBasePath(); - String clientPath = getClientCDPPath(); - - if (clientPath != null) { - cdpPath = clientPath; - } - -// xlog("CDP dir is now at " + cdpPath); - cdpTextField.setText(cdpPath); - - showMessage(""); - - submitter.setContestAndController(inContest, inController); + return warningMsg; + } + + /** + * Returns the list of filenames that end in extension + * + * @param files + * @param extension + * @return + */ + public static List filterSource(List files, String extension) { + + List list = new ArrayList(); + for (File file : files) { + if (file.getName().endsWith(extension)) { + list.add(file); + } + } + return list; + } + + @Override + public String getPluginTitle() { + return "Submitter Pane"; + } + + @Override + public void setContestAndController(IInternalContest inContest, IInternalController inController) { + super.setContestAndController(inContest, inController); + + resetFields(false); + + String cdpPath = getContest().getContestInformation().getJudgeCDPBasePath(); + String clientPath = getClientCDPPath(); + + if (clientPath != null) { + cdpPath = clientPath; + } + +// xlog("CDP dir is now at " + cdpPath); + cdpTextField.setText(cdpPath); + + showMessage(""); + + submitter.setContestAndController(inContest, inController); getEditFilterFrame().setContestAndController(inContest, inController); - log = inController.getLog(); + log = inController.getLog(); getContest().addRunListener(new RunListenerImplementation()); - } + } - public void showMessage(final String message) { - SwingUtilities.invokeLater(new Runnable() { - @Override + public void showMessage(final String message) { + SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { -// xlog(message); - messageLabel.setText(message); - messageLabel.setToolTipText(message); - } - }); - } +// xlog(message); + messageLabel.setText(message); + messageLabel.setToolTipText(message); + } + }); + } /** * This method initializes filterButton diff --git a/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java b/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java index 8df1ef637..409f1d960 100644 --- a/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java +++ b/src/edu/csus/ecs/pc2/ui/team/QuickSubmitter.java @@ -104,7 +104,7 @@ public List getAllCDPsubmissionFileNames(IInternalContest mycontest, Strin * @see #guessProblem(IInternalContest, String) * * @param a list of files to submit - * @return count of files sucessfully submitted/added. + * @return list of successfully submitted samples. */ public List sendSubmissions(List filesToSubmit) { diff --git a/test/edu/csus/ecs/pc2/core/log/NullController.java b/test/edu/csus/ecs/pc2/core/log/NullController.java index 052303695..38e460571 100644 --- a/test/edu/csus/ecs/pc2/core/log/NullController.java +++ b/test/edu/csus/ecs/pc2/core/log/NullController.java @@ -41,7 +41,7 @@ /** * A controller that does nothing. - * + * * @author pc2@ecs.csus.edu * @version $Id$ */ @@ -51,7 +51,7 @@ public class NullController implements IInternalController{ private Log log = null; - + protected NullController() { } @@ -60,106 +60,127 @@ public NullController(String logFilename) { log = new Log(logFilename); } + @Override public void updateSite(Site newSite) { // TODO Auto-generated method stub } + @Override public void updateRun(Run run, JudgementRecord judgementRecord, RunResultFiles runResultFiles) { // TODO Auto-generated method stub } + @Override public void updateProfile(Profile profile) { // TODO Auto-generated method stub } + @Override public void updateProblem(Problem problem, ProblemDataFiles problemDataFiles) { // TODO Auto-generated method stub } + @Override public void updateProblem(Problem problem) { // TODO Auto-generated method stub } + @Override public void updateLanguage(Language language) { // TODO Auto-generated method stub } + @Override public void updateJudgement(Judgement newJudgement) { // TODO Auto-generated method stub } + @Override public void updateGroup(Group group) { // TODO Auto-generated method stub } + @Override public void updateFinalizeData(FinalizeData data) { // TODO Auto-generated method stub } + @Override public void updateContestTime(ContestTime newContestTime) { // TODO Auto-generated method stub } + @Override public void updateContestInformation(ContestInformation contestInformation) { // TODO Auto-generated method stub } + @Override public void updateContestController(IInternalContest inContest, IInternalController inController) { // TODO Auto-generated method stub } + @Override public void updateClientSettings(ClientSettings clientSettings) { // TODO Auto-generated method stub } + @Override public void updateCategory(Category newCategory) { // TODO Auto-generated method stub } + @Override public void updateCategories(Category[] categories) { // TODO Auto-generated method stub } + @Override public void updateBalloonSettings(BalloonSettings newBalloonSettings) { // TODO Auto-generated method stub } + @Override public void updateAccounts(Account[] account) { // TODO Auto-generated method stub } + @Override public void updateAccount(Account account) { // TODO Auto-generated method stub } + @Override public void syncProfileSubmissions(Profile profile) { // TODO Auto-generated method stub } + @Override public void switchProfile(Profile currentProfile, Profile switchToProfile, String contestPassword) { // TODO Auto-generated method stub } + @Override public void submitRunJudgement(Run run, JudgementRecord judgementRecord, RunResultFiles runResultFiles) { // TODO Auto-generated method stub @@ -170,476 +191,581 @@ public void submitJudgeRun(Problem problem, Language language, String mainFileNa } + @Override public void submitClarificationAnswer(Clarification clarification) { // TODO Auto-generated method stub } + @Override public void submitClarification(Problem problem, String question) { // TODO Auto-generated method stub } + @Override public void stopContest(int inSiteNumber) { // TODO Auto-generated method stub } + @Override public void stopAllContestTimes() { // TODO Auto-generated method stub } + @Override public void startPlayback(PlaybackInfo playbackInfo) { // TODO Auto-generated method stub } + @Override public void startMainUI(ClientId clientId) { // TODO Auto-generated method stub } + @Override public ILogWindow startLogWindow(IInternalContest contest) { getLog().log(Level.WARNING, "Attempted to use startLogWindow ", new Exception("Attempted to use startLogWindow")); return null; } + @Override public void startContest(int inSiteNumber) { // TODO Auto-generated method stub } + @Override public void startAllContestTimes() { // TODO Auto-generated method stub } + @Override public void start(String[] stringArray) { // TODO Auto-generated method stub } + @Override public void shutdownTransport() { // TODO Auto-generated method stub } + @Override public void shutdownServer(ClientId requestor, int siteNumber) { // TODO Auto-generated method stub } + @Override public void shutdownServer(ClientId requestor) { // TODO Auto-generated method stub } + @Override public void shutdownRemoteServers(ClientId requestor) { // TODO Auto-generated method stub } + @Override public void showLogWindow(boolean showWindow) { // TODO Auto-generated method stub } + @Override public void setUsingGUI(boolean usingGUI) { // TODO Auto-generated method stub } + @Override public void setSiteNumber(int i) { // TODO Auto-generated method stub } + @Override public void setSecurityLevel(int securityLevel) { // TODO Auto-generated method stub } + @Override public void setJudgementList(Judgement[] judgementList) { // TODO Auto-generated method stub } + @Override public void setContestTime(ContestTime contestTime) { // TODO Auto-generated method stub } + @Override public void setContest(IInternalContest newContest) { // TODO Auto-generated method stub } + @Override public void setClientAutoShutdown(boolean clientAutoShutdown) { // TODO Auto-generated method stub } + @Override public void sendValidatingMessage(Run run) { // TODO Auto-generated method stub } + @Override public void sendToTeams(Packet packet) { // TODO Auto-generated method stub } + @Override public void sendToSpectators(Packet packet) { // TODO Auto-generated method stub } + @Override public void sendToServers(Packet packet) { // TODO Auto-generated method stub } + @Override public void sendToScoreboards(Packet packet) { // TODO Auto-generated method stub } + @Override public void sendToRemoteServer(int siteNumber, Packet packet) { // TODO Auto-generated method stub } + @Override public void sendToLocalServer(Packet packet) { // TODO Auto-generated method stub } + @Override public void sendToJudges(Packet packet) { // TODO Auto-generated method stub } + @Override public void sendToClient(Packet packet) { // TODO Auto-generated method stub } + @Override public void sendToAdministrators(Packet packet) { // TODO Auto-generated method stub } + @Override public void sendShutdownSite(int siteNumber) { // TODO Auto-generated method stub } + @Override public void sendShutdownAllSites() { // TODO Auto-generated method stub } + @Override public void sendServerLoginRequest(int inSiteNumber) throws Exception { // TODO Auto-generated method stub } + @Override public void sendSecurityMessage(String event, String message, ContestSecurityException contestSecurityException) { // TODO Auto-generated method stub } + @Override public void sendExecutingMessage(Run run) { // TODO Auto-generated method stub } + @Override public void sendCompilingMessage(Run run) { // TODO Auto-generated method stub } + @Override public void resetContest(ClientId clientResettingContest, boolean eraseProblems, boolean eraseLanguages) { // TODO Auto-generated method stub } + @Override public void requestChangePassword(String oldPassword, String newPassword) { // TODO Auto-generated method stub } + @Override public void removePacketListener(IPacketListener packetListener) { // TODO Auto-generated method stub } + @Override public void removeLogin(ClientId clientId) { // TODO Auto-generated method stub } + @Override public void removeJudgement(Judgement judgement) { // TODO Auto-generated method stub } + @Override public void removeConnection(ConnectionHandlerID connectionHandlerID) { // TODO Auto-generated method stub } + @Override public void register(UIPlugin plugin) { // TODO Auto-generated method stub } + @Override public void outgoingPacket(Packet packet) { // TODO Auto-generated method stub } + @Override public void logoffUser(ClientId clientId) { // TODO Auto-generated method stub } + @Override public void login(String loginName, String password) { // TODO Auto-generated method stub } + @Override public void logWarning(String string, Exception e) { // TODO Auto-generated method stub } + @Override public boolean isUsingGUI() { return false; } + @Override public boolean isLogWindowVisible() { return false; } + @Override public boolean isClientAutoShutdown() { return false; } + @Override public void initializeStorage(IStorage storage) { // TODO Auto-generated method stub } + @Override public void initializeServer(IInternalContest contest) throws IOException, ClassNotFoundException, FileSecurityException { // TODO Auto-generated method stub } + @Override public void incomingPacket(Packet packet) { // TODO Auto-generated method stub } + @Override public int getSecurityLevel() { return 0; } + @Override public ProblemDataFiles getProblemDataFiles(Problem problem) { return null; } + @Override public int getPortContacted() { return 0; } + @Override public UIPlugin[] getPluginList() { return null; } + @Override public Log getLog() { return log; } + @Override public String getHostContacted() { return null; } + @Override public void generateNewAccounts(String clientTypeName, int count, int startNumber, boolean active) { // TODO Auto-generated method stub } + @Override public void generateNewAccounts(String clientTypeName, int siteNumber, int count, int startNumber, boolean active) { // TODO Auto-generated method stub } + @Override public void forceConnectionDrop(ConnectionHandlerID connectionHandlerID) { // TODO Auto-generated method stub } + @Override public void fetchRun(Run run) throws IOException, ClassNotFoundException, FileSecurityException { // TODO Auto-generated method stub } + @Override public void cloneProfile(Profile profile, ProfileCloneSettings settings, boolean switchNow) { // TODO Auto-generated method stub } + @Override public IInternalContest clientLogin(IInternalContest internalContest, String loginName, String password) throws Exception { return null; } + @Override public void checkOutRun(Run run, boolean readOnly, boolean computerJudge) { // TODO Auto-generated method stub } + @Override public void checkOutRejudgeRun(Run theRun) { // TODO Auto-generated method stub } + @Override public void checkOutClarification(Clarification clarification, boolean readOnly) { // TODO Auto-generated method stub } + @Override public void cancelRun(Run run) { // TODO Auto-generated method stub } + @Override public void cancelClarification(Clarification clarification) { // TODO Auto-generated method stub } + @Override public void addProblem(Problem problem) { // TODO Auto-generated method stub } + @Override public void addPacketListener(IPacketListener packetListener) { // TODO Auto-generated method stub } + @Override public void addNewSite(Site site) { // TODO Auto-generated method stub } + @Override public void addNewProblem(Problem[] problem, ProblemDataFiles[] problemDataFiles) { // TODO Auto-generated method stub } + @Override public void addNewProblem(Problem problem, ProblemDataFiles problemDataFiles) { // TODO Auto-generated method stub } + @Override public void addNewLanguage(Language language) { // TODO Auto-generated method stub } + @Override public void addNewJudgement(Judgement judgement) { // TODO Auto-generated method stub } + @Override public void addNewGroup(Group group) { // TODO Auto-generated method stub } + @Override public void addNewClientSettings(ClientSettings newClientSettings) { // TODO Auto-generated method stub } + @Override public void addNewCategory(Category newCategory) { // TODO Auto-generated method stub } + @Override public void addNewBalloonSettings(BalloonSettings newBalloonSettings) { // TODO Auto-generated method stub } + @Override public void addNewAccounts(Account[] account) { // TODO Auto-generated method stub } + @Override public void addNewAccount(Account account) { // TODO Auto-generated method stub } + @Override public void submitJudgeRun(Problem problem, Language language, String filename, SerializedFile[] otherFiles) throws Exception { // TODO Auto-generated method stub - + } + @Override public void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] auxFileList, long overrideSubmissionTimeMS, long overrideRunId) throws Exception { // TODO Auto-generated method stub - + + } + @Override + public void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, boolean overrideStopOnFailure) throws Exception { + + } + + @Override + public void submitJudgeRun(Problem problem, Language language, String mainFileName, SerializedFile[] otherFiles, + long overrideSubmissionTimeMS, long overrideRunId, boolean overrideStopOnFailure) throws Exception { + } + @Override + public void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, SerializedFile[] otherFiles, + long overrideSubmissionTimeMS, long overrideRunId, boolean overrideStopOnFailure) throws Exception { + } + + @Override public void sendRunToSubmissionInterface(Run run, RunFiles runFiles) { // TODO Auto-generated method stub - + } + @Override public void autoRegister(String teamInformation) { // TODO Auto-generated method stub - + } + @Override public void sendToJudgesAndOthers(Packet packet, boolean sendToServers) { // TODO Auto-generated method stub - + } @Override public void setConnectionManager(ITransportManager connectionManager) { // TODO Auto-generated method stub - + } @Override public void addNewLanguages(Language[] languages) { - + } @Override public void updateLanguages(Language[] languages) { - + } @Override public void addNewGroups(Group[] groups) { - + } @Override public void updateGroups(Group[] groups) { - + } @Override public void updateAutoStartInformation(IInternalContest aContest, IInternalController aController) { // TODO Auto-generated method stub - + } @Override @@ -651,7 +777,7 @@ public IInternalContest getContest() { @Override public void submitRun(ClientId submitter, Problem problem, Language language, SerializedFile mainSubmissionFile, SerializedFile[] additionalFiles, long overrideTimeMS, long overrideRunId) { // TODO Auto-generated method stub - + } @Override @@ -664,7 +790,7 @@ public void submitRun(ClientId submitter, Problem problem, Language language, St @Override public void submitJudgeRun(Problem problem, Language language, SerializedFile mainFile, SerializedFile[] otherFiles, long overrideSubmissionTimeMS, long overrideRunId) throws Exception { // TODO Auto-generated method stub - + } @Override diff --git a/test/edu/csus/ecs/pc2/shadow/RemoteRunSubmitterTest.java b/test/edu/csus/ecs/pc2/shadow/RemoteRunSubmitterTest.java index 2bc26f96b..50faf365b 100644 --- a/test/edu/csus/ecs/pc2/shadow/RemoteRunSubmitterTest.java +++ b/test/edu/csus/ecs/pc2/shadow/RemoteRunSubmitterTest.java @@ -27,80 +27,80 @@ import edu.csus.ecs.pc2.core.util.AbstractTestCase; public class RemoteRunSubmitterTest extends AbstractTestCase{ - - + + /** - * Test submitrun + * Test submitrun * @throws Exception */ public void testOneSubmit() throws Exception { - + String contestDBdir = getOutputDataDirectory(getName()); - + ensureDirectory(contestDBdir); IStorage storage = new FileStorage(contestDBdir); - + SampleContest sample = new SampleContest(); IInternalContest contest = sample.createStandardContest(); - + contest.setStorage(storage); - + contest.generateNewAccounts(Type.FEEDER.toString(), 2, true); Account feeder = getRandomAccount(contest, Type.FEEDER); setCCSMode (contest, feeder); - + assertTrue("Expecting shadow for feeder ",contest.isAllowed(feeder.getClientId(), Permission.Type.SHADOW_PROXY_TEAM)); assertTrue("Not CCS Test ", contest.getContestInformation().isCcsTestMode()); - + IInternalController controller = new MockController(); controller.initializeServer(contest); - + Account[] teams = getTeamAccounts(contest); Arrays.sort(teams, new AccountComparator()); assertEquals("Number of teams", 120, teams.length); - + assertEquals("Expected languages in contest ", 6, contest.getLanguages().length); Account account = getRandomAccount(contest, Type.TEAM); ClientId team = account.getClientId(); Language language = getRandomLanguage(contest); Problem problem = getRandomProblem(contest); - + assertNotNull("Language should not be null ",language); assertNotNull("Language name should not be null ",language.getDisplayName()); - + assertNotNull(feeder); contest.setClientId(feeder.getClientId()); RemoteRunSubmitter sub = new RemoteRunSubmitter(controller); - + // sub.submitRun(account.getClientId(), problemName, languageName, mainFile, auxFiles, overrideTimeMS, overrideRunId); - + ClientId submitter = team; SerializedFile mainSubmissionFile = new SerializedFile(getSamplesSourceFilename(SUMIT_SOURCE_FILENAME)); SerializedFile[] additionalFiles = new SerializedFile[0]; - + long overrideTimeMS = 300; long overrideRunId = 44; controller.submitRun(submitter, problem, language, mainSubmissionFile, additionalFiles, overrideTimeMS, overrideRunId); - + assertEquals("Expecting number of runs ", 1, contest.getRuns().length); printruns(contest); - + String[] src_lines = Utilities.loadFile(getSamplesSourceFilename(SUMIT_SOURCE_FILENAME)); String source = String.join("", src_lines); - + String base64String = Base64.getEncoder().encodeToString(source.getBytes()); IFile mainFile = new IFileImpl("sumit.java", base64String); - + List auxFiles = new ArrayList(); - + sub.submitRun(submitter.getName().toLowerCase(), problem.getShortName(), language.getID(), mainFile, auxFiles, overrideTimeMS, overrideRunId); - + assertEquals("Expecting number of runs ", 2, contest.getRuns().length); - + printruns(contest); - + } /** @@ -109,27 +109,27 @@ public void testOneSubmit() throws Exception { * @param account */ private void setCCSMode(IInternalContest contest, Account account) { - + account.addPermission(Permission.Type.SHADOW_PROXY_TEAM); contest.updateAccount(account); - + ContestInformation contestInformation = contest.getContestInformation(); contestInformation.setCcsTestMode(true); contest.updateContestInformation(contestInformation); } private void printruns(IInternalContest contest) { - + Run[] runs = contest.getRuns(); System.out.println(""); System.out.println("There are "+runs.length+" runs"); for (Run run : runs) { System.out.println("Run = "+run.getNumber()+" is "+run); } - - + + } - + } diff --git a/test/edu/csus/ecs/pc2/ui/team/QuickSubmitterTest.java b/test/edu/csus/ecs/pc2/ui/team/QuickSubmitterTest.java index 1022dbef3..92dffa843 100644 --- a/test/edu/csus/ecs/pc2/ui/team/QuickSubmitterTest.java +++ b/test/edu/csus/ecs/pc2/ui/team/QuickSubmitterTest.java @@ -16,10 +16,11 @@ import edu.csus.ecs.pc2.core.util.AbstractTestCase; import edu.csus.ecs.pc2.imports.ccs.ContestSnakeYAMLLoader; import edu.csus.ecs.pc2.imports.ccs.IContestLoader; +import edu.csus.ecs.pc2.list.SubmissionSample; /** * Unit test. - * + * * @author Douglas A. Lane, PC^2 Team, pc2@ecs.csus.edu */ public class QuickSubmitterTest extends AbstractTestCase { @@ -123,7 +124,7 @@ public void testfilter() throws Exception { /** * Test QuickSubmitter send/add submissions. - * + * * @throws Exception */ public void testsendSubmissions() throws Exception { @@ -154,7 +155,13 @@ public void testsendSubmissions() throws Exception { List files = submitter.getAllCDPsubmissionFileNames(contest, cdpConfig); assertEquals(expectedFiles, files.size()); - int totSubmit = submitter.sendSubmissions(files); + List subList = submitter.sendSubmissions(files); + int totSubmit; + if(subList == null) { + totSubmit = 0; + } else { + totSubmit = subList.size(); + } assertEquals(expectedFiles, totSubmit); } From 0dc9ee680eaad8cd16a26c06b2d9f92b7487f82b Mon Sep 17 00:00:00 2001 From: John Buck Date: Sun, 23 Jun 2024 16:40:57 -0400 Subject: [PATCH 10/10] i_232 Fix deserialization issue If an older Language object is deserialized, the extensions array can be null. This fix addresses that. --- src/edu/csus/ecs/pc2/core/model/Language.java | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/edu/csus/ecs/pc2/core/model/Language.java b/src/edu/csus/ecs/pc2/core/model/Language.java index 8fd3b939d..d88409c3b 100644 --- a/src/edu/csus/ecs/pc2/core/model/Language.java +++ b/src/edu/csus/ecs/pc2/core/model/Language.java @@ -245,6 +245,15 @@ public int hashCode() { return elementId.hashCode(); } + /** + * Check if extensions array is allocated. If not allocate it. This can happen on deserialization of an older object. + */ + private void checkExtensions() { + if(extensions == null) { + extensions = new ArrayList(); + } + } + public String getExecutableIdentifierMask() { return executableIdentifierMask; } @@ -282,7 +291,8 @@ public boolean isUsingJudgeProgramExecuteCommandLine() { } public void setID(String newId) { - this.id = newId; + id = newId; + checkExtensions(); // set default extensions for the language based on its CLICS id if(extensions.isEmpty()) { String [] ext = null; @@ -308,14 +318,36 @@ public String getID() { } public void setExtensions(ArrayList exts) { + checkExtensions(); extensions.clear(); extensions.addAll(exts); } public ArrayList getExtensions() { + checkExtensions(); + if(extensions.isEmpty()) { + setDefaultExtensions(); + } return(extensions); } + /** + * In the event the user did not specify a CLICS ID for the language, we have to make a guess. + * We use is the lower-case display name, minus spaces, and + changed to p, and compare to our known + * list of CLICS ids. + */ + private void setDefaultExtensions() + { + // Make lower case, get rid of spaces and convert all plus signs to p's (eg c++ -> cpp) + String fauxId = getDisplayName().toLowerCase().replaceAll("\\s", "").replaceAll("\\+", "p"); + // Let's use it as the clics ID + setID(fauxId); + // if it didn't work, then pretend we didn't try. + if(extensions.isEmpty()) { + id = null; + } + } + /** * Utility method to convert between a string array and ArrayList *