~codescore-dev/codescore/version-1.0

« back to all changes in this revision

Viewing changes to src/net/codescore/managers/CompetitionManager.java

  • Committer: Adam Cornett
  • Date: 2008-05-16 02:53:17 UTC
  • mfrom: (65.1.52 codescore)
  • Revision ID: adam.cornett@gmail.com-20080516025317-douek1kxjabvb3wu
Merged changes from my branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
import net.codescore.dbo.Team;
34
34
import net.codescore.dbo.TeamSubmission;
35
35
import net.codescore.exe.ExecutionResult;
 
36
import net.codescore.exe.GradingMode;
 
37
import net.codescore.exe.GradingThread;
 
38
import net.codescore.exe.ScoringMode;
36
39
import net.codescore.ui.SubUpdateListener;
37
 
import net.codescore.ui.admin.CompHome;
38
40
import net.codescore.ui.client.TeamHome;
39
41
 
 
42
/**
 
43
 * Manages a competition, providing methods to get competitions from the
 
44
 * database, and facilities for processing submissions, such as a grading queue
 
45
 * and accessor methods to the competition settings.
 
46
 * 
 
47
 * @author Adam Cornett
 
48
 */
40
49
public class CompetitionManager implements SubUpdateListener {
 
50
        /**
 
51
         * The last competition to be created
 
52
         * 
 
53
         * @deprecated
 
54
         */
41
55
        private static CompetitionManager activeCompetition;
42
 
 
 
56
        private static DataContext dc;
 
57
        /**
 
58
         * A map of linking a competition to its associated manager, used to prevent
 
59
         * a competition from having more than one associated manager
 
60
         */
 
61
        private static HashMap<Competition, CompetitionManager> managers =
 
62
                new HashMap<Competition, CompetitionManager>();
 
63
 
 
64
        /**
 
65
         * @return A list of all competitions, using the internal
 
66
         *         {@link DataContext}
 
67
         */
 
68
        public static List<Competition> getAllComps() {
 
69
                if (dc == null)
 
70
                        dc = DataContext.createDataContext();
 
71
                return getAllComps(dc);
 
72
        }
 
73
 
 
74
        /**
 
75
         * @param oc
 
76
         *            The context used to execute the query
 
77
         * @return A List of all competitions
 
78
         */
 
79
        public static List<Competition> getAllComps(ObjectContext oc) {
 
80
                NamedQuery nq = new NamedQuery("competitions_all");
 
81
                return oc.performQuery(nq);
 
82
        }
 
83
 
 
84
        /**
 
85
         * @param c
 
86
         *            The context used to search for the competition
 
87
         * @param name
 
88
         *            The name of the competition
 
89
         * @return The competition with the associated name
 
90
         */
43
91
        public static Competition getCompetitionByName(ObjectContext c, String name) {
44
92
                HashMap<String, Object> params = new HashMap<String, Object>();
45
93
                params.put("n", name);
53
101
                return (Competition) l.get(0);
54
102
        }
55
103
 
 
104
        /**
 
105
         * Uses the internal context to search for a competition
 
106
         * 
 
107
         * @param name
 
108
         *            The name of the competition to lookup
 
109
         * @return The competition with the given name
 
110
         */
 
111
        public static Competition getCompetitionByName(String name) {
 
112
                if (dc == null)
 
113
                        dc = DataContext.createDataContext();
 
114
                return getCompetitionByName(dc, name);
 
115
        }
 
116
 
 
117
        /**
 
118
         * @return The last manager associated with the most recently created
 
119
         *         competition
 
120
         * @deprecated
 
121
         */
56
122
        public static CompetitionManager getCurrent() {
57
123
                if (activeCompetition == null) {
58
124
                        ObjectContext oc = DataContext.createDataContext();
59
125
                        new CompetitionManager(getCompetitionByName(oc, "Test Competition"));
 
126
 
60
127
                }
61
128
                return activeCompetition;
62
129
        }
63
130
 
 
131
        /**
 
132
         * @param oc
 
133
         *            The context used to lookup a competition
 
134
         * @return The last registered competition
 
135
         * @deprecated
 
136
         */
64
137
        public static Competition getCurrent(ObjectContext oc) {
65
138
                if (activeCompetition == null)
66
139
                        activeCompetition =
73
146
                                activeCompetition.getCompetition().getObjectId());
74
147
        }
