diff --git a/projects/WTI-API/WebContent/WEB-INF/lib/pc2.jar b/projects/WTI-API/WebContent/WEB-INF/lib/pc2.jar
index 7e95cb343..bd2526848 100644
Binary files a/projects/WTI-API/WebContent/WEB-INF/lib/pc2.jar and b/projects/WTI-API/WebContent/WEB-INF/lib/pc2.jar differ
diff --git a/projects/WTI-API/src/main/controllers/ContestController.java b/projects/WTI-API/src/main/controllers/ContestController.java
index ddb9530be..13bfd8ca6 100644
--- a/projects/WTI-API/src/main/controllers/ContestController.java
+++ b/projects/WTI-API/src/main/controllers/ContestController.java
@@ -1,4 +1,4 @@
-// Copyright (C) 1989-2024 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau.
+// Copyright (C) 1989-2026 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau.
package controllers;
import java.io.IOException;
@@ -18,6 +18,7 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.XML;
@@ -25,7 +26,6 @@
import communication.WTIWebsocket;
import config.ServerInit;
import edu.csus.ecs.pc2.api.IClarification;
-import edu.csus.ecs.pc2.api.IClient;
import edu.csus.ecs.pc2.api.IContest;
import edu.csus.ecs.pc2.api.IContestClock;
import edu.csus.ecs.pc2.api.IJudgement;
@@ -60,16 +60,16 @@
/**
* This class acts as the MVC "Controller" for all accesses to the WTI endpoints related to obtaining information about
- * a specific contest -- that is, it is the managing Resource for all REST accesses to the "/contest" WTI API endpoint.
- *
+ * a specific contest -- that is, it is the managing Resource for all REST accesses to the "/contest" WTI API endpoint.
+ *
* The {@link MainController} parent class maintains a HashTable mapping currently logged-in teams
* to corresponding PC2 {@link ServerConnection} objects; when any reference to a sub-resource (such as "/contest/languages",
* "/contest/problems", etc.) is made, the sub-resource checks the connection hashtable for an entry for the requesting team;
* if found, the corresponding PC2 ServerConnection is invoked to obtain the requesting information.
- *
+ *
* The class is marked as @Singleton to insure that the Jetty webserver creates just one instance of the class to service
* all /contest requests (rather than having a new instance created for each incoming request).
- *
+ *
* @author EWU WTI Student Project team, with updates by John Clevenger, PC2 Development Team (pc2@ecs.csus.edu)
*
*/
@@ -79,39 +79,39 @@
@Authorization(value="sampleoauth", scopes = {})
})
public class ContestController extends MainController {
-
+
/**
* Key to enable filtering scoreboard by division.
*/
private static final String SERVER_WTI_BOARD_USE_DIVISIONS_KEY = "server.wtiBoardUseDivisions";
-
+
public final static String DEFAULT_PC2_SCOREBOARD_ACCOUNT = "scoreboard2";
public final static String DEFAULT_PC2_SCOREBOARD_PASSWORD = "scoreboard2";
-
+
//this boolean is reset false whenever a standings-changing event is received by the WTI scoreboard ServerConnection;
// it is updated to true whenever an access to the /scoreboard REST API endpoint causes the current standings to be updated
private boolean wtiServerStandingsAreCurrent = false;
-
+
//the current ("cached") copy of the scoreboard standings, converted to JSON from XML returned by {@link DefaultScoringAlgorithm#getStandings()}
private String currentJSONStandings ;
-
+
// Static vars -- must be initialized as soon as the class is loaded so that Jetty startup fails if
// PC2 Scoreboard login fails
-
+
//the ServerConnection used by the ContestController to connect to the PC2 server with a scoreboard account
private static ServerConnection scoreboardServerConn ;
-
+
//the DSA to be used by the /scoreboard endpoint for updating standings when requested
private static DefaultScoringAlgorithm dsa;
-
+
//mutex to insure at most one browser client at a time can attempt to use the above DSA to update standings
private static Boolean updateStandingsMutex = new Boolean(false);
-
+
/**
* Constructs a ContestController for the WTI server. Construction includes
* invoking the super-class {@link MainController}, constructor, which has the
* following effects:
- *
+ *
*
*
*
create an (initially empty) {@link HashMap} mapping team keys to {@link ServerConnection}s.
@@ -121,23 +121,23 @@ public class ContestController extends MainController {
*
The objects created by the superclass constructor are all "protected", making them accessible to this ContestController
* subclass.
*
- *
+ *
* In addition, this constructor creates a {@link ServerConnection} to the PC2 server (which must be running), and it logs into
* the PC2 server using the scoreboard credentials specified in the WTI configuration (pc2v9.ini file).
- *
+ *
* @throws URISyntaxException if a valid websocket could not be constructed in the {@link MainController} super-class from
* the initialization values specified in the WTI pc2v9.ini file.
* @throws LoginFailureException if the ContestController could not login to the PC2 server using the credentials specified in
* the WTI pc2v9.ini file.
- * @throws NotLoggedInException if the ContestController initialization block somehow successfully logged in but a subsequent
+ * @throws NotLoggedInException if the ContestController initialization block somehow successfully logged in but a subsequent
* check returns "not logged in".
*/
public ContestController() throws URISyntaxException, LoginFailureException, NotLoggedInException {
super();
-
+
//create a scoreboard account connection to the PC2 server
scoreboardServerConn = new ServerConnection();
-
+
//get the credentials to be used to login to the PC2 server, either those given in the WTI pc2v9.ini file or the defaults defined above
String sbAccount = ini.getScoreboardAccount();
if (sbAccount==null || sbAccount.equals("")) {
@@ -147,7 +147,7 @@ public ContestController() throws URISyntaxException, LoginFailureException, Not
if (sbPassword==null || sbPassword.equals("")) {
sbPassword = DEFAULT_PC2_SCOREBOARD_PASSWORD;
}
-
+
//login to the PC2 server
try {
scoreboardServerConn.login(sbAccount, sbPassword);
@@ -157,15 +157,15 @@ public ContestController() throws URISyntaxException, LoginFailureException, Not
// Theroretically.
logger.info("WTI Login failed for scoreboard account '" + sbAccount + "': " + e.getMessage());
throw new RuntimeException("WTI login failed for PC2 scoreboard account '" + sbAccount + "': " + e.getMessage()) ;
- }
-
+ }
+
//create a DefaultScoringAlgorithm to be used for computing standings
logger.fine("Constructing DSA for Contest Controller");
dsa = new DefaultScoringAlgorithm() ;
-
+
//insure that team clients only see FROZEN results when in a scoreboard freeze period
dsa.setObeyFreeze(true);
-
+
//add to the Scoreboard ServerConnection's contest a listener for each type of event which can change standings
try {
ScoreboardChangeListener sbListener = new ScoreboardChangeListener(this, client);
@@ -182,21 +182,21 @@ public ContestController() throws URISyntaxException, LoginFailureException, Not
/***
* Languages gets all the languages in the PC^2 contest.
- *
- * @param key a String containing a key which uniquely identifies the team making the request.
+ *
+ * @param key a String containing a key which uniquely identifies the team making the request.
* The value of "key" is obtained from the HTTP header parameter "team_id".
- *
+ *
* @return Response of:
* 401 (unauthorized) if team's credentials are incorrect (i.e. the team is not logged in);
* 500 (INTERNAL_SERVER_ERROR) if an error occurs in fetching the requested data from the PC2 server;
* otherwise 200 (OK) and a JSON string containing an array of {@link ILanguage}s is returned.
- */
+ */
@Path("/languages")
@GET
@ApiOperation(value = "languages",
notes = "Gets languages used within PC^2 contest.")
@ApiResponses({
- @ApiResponse(code = 200, message = "Returns list of languages.", response = LanguageModel.class),
+ @ApiResponse(code = 200, message = "Returns list of languages.", response = LanguageModel.class),
@ApiResponse(code = 401, message = "Returned if invalid credentials are supplied", response = ServerErrorResponseModel.class),
@ApiResponse(code = 500, message = "Return if server is having trouble handling request", response = ServerErrorResponseModel.class)
})
@@ -214,7 +214,7 @@ public Response languages(
//the list of languages to be returned
List languages = new ArrayList();
-
+
try {
ILanguage[] langs = userInformation.getContest().getLanguages();
for(ILanguage lang : langs)
@@ -232,7 +232,7 @@ public Response languages(
.entity(new ServerErrorResponseModel(Response.Status.INTERNAL_SERVER_ERROR, "NullPointerException in ContestController.languages()"))
.type(MediaType.APPLICATION_JSON).build();
}
-
+
return Response.ok()
.entity(languages)
.type(MediaType.APPLICATION_JSON).build();
@@ -240,21 +240,21 @@ public Response languages(
/**
* Judgements gets all the possible judgments in the PC^2 contest -- that is, a list containing every judgement which could be assigned to a submission.
- *
- * @param key a String containing a key which uniquely identifies the team making the request.
+ *
+ * @param key a String containing a key which uniquely identifies the team making the request.
* The value of "key" is obtained from the HTTP header parameter "team_id".
- *
+ *
* @return Response of:
* 401 (unauthorized) if team's credentials are incorrect (i.e. the team is not logged in);
* 500 (INTERNAL_SERVER_ERROR) if an error occurs in fetching the requested data from the PC2 server;
* otherwise 200 (OK) and a JSON string containing an array of {@link IJudgement}s is returned.
- */
+ */
@Path("/judgements")
@GET
@ApiOperation(value = "judgements",
notes = "Gets judgements used within PC^2 contest.")
@ApiResponses({
- @ApiResponse(code = 200, message = "Returns list of judgements.", response = String.class),
+ @ApiResponse(code = 200, message = "Returns list of judgements.", response = String.class),
@ApiResponse(code = 401, message = "Returned if invalid credentials are supplied", response = ServerErrorResponseModel.class)
})
public Response judgements(
@@ -288,23 +288,23 @@ public Response judgements(
.entity(new ServerErrorResponseModel(Response.Status.INTERNAL_SERVER_ERROR, "NullPointerException in ContestController.judgements()"))
.type(MediaType.APPLICATION_JSON).build();
}
-
+
return Response.ok()
.entity(judgements)
.type(MediaType.APPLICATION_JSON).build();
}
/***
- * This method returns a list of all the problems in the PC^2 contest. It first checks to see that the
+ * This method returns a list of all the problems in the PC^2 contest. It first checks to see that the
* user (team) specified by the received "key" is currently logged in and that the contest is running
* (contest problems are only allowed to be viewed when the contest is running). If so, the method
* returns the current contest problems, obtained from the PC2 {@link ServerConnection} for the team.
- *
+ *
* Note that only NON-HIDDEN problems are returned.
- *
- * @param key a String containing a key which uniquely identifies the team making the request.
+ *
+ * @param key a String containing a key which uniquely identifies the team making the request.
* The value of "key" is obtained from the HTTP header parameter "team_id".
- *
+ *
* @return Response of:
* 401 (unauthorized) if team's credentials are incorrect (i.e. the team is not logged in or is not allowed to make such a request);
* 500 (INTERNAL_SERVER_ERROR) if an error occurs in fetching the requested data from the PC2 server;
@@ -315,7 +315,7 @@ public Response judgements(
@ApiOperation(value = "problems",
notes = "Gets problems used within PC^2 contest.")
@ApiResponses({
- @ApiResponse(code = 200, message = "Returns list of problems.", response = ProblemModel.class),
+ @ApiResponse(code = 200, message = "Returns list of problems.", response = ProblemModel.class),
@ApiResponse(code = 401, message = "Returned if invalid credentials are supplied or the contest is not running", response = ServerErrorResponseModel.class)
})
public Response problems(
@@ -323,7 +323,7 @@ public Response problems(
//get the PC2 server connection information for the team
ServerConnection userInformation = connections.get(key);
-
+
//verify the user is logged in and the contest is running
try {
// make sure we have connection information for this user (i.e. that the user is logged in)
@@ -368,19 +368,19 @@ public Response problems(
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(new ServerErrorResponseModel(Response.Status.INTERNAL_SERVER_ERROR, "NullPointerException in ContestController.problems()"))
.type(MediaType.APPLICATION_JSON).build();
- }
-
+ }
+
return Response.ok()
.entity(problems)
.type(MediaType.APPLICATION_JSON).build();
}
-
+
/***
* This method returns an indication of whether the contest clock is currently running.
- *
- * @param key a String containing a key which uniquely identifies the team making the request.
+ *
+ * @param key a String containing a key which uniquely identifies the team making the request.
* The value of "key" is obtained from the HTTP header parameter "team_id".
- *
+ *
* @return Response of:
* 401 (unauthorized) if team's credentials are incorrect (i.e. the team is not logged in or is not allowed to make such a request);
* 500 (INTERNAL_SERVER_ERROR) if an error occurs in fetching the requested data from the PC2 server;
@@ -391,7 +391,7 @@ public Response problems(
@ApiOperation(value = "isRunning",
notes = "Get the state of the contest if it is running of not")
@ApiResponses({
- @ApiResponse(code = 200, message = "Returns a boolean true or false", response = Boolean.class),
+ @ApiResponse(code = 200, message = "Returns a boolean true or false", response = Boolean.class),
@ApiResponse(code = 401, message = "Returned if invalid credentials are supplied", response = ServerErrorResponseModel.class)
})
public Response isRunning(
@@ -403,9 +403,9 @@ public Response isRunning(
return Response.status(Response.Status.UNAUTHORIZED)
.entity(new ServerErrorResponseModel(Response.Status.UNAUTHORIZED, "Unauthorized user request"))
.type(MediaType.APPLICATION_JSON).build();
-
+
try {
-
+
isRunning = userInformation.getContest().getContestClock().isContestClockRunning();
}
catch(NotLoggedInException e) {
@@ -417,22 +417,22 @@ public Response isRunning(
.entity(new ServerErrorResponseModel(Response.Status.INTERNAL_SERVER_ERROR, "Unauthorized user request"))
.type(MediaType.APPLICATION_JSON).build();
}
-
+
return Response.ok()
.entity(isRunning)
.type(MediaType.APPLICATION_JSON).build();
}
-
+
/***
- * This method returns a "ContestClock" object encapsulating the current state of the PC2 contest clock
- * as maintained by the PC2 class "ContestTime".
+ * This method returns a "ContestClock" object encapsulating the current state of the PC2 contest clock
+ * as maintained by the PC2 class "ContestTime".
* It first checks to see that the user (team) specified by the received "key" is currently logged in. If so, the method
* returns the current contest time information, obtained from the PC2 {@link ServerConnection} for the team.
- *
- * @param key a String containing a key which uniquely identifies the team making the request.
+ *
+ * @param key a String containing a key which uniquely identifies the team making the request.
* The value of "key" is obtained from the HTTP header parameter "team_id".
- *
+ *
* @return Response of:
* 401 (unauthorized) if team's credentials are incorrect (i.e. the team is not logged in or is not allowed to make such a request);
* 500 (INTERNAL_SERVER_ERROR) if an error occurs in fetching the requested data from the PC2 server;
@@ -443,11 +443,11 @@ public Response isRunning(
@ApiOperation(value = "contestclock",
notes = "Gets the PC2 contest clock (time info).")
@ApiResponses({
- @ApiResponse(code = 200, message = "Returns a contest clock object.", response = ContestClockModel.class),
+ @ApiResponse(code = 200, message = "Returns a contest clock object.", response = ContestClockModel.class),
@ApiResponse(code = 401, message = "Returned if invalid credentials are supplied", response = ServerErrorResponseModel.class)
})
- public Response contestClock(@ApiParam(value="token used by logged in users to access teams information",
+ public Response contestClock(@ApiParam(value="token used by logged in users to access teams information",
required = true) @HeaderParam("team_id")String key) {
if (connections == null) {
@@ -462,20 +462,20 @@ public Response contestClock(@ApiParam(value="token used by logged in users to a
// make sure we have connection information for this user (i.e. that the user is logged in)
if (userInformation == null) {
throw new NotLoggedInException();
- }
+ }
} catch (NotLoggedInException e1) {
return Response.status(Response.Status.UNAUTHORIZED)
.entity(new ServerErrorResponseModel(Response.Status.UNAUTHORIZED, "Unauthorized user request"))
.type(MediaType.APPLICATION_JSON).build();
}
-
+
//the ContestClock object to be returned in the response to the HTTP request
ContestClockModel returnableContestClock ;
-
+
try {
//get the contest clock from the PC2 Server via the PC2 API ServerConnection
// IContestClock contestClock = userInformation.getContest().getContestClock();
-
+
IContest contest = userInformation.getContest();
if (contest == null) {
System.err.println ("SEVERE: ContestController.contestClock(): ServerConnection.getContest() returned null!");
@@ -488,7 +488,7 @@ public Response contestClock(@ApiParam(value="token used by logged in users to a
logger.severe("ContestController.contestClock(): ServerConnection.getContest().getContestClock() returned null!");
throw new NullPointerException("ServerConnection.getContest().getContestClock() returned null in ContestController.contestClock()");
}
-
+
//retrieve the relevant fields from the PC2 contest clock
boolean isRunning = contestClock.isContestClockRunning();
long contestLengthSecs = contestClock.getContestLengthSecs();
@@ -501,10 +501,10 @@ public Response contestClock(@ApiParam(value="token used by logged in users to a
} else {
wallClockStartTime = startTimeCalendar.getTimeInMillis();
}
-
+
//construct a ContestClock containing the PC2 Server clock values
returnableContestClock = new ContestClockModel(isRunning,contestLengthSecs, elapsedSecs, wallClockStartTime);
-
+
}
catch(NotLoggedInException e) {
return Response.status(Response.Status.UNAUTHORIZED)
@@ -516,24 +516,24 @@ public Response contestClock(@ApiParam(value="token used by logged in users to a
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(new ServerErrorResponseModel(Response.Status.INTERNAL_SERVER_ERROR, "NullPointerException in ContestController.contestClock()"))
.type(MediaType.APPLICATION_JSON).build();
- }
-
+ }
+
//return the PC2 ContestClock, mapped into JSON
return Response.ok()
.entity(returnableContestClock)
.type(MediaType.APPLICATION_JSON).build();
}
-
+
/***
- * This method returns a list of all the clarifications in the PC^2 contest which the requesting client is allowed to see.
+ * This method returns a list of all the clarifications in the PC^2 contest which the requesting client is allowed to see.
* It first checks to see that the user (team) specified by the received "key" is currently logged in. If so, the method
* returns the current team's clarifications, obtained from the PC2 {@link ServerConnection} for the team.
- *
+ *
* Note that only clarifications which are allowed to be viewed by the requesting client are returned.
- *
- * @param key a String containing a key which uniquely identifies the team making the request.
+ *
+ * @param key a String containing a key which uniquely identifies the team making the request.
* The value of "key" is obtained from the HTTP header parameter "team_id".
- *
+ *
* @return Response of:
* 401 (unauthorized) if team's credentials are incorrect (i.e. the team is not logged in or is not allowed to make such a request);
* 500 (INTERNAL_SERVER_ERROR) if an error occurs in fetching the requested data from the PC2 server;
@@ -544,15 +544,15 @@ public Response contestClock(@ApiParam(value="token used by logged in users to a
@ApiOperation(value = "clarifications",
notes = "Gets all clarifications submitted in PC^2 contest.")
@ApiResponses({
- @ApiResponse(code = 200, message = "Returns list of clarifications.", response = ClarificationModel.class),
+ @ApiResponse(code = 200, message = "Returns list of clarifications.", response = ClarificationModel.class),
@ApiResponse(code = 401, message = "Returned if invalid credentials are supplied", response = ServerErrorResponseModel.class)
})
- public Response clarifications(@ApiParam(value="token used by logged in users to access teams information",
+ public Response clarifications(@ApiParam(value="token used by logged in users to access teams information",
required = true) @HeaderParam("team_id")String key) {
ServerConnection userInformation = connections.get(key);
-
+
//verify that the user is logged in
try {
// make sure we have connection information for this user (i.e. that the user is logged in)
@@ -567,22 +567,22 @@ public Response clarifications(@ApiParam(value="token used by logged in users to
//a list of the contest clarifications to be returned
List clarifications = new ArrayList();
-
+
try {
-
+
//get the clarifications associated with the invoking client's Id.
//Note that getClarificationsWithClientId() returns exactly, and only, clarifications that the current Client should receive.
//This includes clars that were submitted by the team as well as announcement clars directed to the team -- either
//specifically or as a result of being directed to "All Teams" or to a Group of which the team is a member.
IClarification[] clars = userInformation.getContest().getClarificationsWithClientId();
-
+
//encode each PC2 clar into a WTI ClarificationModel
for(IClarification clar : clars) {
-
+
//holders for the lists of recipient teams and groups (if any)
ArrayList teamRecipientList = new ArrayList();
ArrayList groupRecipientList = new ArrayList();
-
+
//find the teams (if any) and groups (if any) to whom the answer to this clar (if any) was sent
if (clar.isAnswered()) {
@@ -598,10 +598,10 @@ public Response clarifications(@ApiParam(value="token used by logged in users to
groupRecipientList.add(groupName);
}
}
-
+
// set the "recipient type" indicating whether this clar goes to the team because it was "sent to all",
// because it was sent to several teams including this team or a group containing this team,
- // or it was sent only to this team. (The "recipient type" is used by the WTI-UI
+ // or it was sent only to this team. (The "recipient type" is used by the WTI-UI
// to determine under what conditions to display the clar on the Clarifications page.)
String recipientType = "";
if (clar.isAnswered()) {
@@ -617,14 +617,14 @@ public Response clarifications(@ApiParam(value="token used by logged in users to
recipientType = "No Answer Yet";
}
clarifications.add(new ClarificationModel(
- recipientType,
+ recipientType,
teamRecipientList,
groupRecipientList,
- clar.getProblem().getName(),
- clar.getQuestion(),
+ clar.getProblem().getName(),
+ clar.getQuestion(),
clar.getAnswer(),
String.format("%s-%s", clar.getSiteNumber(), clar.getNumber()), //notional "id" for the clar
- clar.getSubmissionTime(),
+ clar.getSubmissionTime(),
clar.isAnswered()));
}
}
@@ -645,39 +645,39 @@ public Response clarifications(@ApiParam(value="token used by logged in users to
.entity(new ServerErrorResponseModel(Response.Status.INTERNAL_SERVER_ERROR, "Exception in ContestController.clarifications(): " + e.getMessage()))
.type(MediaType.APPLICATION_JSON).build();
}
-
-
+
+
return Response.ok()
.entity(clarifications)
.type(MediaType.APPLICATION_JSON).build();
}
-
+
/***
* This method returns the current contest scoreboard standings as a JSON string.
- *
- * The returned JSON string is constructed by first making a call to
+ *
+ * The returned JSON string is constructed by first making a call to
* {@link DefaultScoringAlgorithm#getStandings(edu.csus.ecs.pc2.core.model.IInternalContest, Properties, edu.csus.ecs.pc2.core.log.Log)},
- * which returns an XML document whose format is documented at
+ * which returns an XML document whose format is documented at
* this URL.
* This XML string is then converted to JSON before being returned to the caller.
- *
+ *
* The ContestController caches the scoreboard standings JSON each time they are updated; if standings have not changed
* since the last call to this endpoint then the cached copy is returned rather than making a new call to {@link DefaultScoringAlgorithm}.
- *
- * @param key a String containing a key which uniquely identifies the team making the request.
+ *
+ * @param key a String containing a key which uniquely identifies the team making the request.
* The value of "key" is obtained from the HTTP header parameter "team_id".
*
* @return Response of:
* 401 (unauthorized) if team's credentials are incorrect (i.e. the team is not logged in or is not allowed to make such a request);
* 500 (INTERNAL_SERVER_ERROR) if an error occurs either within this ContestController or in fetching the requested data from the PC2 server;
* otherwise 200 (OK) and a JSON string containing {@link edu.csus.ecs.pc2.core.scoring.Standings}s is returned.
- */
+ */
@Path("/scoreboard")
@GET
@ApiOperation(value = "scoreboard",
notes = "Gets current scoreboard standings in the contest.")
@ApiResponses({
- @ApiResponse(code = 200, message = "Returns XML standings.", response = String.class),
+ @ApiResponse(code = 200, message = "Returns XML standings.", response = String.class),
@ApiResponse(code = 401, message = "Returned if invalid credentials are supplied", response = ServerErrorResponseModel.class),
@ApiResponse(code = 500, message = "Return if server is having trouble handling request", response = ServerErrorResponseModel.class)
})
@@ -685,7 +685,7 @@ public Response getStandings(
@ApiParam(value="token used by logged in users to access team information", required = true) @HeaderParam("team_id")String key) {
logger.fine("Looking up team login connection");
-
+
ServerConnection userInformation = connections.get(key);
// make sure we have connection information for this user (i.e. that the user is logged in)
@@ -703,17 +703,17 @@ public Response getStandings(
.entity(new ServerErrorResponseModel(Response.Status.INTERNAL_SERVER_ERROR, "DefaultScoringAlgorithm in null in ContestController"))
.type(MediaType.APPLICATION_JSON).build();
}
-
+
try {
logger.info("Standings requested by team " + userInformation.getMyClient().getLoginName());
-
+
xlog(logger, "debug 22 Start" );
-
+
//insure that only one browser client at a time can attempt to use the DSA to update standings
synchronized (updateStandingsMutex) {
-
+
// check if some event has occurred which could have changed the standings
-
+
/**
* Should scoreboaed only show the teams in a team's division?
*/
@@ -736,7 +736,7 @@ public Response getStandings(
if (!wtiServerStandingsAreCurrent) {
logger.info("Standings are not current; invoking DSA to update");
-
+
// Standings could have changed; try to get the actual InternalContest so
// we can use it to get updated standings
@@ -757,12 +757,12 @@ public Response getStandings(
if (props != null) {
Set