Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package furkan.app.tictactoewebsocket; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.Hashtable; import java.util.List; import java.util.Map; import javax.websocket.CloseReason; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; /** * * @author SVLLA */ @ServerEndpoint("/tictactoe/{gameId}/{username}") public class TicTacToeServer { private static Map<Long, Game> games = new Hashtable<>(); private static ObjectMapper mapper = new ObjectMapper(); @OnOpen public void onOpen(Session session, @PathParam("gameId") long gameId, @PathParam("username") String username) { System.out.println("Inside onOpen"); try { TicTacToeGame ticTacToeGame = TicTacToeGame.getActiveGame(gameId); if (ticTacToeGame != null) { session.close(new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, "This game has already started!")); } List<String> actions = session.getRequestParameterMap().get("action"); if (actions != null && actions.size() == 1) { String action = actions.get(0); if (action.equalsIgnoreCase("start")) { Game game = new Game(); game.gameId = gameId; game.player1 = session; TicTacToeServer.games.put(gameId, game); } else if (action.equalsIgnoreCase("join")) { Game game = TicTacToeServer.games.get(gameId); game.player2 = session; game.ticTacToeGame = TicTacToeGame.startGame(gameId, username); this.sendJsonMessage(game.player1, game, new GameStartedMessage(game.ticTacToeGame)); this.sendJsonMessage(game.player2, game, new GameStartedMessage(game.ticTacToeGame)); } } } catch (IOException ioe) { ioe.printStackTrace(); try { session.close(new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, ioe.toString())); } catch (IOException ignore) { } } } @OnMessage public void onMessage(Session session, String message, @PathParam("gameId") long gameId) { Game game = TicTacToeServer.games.get(gameId); boolean isPlayer1 = session == game.player1; try { Move move = TicTacToeServer.mapper.readValue(message, Move.class); game.ticTacToeGame.move(isPlayer1 ? TicTacToeGame.Player.PLAYER1 : TicTacToeGame.Player.PLAYER2, move.getRow(), move.getColumn()); this.sendJsonMessage((isPlayer1 ? game.player2 : game.player1), game, new OpponentMadeMoveMessage(move)); if (game.ticTacToeGame.isOver()) { if (game.ticTacToeGame.isDraw()) { this.sendJsonMessage(game.player1, game, new GameIsDrawMessage()); this.sendJsonMessage(game.player2, game, new GameIsDrawMessage()); } else { boolean wasPlayer1 = game.ticTacToeGame.getWinner() == TicTacToeGame.Player.PLAYER1; this.sendJsonMessage(game.player1, game, new GameOverMessage(wasPlayer1)); this.sendJsonMessage(game.player2, game, new GameOverMessage(!wasPlayer1)); } game.player1.close(); game.player2.close(); } } catch (IOException ioe) { this.handleException(ioe, game); } } @OnClose public void onClose(Session session, @PathParam("gameId") long gameId) { Game game = TicTacToeServer.games.get(gameId); if (game == null) return; boolean isPlayer1 = session == game.player1; if (game.ticTacToeGame == null) TicTacToeGame.removeQueuedGame(game.gameId); else if (!game.ticTacToeGame.isOver()) { game.ticTacToeGame.forfeit(isPlayer1 ? TicTacToeGame.Player.PLAYER1 : TicTacToeGame.Player.PLAYER2); Session opponent = (isPlayer1 ? game.player2 : game.player1); this.sendJsonMessage(opponent, game, new GameForfeitedMessage()); try { opponent.close(); } catch (IOException ioe) { ioe.printStackTrace(); } } } private void sendJsonMessage(Session session, Game game, Message message) { try { session.getBasicRemote().sendText(TicTacToeServer.mapper.writeValueAsString(message)); } catch (IOException ioe) { this.handleException(ioe, game); } } private void handleException(Throwable t, Game game) { t.printStackTrace(); String message = t.toString(); try { game.player1.close(new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, message)); } catch (IOException ignore) { } try { game.player2.close(new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, message)); } catch (IOException ignore) { } } private static class Game { public long gameId; public Session player1; public Session player2; public TicTacToeGame ticTacToeGame; } public static class Move { private int row; private int column; // accessor and mutator methods public int getRow() { return row; } public void setRow(int row) { this.row = row; } public int getColumn() { return column; } public void setColumn(int column) { this.column = column; } } public static abstract class Message { private final String action; public Message(String action) { this.action = action; } public String getAction() { return this.action; } } public static class GameStartedMessage extends Message { private final TicTacToeGame game; public GameStartedMessage(TicTacToeGame game) { super("gameStarted"); this.game = game; } public TicTacToeGame getGame() { return game; } } public static class OpponentMadeMoveMessage extends Message { private final Move move; public OpponentMadeMoveMessage(Move move) { super("opponentMadeMove"); this.move = move; } public Move getMove() { return this.move; } } public static class GameOverMessage extends Message { private final boolean winner; public GameOverMessage(boolean winner) { super("gameOver"); this.winner = winner; } public boolean isWinner() { return winner; } } public static class GameIsDrawMessage extends Message { public GameIsDrawMessage() { super("gameIsDraw"); } } public static class GameForfeitedMessage extends Message { public GameForfeitedMessage() { super("gameForfeited"); } } }