75
148
 
 
149
        /**
 
150
         * Get all currently running competitions using the internal context
 
151
         * 
 
152
         * @return A list of all competitions that are currently 'running': The
 
153
         *         competitions start time is before the current time, and the end
 
154
         *         time is after the current time.
 
155
         */
 
156
        public static List<Competition> getCurrentComps() {
 
157
                return getCurrentComps(DataContext.createDataContext());
 
158
        }
 
159
 
 
160
        /**
 
161
         * A list of all currently running competitions using the supplied context
 
162
         * 
 
163
         * @param oc
 
164
         *            The context to use when executing the query
 
165
         * @return A list of all competitions where the competition's start time is
 
166
         *         before the current time and its end time is after the current
 
167
         *         time.
 
168
         */
 
169
        public static List<Competition> getCurrentComps(ObjectContext oc) {
 
170
                NamedQuery nq = new NamedQuery("competitions_current");
 
171
                return oc.performQuery(nq);
 
172
        }
 
173
 
 
174
        /**
 
175
         * Get the associated manager for a competition. A new manager will be
 
176
         * created if one does not already exist for the given competition.
 
177
         * 
 
178
         * @param c
 
179
         *            The competition
 
180
         * @return The manager associated with the competition.
 
181
         */
 
182
        public static CompetitionManager getManager(Competition c) {
 
183
                if (managers.containsKey(c))
 
184
                        return managers.get(c);
 
185
                return new CompetitionManager(c);
 
186
 
 
187
        }
 
188
 
 
189
        /**
 
190
         * Lookup a submission for a given submission id (sid)
 
191
         * 
 
192
         * @param c
 
193
         *            The context to use for executing the query
 
194
         * @param sid
 
195
         *            The sid of the submission
 
196
         * @return The Team Submission with the associated sid
 
197
         */
76
198
        public static TeamSubmission getSubmission(ObjectContext c, int sid) {
77
199
                HashMap<String, Object> params = new HashMap<String, Object>();
78
200
                params.put("sid", sid);
85
207
                return (TeamSubmission) l.get(0);
86
208
        }
87
209
 
88
 
        private CompHome competitionHome;
89
 
 
90
210
        private volatile boolean compIsRunning;
91
211
        private Competition currentComp;
92
212
        private ConcurrentHashMap<Submission, ExecutionResult> gradeResults;
93
 
        private ConcurrentLinkedQueue<Submission> gradingQueue;
 
213
        private ConcurrentLinkedQueue<Submission> gradingQueue, practiceQueue;
94
214
        private List<GradingThread> gThreads;
95
215
        private ConcurrentLinkedQueue<Submission> judgingQueue;
96
216
        private Log log = LogFactory.getLog(CompetitionManager.class);
97
217
        private int numGradingThreads;
98
218
        private Map<Team, TeamHome> teamHomes;
 
219
        private GradingThread testThread;
99
220
 
 
221
        /**
 
222
         * Create a new manager.
 
223
         * 
 
224
         * @param c
 
225
         *            The competition the manager is associated with
 
226
         * @throws IllegalArgumentException
 
227
         *             If a manager already exists for the competition. Use
 
228
         *             {@link CompetitionManager#getManager(Competition)} to safely
 
229
         *             get a manager for a competition
 
230
         */
100
231
        public CompetitionManager(Competition c) {
 
232
                if (managers.containsKey(c)) {
 
233
                        throw new IllegalArgumentException("A manager for " + c
 
234
                                + " already exists, please use getManager(Competition)");
 
235
                }
 
236
                managers.put(c, this);
101
237
                if (activeCompetition == null) {
102
238
                        CompetitionManager.activeCompetition = this;
103
239
                }
104
240
                gradingQueue = new ConcurrentLinkedQueue<Submission>();
 
241
                practiceQueue = new ConcurrentLinkedQueue<Submission>();
105
242
                judgingQueue = new ConcurrentLinkedQueue<Submission>();
106
243
                gradeResults = new ConcurrentHashMap<Submission, ExecutionResult>();
107
244
                gThreads = new LinkedList<GradingThread>();
108
245
                teamHomes = new HashMap<Team, TeamHome>();
109
246
                this.setCurrentComp(c);
110
 
                competitionHome = new CompHome();
111
247
                compIsRunning = currentComp.getActive();
112
248
                SubmissionListener.registerCallback(this);
113
249
                if (getCompetition().getProp("num_graders") == null) {
115
251
                } else {
116
252
                        Integer i = (Integer) getCompetition().getProp("num_graders");
117
253
                        if (i == null)
118
 
                                numGradingThreads = 10;
 
254
                                numGradingThreads = 2;
119
255
                        else
120
256
                                numGradingThreads = i;
121
257
                }
 
258
                testThread = new GradingThread(this, GradingMode.PracticeSubmission);
 
259
                testThread.start();
 
260
                log.debug("Loaded:" + currentComp);
 
261
        }
 
