Moved the creation of games and broadcasting outside of tournament lock to prevent theoretical deadlocks. These actions are now made through a list of actions returned from tournament advance method.
This commit is contained in:
@@ -12,6 +12,9 @@ import com.gempukku.lotro.draft.DraftPack;
|
||||
import com.gempukku.lotro.game.*;
|
||||
import com.gempukku.lotro.logic.vo.LotroDeck;
|
||||
import com.gempukku.lotro.packs.ProductLibrary;
|
||||
import com.gempukku.lotro.tournament.action.BroadcastAction;
|
||||
import com.gempukku.lotro.tournament.action.CreateGameAction;
|
||||
import com.gempukku.lotro.tournament.action.TournamentProcessAction;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -288,47 +291,45 @@ public class DefaultTournament implements Tournament {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean advanceTournament(TournamentCallback tournamentCallback, CollectionsManager collectionsManager) {
|
||||
public List<TournamentProcessAction> advanceTournament(CollectionsManager collectionsManager) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
boolean result = false;
|
||||
List<TournamentProcessAction> result = new LinkedList<>();
|
||||
if (_nextTask == null) {
|
||||
if (_tournamentStage == Stage.DRAFT) {
|
||||
_draft.advanceDraft(tournamentCallback);
|
||||
// Temporary - don't want to involve draft in this
|
||||
_draft.advanceDraft(null);
|
||||
if (_draft.isFinished()) {
|
||||
tournamentCallback.broadcastMessage("Drafting in tournament " + _tournamentName + " is finished, starting deck building");
|
||||
result.add(new BroadcastAction("Drafting in tournament " + _tournamentName + " is finished, starting deck building"));
|
||||
_tournamentStage = Stage.DECK_BUILDING;
|
||||
_tournamentService.updateTournamentStage(_tournamentId, _tournamentStage);
|
||||
_deckBuildStartTime = System.currentTimeMillis();
|
||||
_draft = null;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
if (_tournamentStage == Stage.DECK_BUILDING) {
|
||||
if (_deckBuildStartTime + DeckBuildTime < System.currentTimeMillis()
|
||||
if (_deckBuildStartTime + DeckBuildTime > System.currentTimeMillis()
|
||||
|| _playerDecks.size() == _players.size()) {
|
||||
_tournamentStage = Stage.PLAYING_GAMES;
|
||||
_tournamentService.updateTournamentStage(_tournamentId, _tournamentStage);
|
||||
result = true;
|
||||
result.add(new BroadcastAction("Deck building in tournament " + _tournamentName + " has finished"));
|
||||
}
|
||||
}
|
||||
if (_tournamentStage == Stage.PLAYING_GAMES) {
|
||||
if (_currentlyPlayingPlayers.isEmpty()) {
|
||||
if (_pairingMechanism.isFinished(_tournamentRound, _players, _droppedPlayers)) {
|
||||
finishTournament(tournamentCallback, collectionsManager);
|
||||
result.add(finishTournament(collectionsManager));
|
||||
} else {
|
||||
tournamentCallback.broadcastMessage("Tournament " + _tournamentName + " will start round "+(_tournamentRound+1)+" in 1 minute.");
|
||||
result.add(new BroadcastAction("Tournament " + _tournamentName + " will start round "+(_tournamentRound+1)+" in 1 minute."));
|
||||
_nextTask = new PairPlayers();
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_nextTask != null && _nextTask.getExecuteAfter() <= System.currentTimeMillis()) {
|
||||
TournamentTask task = _nextTask;
|
||||
_nextTask = null;
|
||||
task.executeTask(tournamentCallback, collectionsManager);
|
||||
result = true;
|
||||
task.executeTask(result, collectionsManager);
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
@@ -351,11 +352,11 @@ public class DefaultTournament implements Tournament {
|
||||
}
|
||||
}
|
||||
|
||||
private void finishTournament(TournamentCallback tournamentCallback, CollectionsManager collectionsManager) {
|
||||
private TournamentProcessAction finishTournament(CollectionsManager collectionsManager) {
|
||||
_tournamentStage = Stage.FINISHED;
|
||||
_tournamentService.updateTournamentStage(_tournamentId, _tournamentStage);
|
||||
tournamentCallback.broadcastMessage("Tournament " + _tournamentName + " is finished");
|
||||
awardPrizes(collectionsManager);
|
||||
return new BroadcastAction("Tournament " + _tournamentName + " is finished");
|
||||
}
|
||||
|
||||
private void awardPrizes(CollectionsManager collectionsManager) {
|
||||
@@ -370,12 +371,12 @@ public class DefaultTournament implements Tournament {
|
||||
}
|
||||
}
|
||||
|
||||
private void createNewGame(TournamentCallback tournamentCallback, String playerOne, String playerTwo) {
|
||||
tournamentCallback.createGame(playerOne, _playerDecks.get(playerOne),
|
||||
private TournamentProcessAction createNewGame(String playerOne, String playerTwo) {
|
||||
return new CreateGameAction(playerOne, _playerDecks.get(playerOne),
|
||||
playerTwo, _playerDecks.get(playerTwo));
|
||||
}
|
||||
|
||||
private void doPairing(TournamentCallback tournamentCallback, CollectionsManager collectionsManager) {
|
||||
private void doPairing(List<TournamentProcessAction> actions, CollectionsManager collectionsManager) {
|
||||
_tournamentRound++;
|
||||
_tournamentService.updateTournamentRound(_tournamentId, _tournamentRound);
|
||||
Map<String, String> pairingResults = new HashMap<>();
|
||||
@@ -386,7 +387,7 @@ public class DefaultTournament implements Tournament {
|
||||
boolean finished = _pairingMechanism.pairPlayers(_tournamentRound, _players, _droppedPlayers, _playerByes,
|
||||
getCurrentStandings(), previouslyPaired, pairingResults, byeResults);
|
||||
if (finished) {
|
||||
finishTournament(tournamentCallback, collectionsManager);
|
||||
actions.add(finishTournament(collectionsManager));
|
||||
} else {
|
||||
for (Map.Entry<String, String> pairing : pairingResults.entrySet()) {
|
||||
String playerOne = pairing.getKey();
|
||||
@@ -394,11 +395,11 @@ public class DefaultTournament implements Tournament {
|
||||
_tournamentService.addMatch(_tournamentId, _tournamentRound, playerOne, playerTwo);
|
||||
_currentlyPlayingPlayers.add(playerOne);
|
||||
_currentlyPlayingPlayers.add(playerTwo);
|
||||
createNewGame(tournamentCallback, playerOne, playerTwo);
|
||||
actions.add(createNewGame(playerOne, playerTwo));
|
||||
}
|
||||
|
||||
if (!byeResults.isEmpty()) {
|
||||
tournamentCallback.broadcastMessage("Bye awarded to: "+ StringUtils.join(byeResults, ", "));
|
||||
actions.add(new BroadcastAction("Bye awarded to: "+ StringUtils.join(byeResults, ", ")));
|
||||
}
|
||||
|
||||
for (String bye : byeResults) {
|
||||
@@ -424,8 +425,8 @@ public class DefaultTournament implements Tournament {
|
||||
private final long _taskStart = System.currentTimeMillis() + PairingDelayTime;
|
||||
|
||||
@Override
|
||||
public void executeTask(TournamentCallback tournamentCallback, CollectionsManager collectionsManager) {
|
||||
doPairing(tournamentCallback, collectionsManager);
|
||||
public void executeTask(List<TournamentProcessAction> actions, CollectionsManager collectionsManager) {
|
||||
doPairing(actions, collectionsManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -442,11 +443,11 @@ public class DefaultTournament implements Tournament {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeTask(TournamentCallback tournamentCallback, CollectionsManager collectionsManager) {
|
||||
public void executeTask(List<TournamentProcessAction> actions, CollectionsManager collectionsManager) {
|
||||
for (Map.Entry<String, String> pairings : _gamesToCreate.entrySet()) {
|
||||
String playerOne = pairings.getKey();
|
||||
String playerTwo = pairings.getValue();
|
||||
createNewGame(tournamentCallback, playerOne, playerTwo);
|
||||
actions.add(createNewGame(playerOne, playerTwo));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,9 @@ import com.gempukku.lotro.competitive.PlayerStanding;
|
||||
import com.gempukku.lotro.db.vo.CollectionType;
|
||||
import com.gempukku.lotro.draft.Draft;
|
||||
import com.gempukku.lotro.game.CardNotFoundException;
|
||||
import com.gempukku.lotro.game.LotroCardBlueprintLibrary;
|
||||
import com.gempukku.lotro.game.SortAndFilterCards;
|
||||
import com.gempukku.lotro.game.formats.LotroFormatLibrary;
|
||||
import com.gempukku.lotro.logic.vo.LotroDeck;
|
||||
import com.gempukku.lotro.packs.ProductLibrary;
|
||||
import com.gempukku.lotro.tournament.action.TournamentProcessAction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -75,7 +73,7 @@ public interface Tournament {
|
||||
public int getPlayersInCompetitionCount();
|
||||
public String getPlayerList();
|
||||
|
||||
public boolean advanceTournament(TournamentCallback tournamentCallback, CollectionsManager collectionsManager);
|
||||
public List<TournamentProcessAction> advanceTournament(CollectionsManager collectionsManager);
|
||||
|
||||
public void reportGameFinished(String winner, String loser);
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.gempukku.lotro.hall.HallServer;
|
||||
import com.gempukku.lotro.logic.vo.LotroDeck;
|
||||
import com.gempukku.lotro.packs.DraftPackStorage;
|
||||
import com.gempukku.lotro.packs.ProductLibrary;
|
||||
import com.gempukku.lotro.tournament.action.TournamentProcessAction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
@@ -169,7 +170,12 @@ public class TournamentService {
|
||||
var tourneyID = entry.getKey();
|
||||
var tourney = entry.getValue();
|
||||
|
||||
tournamentsChanged |= tourney.advanceTournament(hall.getTournamentCallback(tourney), _collectionsManager);
|
||||
TournamentCallback tournamentCallback = hall.getTournamentCallback(tourney);
|
||||
List<TournamentProcessAction> actions = tourney.advanceTournament(_collectionsManager);
|
||||
tournamentsChanged |= !actions.isEmpty();
|
||||
for (TournamentProcessAction action : actions) {
|
||||
action.process(tournamentCallback);
|
||||
}
|
||||
if (tourney.getTournamentStage() == Tournament.Stage.FINISHED)
|
||||
_activeTournaments.remove(tourneyID);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package com.gempukku.lotro.tournament;
|
||||
|
||||
import com.gempukku.lotro.collection.CollectionsManager;
|
||||
import com.gempukku.lotro.tournament.action.TournamentProcessAction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TournamentTask {
|
||||
public void executeTask(TournamentCallback tournamentCallback, CollectionsManager collectionsManager);
|
||||
public void executeTask(List<TournamentProcessAction> actions, CollectionsManager collectionsManager);
|
||||
|
||||
public long getExecuteAfter();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.gempukku.lotro.tournament.action;
|
||||
|
||||
import com.gempukku.lotro.tournament.TournamentCallback;
|
||||
|
||||
public class BroadcastAction implements TournamentProcessAction {
|
||||
private final String message;
|
||||
|
||||
public BroadcastAction(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(TournamentCallback callback) {
|
||||
callback.broadcastMessage(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.gempukku.lotro.tournament.action;
|
||||
|
||||
import com.gempukku.lotro.logic.vo.LotroDeck;
|
||||
import com.gempukku.lotro.tournament.TournamentCallback;
|
||||
|
||||
public class CreateGameAction implements TournamentProcessAction{
|
||||
private String playerOne;
|
||||
private LotroDeck playerOneDeck;
|
||||
private String playerTwo;
|
||||
private LotroDeck playerTwoDeck;
|
||||
|
||||
public CreateGameAction(String playerOne, LotroDeck playerOneDeck, String playerTwo, LotroDeck playerTwoDeck) {
|
||||
this.playerOne = playerOne;
|
||||
this.playerOneDeck = playerOneDeck;
|
||||
this.playerTwo = playerTwo;
|
||||
this.playerTwoDeck = playerTwoDeck;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(TournamentCallback callback) {
|
||||
callback.createGame(playerOne, playerOneDeck, playerTwo, playerTwoDeck);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.gempukku.lotro.tournament.action;
|
||||
|
||||
import com.gempukku.lotro.tournament.TournamentCallback;
|
||||
|
||||
public interface TournamentProcessAction {
|
||||
void process(TournamentCallback callback);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import com.gempukku.lotro.db.vo.CollectionType;
|
||||
import com.gempukku.lotro.draft.DraftPack;
|
||||
import com.gempukku.lotro.logic.vo.LotroDeck;
|
||||
import com.gempukku.lotro.packs.ProductLibrary;
|
||||
import com.gempukku.lotro.tournament.action.TournamentProcessAction;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.internal.verification.Times;
|
||||
@@ -110,13 +111,13 @@ public class DefaultTournamentTest extends AbstractAtTest {
|
||||
}
|
||||
).when(tournamentCallback).broadcastMessage(Mockito.anyString());
|
||||
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
|
||||
Mockito.verify(tournamentCallback).broadcastMessage(Mockito.anyString());
|
||||
Mockito.verifyNoMoreInteractions(collectionsManager, tournamentCallback);
|
||||
|
||||
Thread.sleep(_waitForPairingsTime);
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
|
||||
Mockito.verify(tournamentCallback, new Times(1)).createGame("p1", playerDecks.get("p1"), "p2", playerDecks.get("p2"));
|
||||
Mockito.verify(tournamentCallback, new Times(1)).createGame("p3", playerDecks.get("p3"), "p4", playerDecks.get("p4"));
|
||||
@@ -127,32 +128,32 @@ public class DefaultTournamentTest extends AbstractAtTest {
|
||||
|
||||
assertEquals(1, tournament.getCurrentRound());
|
||||
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
Mockito.verifyNoMoreInteractions(collectionsManager, tournamentCallback);
|
||||
|
||||
tournament.reportGameFinished("p1", "p2");
|
||||
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
Mockito.verifyNoMoreInteractions(collectionsManager, tournamentCallback);
|
||||
|
||||
tournament.reportGameFinished("p3", "p4");
|
||||
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
Mockito.verifyNoMoreInteractions(collectionsManager, tournamentCallback);
|
||||
|
||||
tournament.reportGameFinished("p5", "p6");
|
||||
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
Mockito.verifyNoMoreInteractions(collectionsManager, tournamentCallback);
|
||||
|
||||
tournament.reportGameFinished("p7", "p8");
|
||||
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
Mockito.verify(tournamentCallback, new Times(2)).broadcastMessage(Mockito.anyString());
|
||||
Mockito.verifyNoMoreInteractions(collectionsManager, tournamentCallback);
|
||||
|
||||
Thread.sleep(_waitForPairingsTime);
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
|
||||
Mockito.verify(tournamentCallback, new Times(1)).createGame("p1", playerDecks.get("p1"), "p3", playerDecks.get("p3"));
|
||||
Mockito.verify(tournamentCallback, new Times(1)).createGame("p5", playerDecks.get("p5"), "p7", playerDecks.get("p7"));
|
||||
@@ -161,22 +162,22 @@ public class DefaultTournamentTest extends AbstractAtTest {
|
||||
|
||||
assertEquals(2, tournament.getCurrentRound());
|
||||
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
Mockito.verifyNoMoreInteractions(collectionsManager, tournamentCallback);
|
||||
|
||||
tournament.reportGameFinished("p1", "p3");
|
||||
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
Mockito.verifyNoMoreInteractions(collectionsManager, tournamentCallback);
|
||||
|
||||
tournament.reportGameFinished("p5", "p7");
|
||||
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
Mockito.verify(tournamentCallback, new Times(3)).broadcastMessage(Mockito.anyString());
|
||||
Mockito.verifyNoMoreInteractions(collectionsManager, tournamentCallback);
|
||||
|
||||
Thread.sleep(_waitForPairingsTime);
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
|
||||
Mockito.verify(tournamentCallback, new Times(1)).createGame("p1", playerDecks.get("p1"), "p5", playerDecks.get("p5"));
|
||||
|
||||
@@ -184,12 +185,12 @@ public class DefaultTournamentTest extends AbstractAtTest {
|
||||
|
||||
assertEquals(3, tournament.getCurrentRound());
|
||||
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
Mockito.verifyNoMoreInteractions(collectionsManager, tournamentCallback);
|
||||
|
||||
tournament.reportGameFinished("p1", "p5");
|
||||
|
||||
tournament.advanceTournament(tournamentCallback, collectionsManager);
|
||||
advanceTournament(tournament, collectionsManager, tournamentCallback);
|
||||
Mockito.verify(tournamentCallback, new Times(4)).broadcastMessage(Mockito.anyString());
|
||||
|
||||
Mockito.verify(collectionsManager).addItemsToPlayerCollection(Mockito.eq(true), Mockito.anyString(), Mockito.eq("p1"), Mockito.eq(CollectionType.MY_CARDS), Mockito.anyCollection());
|
||||
@@ -202,4 +203,11 @@ public class DefaultTournamentTest extends AbstractAtTest {
|
||||
assertEquals(3, tournament.getCurrentRound());
|
||||
assertEquals(Tournament.Stage.FINISHED, tournament.getTournamentStage());
|
||||
}
|
||||
|
||||
private void advanceTournament(Tournament tournament, CollectionsManager collectionsManager, TournamentCallback callback) {
|
||||
List<TournamentProcessAction> actions = tournament.advanceTournament(collectionsManager);
|
||||
for (TournamentProcessAction action : actions) {
|
||||
action.process(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user