Java tutorial
/* * Computoser is a music-composition algorithm and a website to present the results * Copyright (C) 2012-2014 Bozhidar Bozhanov * * Computoser is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * Computoser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Computoser. If not, see <http://www.gnu.org/licenses/>. */ package com.music.web.websocket; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import javax.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.AbstractWebSocketHandler; import com.fasterxml.jackson.databind.ObjectMapper; import com.music.service.PieceService; import com.music.web.websocket.dto.GameEvent; import com.music.web.websocket.dto.GameEventType; import com.music.web.websocket.dto.GameMessage; @Component public class GameHandler extends AbstractWebSocketHandler { private static final Logger logger = LoggerFactory.getLogger(GameHandler.class); private ObjectMapper mapper = new ObjectMapper(); @Inject private PieceService pieceService; private Map<String, Game> games = new ConcurrentHashMap<>(); private Map<String, Game> pendingGames = new ConcurrentHashMap<>(); private Map<String, Player> players = new ConcurrentHashMap<>(); private Map<String, Game> playerGames = new ConcurrentHashMap<>(); @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { Player player = new Player(session); players.put(session.getId(), player); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { leave(session.getId()); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage textMessage) throws Exception { try { GameMessage message = getMessage(textMessage); switch (message.getAction()) { case INITIALIZE: initialize(message, session); break; case JOIN: join(message.getGameId(), message.getPlayerName(), session); break; case LEAVE: leave(session.getId()); break; case START: startGame(message); break; case ANSWER: answer(message, session.getId()); break; case JOIN_RANDOM: joinRandomGame(message.getPlayerName(), session); break; } } catch (Exception ex) { logger.error("Exception occurred while handling message", ex); } } private void startGame(GameMessage message) { Game game = games.get(message.getGameId()); if (game != null) { game.start(); } pendingGames.remove(game.getId()); } private void answer(GameMessage message, String playerId) { Game game = games.get(message.getGameId()); Player player = game.getPlayers().get(playerId); player.answer(game, message.getAnswer()); } private void leave(String playerId) { players.remove(playerId); Game game = playerGames.remove(playerId); if (game != null) { game.playerLeft(playerId); // if this is the last player, remove the orphaned game if (game.getPlayers().isEmpty()) { games.remove(game.getId()); pendingGames.remove(game.getId()); } } } private void join(String gameId, String playerName, WebSocketSession session) { Game game = games.get(gameId); if (game == null) { sendMessage(new GameEvent(GameEventType.NO_GAME_AVAILABLE), session); } if (!game.isStarted()) { String playerId = session.getId(); Player player = players.get(playerId); player.setName(playerName); playerGames.put(playerId, game); if (!game.playerJoined(player)) { sendMessage(new GameEvent(GameEventType.PLAYER_NAME_TAKEN), session); } } else { sendMessage(new GameEvent(GameEventType.GAME_ALREADY_STARTED), session); } } public static void sendMessage(GameEvent event, WebSocketSession session) { try { session.sendMessage(new TextMessage(event.toJson())); } catch (IOException e) { throw new IllegalStateException(e); } } private void joinRandomGame(String playerName, WebSocketSession session) { if (pendingGames.isEmpty()) { sendMessage(new GameEvent(GameEventType.NO_GAME_AVAILABLE), session); return; } List<Game> games = new ArrayList<>(this.pendingGames.values()); Random random = new Random(); Game game = pendingGames.get(random.nextInt(games.size())); join(game.getId(), playerName, session); GameEvent event = new GameEvent(GameEventType.RANDOM_GAME_JOINED); event.setGameId(game.getId()); sendMessage(event, session); } private void initialize(GameMessage message, WebSocketSession session) { String gameId = UUID.randomUUID().toString(); Game game = new Game(gameId, pieceService); games.put(gameId, game); pendingGames.put(gameId, game); join(gameId, message.getPlayerName(), session); GameEvent event = new GameEvent(GameEventType.GAME_INITIALIZED); event.setGameId(gameId); sendMessage(event, session); } public GameMessage getMessage(TextMessage message) { try { return mapper.readValue(message.getPayload(), GameMessage.class); } catch (IOException e) { throw new IllegalStateException(e); } } public Map<String, Game> getGames() { return games; } public void setPieceService(PieceService pieceService) { this.pieceService = pieceService; } }