262
 
 
263
        /**
 
264
         * When a submission has been graded, the result of the Grader is returned
 
265
         * here so that it can be reviewed by a judge.
 
266
         * 
 
267
         * @param s
 
268
         *            The submission which was graded
 
269
         * @param er
 
270
         *            The result of the grading
 
271
         */
 
272
        public void addGradeResult(Submission s, ExecutionResult er) {
 
273
                // If it is not a Judge's Solution, add the result to the list
 
274
                if (s instanceof TeamSubmission)
 
275
                        gradeResults.put(s, er);
 
276
                // If the status is still pending, send it to a judge
 
277
                if (s.getStatus() == null) {
 
278
                        judgingQueue.add(s);
 
279
                }
 
280
                s.getObjectContext().commitChanges();
122
281
        }
123
282
 
124
283
        /**
140
299
        }
141
300
 
142
301
        /**
 
302
         * Add a submission to the practice queue.<br />
 
303
         * If the queue already contains s, it will not be added again. The queue is
 
304
         * a FIFO queue.
 
305
         * 
 
306
         * @see ConcurrentLinkedQueue
 
307
         * @param s
 
308
         *            The submission to be added.
 
309
         */
 
310
        public void addSubmissionToPracticeQueue(Submission s) {
 
311
                // Don't add a submission if its already in the queue
 
312
                if (practiceQueue.contains(s))
 
313
                        return;
 
314
                log.info("Adding Submission to practice queue:" + s.getObjectId());
 
315
                practiceQueue.add(s);
 
316
        }
 
317
 
 
318
        /**
143
319
         * Removes dead graders from the list and ensures that the actual number of
144
320
         * active grading threads matches the expected number.
145
321
         */
146
322
        public void checkGThreads() {
147
 
                Iterator<GradingThread> gti = gThreads.iterator();
148
 
                while (gti.hasNext())
149
 
                        if (!gti.next().isAlive())
150
 
                                gti.remove();
151
 
                int expNum = numGradingThreads;
152
 
                numGradingThreads = gThreads.size();
153
 
                setNumGraders(expNum);
 
323
                checkGThreads(true);
 
324
        }
 
325
 
 
326
        /**
 
327
         * Dump debugging information to the log
 
328
         */
 
329
        public void debug() {
 
330
                log.debug(getCompetition());
 
331
                getCompetition().debug();
154
332
        }
155
333
 
156
334
        /**
205
383
                return false;
206
384
        }
207
385
 
 
386
        /**
 
387
         * @return The associated competition
 
388
         */
208
389
        public Competition getCompetition() {
209
390
                return this.currentComp;
210
391
        }
211
392
 
212
393
        /**
213
 
         * @return the compile_error_status
 
394
         * @return The <code>compile_error_status</code> property of the
 
395
         *         competition.
 
396
         * @see #getCompileError(ObjectContext)
214
397
         */
215
398
        public int getCompile_error_status() {
216
399
                Integer ces =
218
401
                return ces;
219
402
        }
220
403
 
 
404
        /**
 
405
         * @param oc
 
406
         *            The context used to get the ProblemStatus.
 
407
         * @return The problem status object signifying a compiler error for a
 
408
         *         submission.
 
409
         * @see #getCompile_error_status()
 
410
         */
221
411
        public ProblemStatus getCompileError(ObjectContext oc) {
222
412
                return DataObjectUtils.objectForPK(oc, ProblemStatus.class,
223
413
                        getCompile_error_status());
224
414
        }
225
415
 
 
416
        /**
 
417
         * @param oc
 
418
         *            The context used to get the ProblemStatus.
 
419
         * @return The problem status object signifying a correct submission.
 
420
         * @see #getCorrect_status()
 
421
         */
226
422
        public ProblemStatus getCorrect(ObjectContext oc) {
227
423
                return DataObjectUtils.objectForPK(oc, ProblemStatus.class,
228
424
                        getCorrect_status());
229
425
        }
230
426
 
