furkan.app.tictactoewebsocket.TicTacToeServer.java Source code

Java tutorial

Introduction

Here is the source code for furkan.app.tictactoewebsocket.TicTacToeServer.java

Source

/*
 * 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");
        }
    }
}