/**
   * Typed request handlers simplify testing, no need to mock http response, request dispatcher or
   * to handle exceptions.
   */
  String handleRequest(ConnectFourRequest req) {
    // Get elements from the session
    ConnectFourSession session = req.getSession();
    Game game = session.getGame();

    // Create game or reset it if necessary
    String resetStr = req.getParameter(PARAM_RESET_KEY);
    if ((game == null) || (resetStr != null)) {
      // TODO use dependency injection to avoid dependency on implementation
      game = new GameImpl();
      game.begin();
    }

    // Handle play parameter
    String subMessage = "";
    String colStr = req.getParameter(PARAM_PLAY_KEY);
    if (colStr != null) {
      try {
        int colIdx = Integer.parseInt(colStr);
        game.dropDisc(colIdx - 1);
      } catch (NumberFormatException e) {
        subMessage = "Invalid parameter col: " + colStr;
        log.error(subMessage);
      } catch (ConnectFourException e) {
        subMessage = e.getMessage();
        log.error(subMessage);
      }
    }

    // Build main message
    String mainMessage = "";
    GameStatus gameStatus = game.getStatus();
    if (gameStatus == GameStatus.ONGOING) {
      Player player = game.getCurrentPlayer();
      mainMessage = "Now playing: " + player.getName();
    } else if (gameStatus == GameStatus.FINISHED) {
      Player winner = game.getWinner();
      if (winner != null) {
        mainMessage = winner.getName() + " won the game.";
      } else {
        mainMessage = "It's a draw game.";
      }
    }

    // Save request attributes for the view
    req.setMainMessage(mainMessage);
    req.setSubMessage(subMessage);
    req.setGameId(game.getId());

    // Save elements in the session
    session.setGame(game);

    return MAIN_DISPLAY_JSP;
  }