231
427
        /**
232
 
         * @return the correct_status
 
428
         * @return The <code>correct_status</code> property of the competition
 
429
         * @see #getCorrect(ObjectContext)
233
430
         */
234
431
        public int getCorrect_status() {
235
432
                Integer cs = (Integer) getCompetition().getProp("correct_status");
243
440
                return (Integer) getCompetition().getProp("exe_timeout");
244
441
        }
245
442
 
 
443
        /**
 
444
         * @return The number of grading threads this competition should maintain
 
445
         */
246
446
        public int getNumGraders() {
247
447
                Integer db = (Integer) currentComp.getProp("num_graders");
248
448
                if (db != numGradingThreads)
250
450
                return numGradingThreads;
251
451
        }
252
452
 
253
 
        @SuppressWarnings("unchecked")
 
453
        /**
 
454
         * @return A list of submissions waiting to be graded
 
455
         */
254
456
        public List<Submission> getPendingSubs() {
255
457
                HashMap<String, Object> params = new HashMap<String, Object>();
256
458
                params.put("comp", getCompetition());
261
463
        }
262
464
 
263
465
        /**
264
 
         * @return the presentation_error_status
 
466
         * @return the <code>presentation_error_status</code> property of the
 
467
         *         competition
 
468
         * @see #getPresError(ObjectContext)
265
469
         */
266
470
        public int getPresentation_error_status() {
267
471
                Integer pes =
269
473
                return pes;
270
474
        }
271
475
 
 
476
        /**
 
477
         * @param oc
 
478
         *            The context used to get the ProblemStatus.
 
479
         * @return The problem status object signifying a presentational error in a
 
480
         *         submission
 
481
         * @see #getPresentation_error_status()
 
482
         */
272
483
        public ProblemStatus getPresError(ObjectContext oc) {
273
484
                return DataObjectUtils.objectForPK(oc, ProblemStatus.class,
274
485
                        getPresentation_error_status());
294
505
        }
295
506
 
296
507
        /**
297
 
         * @return the runtime_error_status
 
508
         * @return The <code>runtime_error_status</code> property of the
 
509
         *         competition.
 
510
         * @see #getRuntimeError(ObjectContext)
298
511
         */
299
512
        public int getRuntime_error_status() {
300
513
                Integer res =
302
515
                return res;
303
516
        }
304
517
 
 
518
        /**
 
519
         * @param oc
 
520
         *            The context used to get the ProblemStatus.
 
521
         * @return The problem status object signifying a runtime error in a
 
522
         *         submission.
 
523
         * @see #getRuntime_error_status()
 
524
         */
305
525
        public ProblemStatus getRuntimeError(ObjectContext oc) {
306
526
                return DataObjectUtils.objectForPK(oc, ProblemStatus.class,
307
527
                        getRuntime_error_status());
308
528
        }
309
529
 
 
530
        /**
 
531
         * Get the scoring mode for this competition.<br />
 
532
         * Stored in the <code>scoring_mode</code> competition property
 
533
         * 
 
534
         * @return The scoring mode for the associated competition
 
535
         */
 
536
        public ScoringMode getScoringMode() {
 
537
                return (ScoringMode) getCompetition().getProp("scoring_mode");
 
538
        }
 
539
 
 
540
        /**
 
541
         * @return The <code>test_status</code> property of the competition.
 
542
         * @see #getTestStatus(ObjectContext)
 
543
         */
 
544
        public int getTest_status() {
 
545
                Integer tes = (Integer) getCompetition().getProp("test_status");
 
546
                return tes;
 
547
        }
 
548
 
 
549
        /**
 
550
         * @param oc
 
551
         *            The context used to get the ProblemStatus.
 
552
         * @return The problem status signifying a problem should not be graded
 
553
         *         normally, but instead is a test submission.
 
554
         * @see #getTest_status()
 
555
         */
 
556
        public ProblemStatus getTestStatus(ObjectContext oc) {
 
557
                return DataObjectUtils.objectForPK(oc, ProblemStatus.class,
 
558
                        getTest_status());
 
559
        }
 
560
 
 
561
        /**
 
562
         * @return The <code>timelimit_error_status</code> property of the
 
563
         *         competition.
 
564
         * @see #getTimelimitError(ObjectContext)
 
565
         */
310
566
        public int getTimelimit_error_status() {
311
567
                Integer tes =
312
568
                        (Integer) getCompetition().getProp("timelimit_error_status");
313
569
                return tes;
314
570
        }
315
571
 
 
572
        /**
 
573
         * @param oc
 
574
         *            The context used to get the ProblemStatus.
 
575
         * @return The problem status signifying that a submission has exceeded the
 
576
         *         maximum time limit.
 
577
         * @see #getTimelimit_error_status()
 
578
         * @see #getExeTimeout()
 
579
         */
316
580
        public ProblemStatus getTimelimitError(ObjectContext oc) {
317
581
                return DataObjectUtils.objectForPK(oc, ProblemStatus.class,
318
582
                        getTimelimit_error_status());
319
583
        }
320
584
 
 
585
        /**
 
586
         * Tells the grading system if it should use the extra security precautions
 
587
         * while executing a submission.<br />
 
588
         * <b>This will cause the grader to fail currently as the security system
 
589
         * has not been implemented</b>
 
590
         * 
 
591
         * @return The <code>use_security</code> property of the competition
 
592
         */
321
593
        public boolean getUseSecurity() {
322
594
                return (Boolean) getCompetition().getProp("use_security");
323
595
        }
324
596
 
325
597
        /**
326
 
         * @return the wrong_output_status
 
598
         * @return The <code>wrong_output_status</code> property of the
 
599
         *         competition
 
600
         * @see #getWrongOutput(ObjectContext)
327
601
         */
328
602
        public int getWrong_output_status() {
329
603
                Integer wos = (Integer) getCompetition().getProp("wrong_output_status");
330
604
                return wos;
331
605
        }
332
606
 
 
607
        /**
 
608
         * @param oc
 
609
         *            The context used to get the ProblemStatus.
 
610
         * @return The problem status object signifying that a submission has the
 
611
         *         wrong output.
 
612
         * @see #getWrong_output_status()
 
613
         */
333
614
        public ProblemStatus getWrongOutput(ObjectContext oc) {
334
615
                return DataObjectUtils.objectForPK(oc, ProblemStatus.class,
335
616
                        getWrong_output_status());
347
628
 
348
629
        @Override
349
630
        public void onSubAdd(TeamSubmission s) {
350
 
                addSubmissionToGradeQueue(s);
 
631
                if (s.getStatus().equals(getTestStatus(s.getObjectContext())))
 
632
                        addSubmissionToPracticeQueue(s);
 
633
                else if (s.getStatus() == null)
 
634
                        addSubmissionToGradeQueue(s);
351
635
        }
352
636
 
353
637
        @Override
355
639
                return;
356
640
        }
357
641
 
 
642
        /**
 
643
         * Called by the grading thread to check if any submissions are waiting to
 
644
         * be graded.
 
645
         * 
 
646
         * @return A submission, or null if the queue is empty.
 
647
         */
 
648
        public Submission pollGradeQueue() {
 
649
                return gradingQueue.poll();
 
650
        }
 
651
 
 
652
        /**
 
653
         * Called by the grading thread to check if any submissions are waiting to
 
654
         * be run. This polls the practice queue, which is for submissions that are
 
655
         * not scored and are only fed the sample input.
 
656
         * 
 
657
         * @return A submission, or null if the queue is empty.
 
658
         */
 
659
        public Submission pollPracticeQueue() {
 
660
                return practiceQueue.poll();
 
661
        }
 
662
 
 
663
        /**
 
664
         * Registers a team home with the competition manager
 
665
         * 
 
666
         * @param th
 
667
         *            The team home to register
 
668
         * @deprecated
 
669
         */
358
670
        public void registerTeamHome(TeamHome th) {
359
671
                Team t = th.getController().getTeam();
360
672
                if (teamHomes.containsKey(t)) {
366
678
        }
367
679
 
368
680
        /**
369
 
         * All <b>ALL</b> submissions for this competition to the grading queue.<br />
 
681
         * Add <b>ALL</b> submissions for this competition to the grading queue.<br />
370
682
         * This method is used mainly for testing and has little real world use.
371
683
         */
372
684
        public void reGradeAllSubs() {
377
689
                        subs.addAll(p.getSubmissions());
378
690
                }
379
691
                for (TeamSubmission s : subs) {
 
692
                        if (s.getStatus() != null
 
693
                                && s.getStatus().equals(getTestStatus(s.getObjectContext())))
 
694
                                addSubmissionToPracticeQueue(s);
 
695
                        else
 
696
                                addSubmissionToGradeQueue(s);
380
697
                        s.setStatus(null);
381
698
                        s.setPoints(0);
382
699
                }
383
700
                currentComp.getObjectContext().commitChanges();
384
 
                for (TeamSubmission s : subs)
385
 
                        addSubmissionToGradeQueue(s);
 
701
 
386
702
        }
387
703
 
388
704
        /**
471
787
        public void setNumGraders(int num) {
472
788
                if (num <= 0)
473
789
                        throw new IllegalArgumentException("num must be greater than zero!");
 
790
                checkGThreads(false);
474
791
                if (num == numGradingThreads) {
475
792
                        return;
476
793
                } else if (num > numGradingThreads) {
487
804
                                numGradingThreads--;
488
805
                        }
489
806
                }
 
807
                numGradingThreads = num;
490
808
                if (gThreads.size() != numGradingThreads)
491
 
                        checkGThreads();
 
809
                        checkGThreads(true);
492
810
                getCompetition().setProp("num_graders", num);
 
811
 
493
812
        }
494
813
 
495
814
        /**
510
829
        }
511
830
 
512
831
        /**
 
832
         * Set the scoring mode to be used by the competition
 
833
         * 
 
834
         * @param mode
 
835
         *            The new scoring mode
 
836
         */
 
837
        public void setScoringMode(ScoringMode mode) {
 
838
                getCompetition().setProp("scoring_mode", mode);
 
839
        }
 
840
 
 
841
        /**
 
842
         * @param test_status
 
843
         *            the test_status to set
 
844
         */
 
845
        public void setTest_status(int test_status) {
 
846
                getCompetition().setProp("test_status", test_status);
 
847
        }
 
848
 
 
849
        /**
513
850
         * @param timelimit_error_status
514
851
         *            the timelimit_error_status to set
515
852
         */
518
855
                        timelimit_error_status);
519
856
        }
520
857
 
 
858
        /**
 
859
         * Set the <code>use_security</code> property.
 
860
         * 
 
861
         * @param on
 
862
         * @see #getUseSecurity()
 
863
         */
521
864
        public void setUseSecurity(boolean on) {
522
865
                getCompetition().setProp("use_security", on);
523
866
        }
535
878
                teamHomes.remove(t);
536
879
        }
537
880
 
 
881
        private void checkGThreads(boolean fix) {
 
882
                Iterator<GradingThread> gti = gThreads.iterator();
 
883
                while (gti.hasNext())
 
884
                        if (!gti.next().isAlive())
 
885
                                gti.remove();
 
886
                if (fix && numGradingThreads != gThreads.size()) {
 
887
                        int expNum = numGradingThreads;
 
888
                        numGradingThreads = gThreads.size();
 
889
                        setNumGraders(expNum);
 
890
                }
 
891
                numGradingThreads = gThreads.size();
 
892
        }
 
893
 
538
894
        private void initGThreads() {
539
895
                GradingThread gt;
540
896
                for (int i = 0; i < numGradingThreads; i++) {
545
901
        }
546
902
 
547
903
        /**
548
 
         * When a submission has been graded, the result of the Grader is returned
549
 
         * here so that it can be reviewed by a judge.
550
 
         * 
551
 
         * @param s
552
 
         *            The submission which was graded
553
 
         * @param er
554
 
         *            The result of the grading
555
 
         */
556
 
        protected void addGradeResult(Submission s, ExecutionResult er) {
557
 
                // If it is not a Judge's Solution, add the result to the list
558
 
                if (s instanceof TeamSubmission)
559
 
                        gradeResults.put(s, er);
560
 
                // If the status is still pending, send it to a judge
561
 
                if (s.getStatus() == null) {
562
 
                        judgingQueue.add(s);
563
 
                }
564
 
                s.getObjectContext().commitChanges();
565
 
        }
566
 
 
567
 
        /**
568
904
         * We need to make sure that we stop the grading thread for this competition
569
905
         * when we clean up this object, also deregisters the listeners.
570
906
         */
574
910
                for (GradingThread gt : gThreads)
575
911
                        gt.stopGrading();
576
912
        }
577
 
 
578
 
        /**
579
 
         * Called by the grading thread to check if any submissions are waiting to
580
 
         * be graded.
581
 
         * 
582
 
         * @return A submission, or null if the queue is empty.
583
 
         */
584
 
        protected Submission pollGradeQueue() {
585
 
                return gradingQueue.poll();
586
 
        }
587
913
}