From 93b47d69d804484e2f1555e0013dac9bee557715 Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Tue, 30 Dec 2025 21:29:24 +0200 Subject: [PATCH 01/13] feat: rename ActivityPoint entity and related classes --- .../dao/{ActivityDAO.java => SessionDAO.java} | 104 +++++++++--------- .../{ActivityPoint.java => Session.java} | 9 +- .../exception/ActivityNotFoundException.java | 12 -- .../exception/ExceptionHandlerMiddleware.java | 4 +- .../exception/SessionNotFoundException.java | 12 ++ ...Service.java => PlayerSessionService.java} | 28 ++--- .../domain/statistics/StatisticsManager.java | 4 +- 7 files changed, 86 insertions(+), 87 deletions(-) rename src/main/java/com/mycompany/tictactoeserver/datasource/database/dao/{ActivityDAO.java => SessionDAO.java} (69%) rename src/main/java/com/mycompany/tictactoeserver/datasource/model/{ActivityPoint.java => Session.java} (90%) delete mode 100644 src/main/java/com/mycompany/tictactoeserver/domain/exception/ActivityNotFoundException.java create mode 100644 src/main/java/com/mycompany/tictactoeserver/domain/exception/SessionNotFoundException.java rename src/main/java/com/mycompany/tictactoeserver/domain/statistics/{ActivityService.java => PlayerSessionService.java} (56%) diff --git a/src/main/java/com/mycompany/tictactoeserver/datasource/database/dao/ActivityDAO.java b/src/main/java/com/mycompany/tictactoeserver/datasource/database/dao/SessionDAO.java similarity index 69% rename from src/main/java/com/mycompany/tictactoeserver/datasource/database/dao/ActivityDAO.java rename to src/main/java/com/mycompany/tictactoeserver/datasource/database/dao/SessionDAO.java index a349f33..0470df0 100644 --- a/src/main/java/com/mycompany/tictactoeserver/datasource/database/dao/ActivityDAO.java +++ b/src/main/java/com/mycompany/tictactoeserver/datasource/database/dao/SessionDAO.java @@ -1,9 +1,9 @@ package com.mycompany.tictactoeserver.datasource.database.dao; import com.mycompany.tictactoeserver.datasource.database.Database; -import com.mycompany.tictactoeserver.datasource.model.ActivityPoint; +import com.mycompany.tictactoeserver.datasource.model.Session; import com.mycompany.tictactoeserver.domain.exception.ActiveSessionExistsException; -import com.mycompany.tictactoeserver.domain.exception.ActivityNotFoundException; +import com.mycompany.tictactoeserver.domain.exception.SessionNotFoundException; import com.mycompany.tictactoeserver.domain.exception.DataAccessException; import java.sql.*; @@ -14,43 +14,43 @@ /** * @author Tasneem */ -public class ActivityDAO { +public class SessionDAO { private final Connection connection; - public ActivityDAO() { + public SessionDAO() { this.connection = Database.getInstance().getConnection(); } - public boolean startActivity(ActivityPoint activity) throws ActiveSessionExistsException { - ActivityPoint existingSession = getActiveSessionByPlayerId(activity.getPlayerId()); + public boolean startSession(Session session) throws ActiveSessionExistsException { + Session existingSession = getActiveSessionByPlayerId(session.getPlayerId()); if (existingSession != null) { throw new ActiveSessionExistsException(); } String sql = "INSERT INTO ACTIVITY (id, player_id, start_date, end_date) VALUES (?, ?, ?, ?)"; try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { - preparedStatement.setString(1, activity.getId()); - preparedStatement.setString(2, activity.getPlayerId()); - preparedStatement.setTimestamp(3, Timestamp.valueOf(activity.getStartTime())); - preparedStatement.setTimestamp(4, activity.getEndTime() != null ? Timestamp.valueOf(activity.getEndTime()) : null); + preparedStatement.setString(1, session.getId()); + preparedStatement.setString(2, session.getPlayerId()); + preparedStatement.setTimestamp(3, Timestamp.valueOf(session.getStartTime())); + preparedStatement.setTimestamp(4, session.getEndTime() != null ? Timestamp.valueOf(session.getEndTime()) : null); int rowsAffected = preparedStatement.executeUpdate(); return rowsAffected > 0; } catch (SQLException e) { - System.err.println("Error starting activity: " + e.getMessage()); + System.err.println("Error starting session: " + e.getMessage()); return false; } } - public boolean endActivity(ActivityPoint activity) throws ActivityNotFoundException, DataAccessException { + public boolean endSession(Session session) throws SessionNotFoundException, DataAccessException { String sql = "UPDATE ACTIVITY SET end_date = ? WHERE id = ?"; try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { - preparedStatement.setTimestamp(1, Timestamp.valueOf(activity.getEndTime())); - preparedStatement.setString(2, activity.getId()); + preparedStatement.setTimestamp(1, Timestamp.valueOf(session.getEndTime())); + preparedStatement.setString(2, session.getId()); int rowsAffected = preparedStatement.executeUpdate(); if (rowsAffected == 0) { - throw new ActivityNotFoundException(); + throw new SessionNotFoundException(); } return true; } catch (SQLException e) { @@ -58,10 +58,10 @@ public boolean endActivity(ActivityPoint activity) throws ActivityNotFoundExcept } } - public boolean endActivityByPlayerId(String playerId) throws ActivityNotFoundException, DataAccessException { - ActivityPoint activeSession = getActiveSessionByPlayerId(playerId); + public boolean endSessionByPlayerId(String playerId) throws SessionNotFoundException, DataAccessException { + Session activeSession = getActiveSessionByPlayerId(playerId); if (activeSession == null) { - throw new ActivityNotFoundException(); + throw new SessionNotFoundException(); } String sql = "UPDATE ACTIVITY SET end_date = ? WHERE id = ?"; @@ -76,48 +76,48 @@ public boolean endActivityByPlayerId(String playerId) throws ActivityNotFoundExc } } - public ActivityPoint getActivityById(String activityId) throws ActivityNotFoundException, DataAccessException { + public Session getSessionById(String sessionId) throws SessionNotFoundException, DataAccessException { String sql = "SELECT id, player_id, start_date, end_date FROM ACTIVITY WHERE id = ?"; try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { - preparedStatement.setString(1, activityId); + preparedStatement.setString(1, sessionId); try (ResultSet resultSet = preparedStatement.executeQuery()) { if (resultSet.next()) { - return mapResultSetToActivity(resultSet); + return mapResultSetToSession(resultSet); } - throw new ActivityNotFoundException(); + throw new SessionNotFoundException(); } } catch (SQLException e) { throw new DataAccessException(e.getStackTrace()); } } - public List getActivitiesByPlayerId(String playerId) throws DataAccessException { + public List getSessionByPlayerId(String playerId) throws DataAccessException { String sql = "SELECT id, player_id, start_date, end_date FROM ACTIVITY WHERE player_id = ? ORDER BY start_date DESC"; - List activities = new ArrayList<>(); + List sessions = new ArrayList<>(); try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { preparedStatement.setString(1, playerId); try (ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { - activities.add(mapResultSetToActivity(resultSet)); + sessions.add(mapResultSetToSession(resultSet)); } } } catch (SQLException e) { throw new DataAccessException(e.getStackTrace()); } - return activities; + return sessions; } - public ActivityPoint getActiveSessionByPlayerId(String playerId) { + public Session getActiveSessionByPlayerId(String playerId) { String sql = "SELECT id, player_id, start_date, end_date FROM ACTIVITY WHERE player_id = ? AND end_date IS NULL ORDER BY start_date DESC LIMIT 1"; try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { preparedStatement.setString(1, playerId); try (ResultSet resultSet = preparedStatement.executeQuery()) { if (resultSet.next()) { - return mapResultSetToActivity(resultSet); + return mapResultSetToSession(resultSet); } } } catch (SQLException e) { @@ -126,9 +126,9 @@ public ActivityPoint getActiveSessionByPlayerId(String playerId) { return null; } - public List getActivitiesByDateRange(LocalDateTime startDate, LocalDateTime endDate) throws DataAccessException { + public List getSessionsByDateRange(LocalDateTime startDate, LocalDateTime endDate) throws DataAccessException { String sql = "SELECT id, player_id, start_date, end_date FROM ACTIVITY WHERE start_date BETWEEN ? AND ? ORDER BY start_date DESC"; - List activities = new ArrayList<>(); + List sessions = new ArrayList<>(); try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { preparedStatement.setTimestamp(1, Timestamp.valueOf(startDate)); @@ -136,16 +136,16 @@ public List getActivitiesByDateRange(LocalDateTime startDate, Loc try (ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { - activities.add(mapResultSetToActivity(resultSet)); + sessions.add(mapResultSetToSession(resultSet)); } } } catch (SQLException e) { throw new DataAccessException(e.getStackTrace()); } - return activities; + return sessions; } - public int getActivityCountByPlayerId(String playerId) throws DataAccessException { + public int getSessionCountByPlayerId(String playerId) throws DataAccessException { String sql = "SELECT COUNT(*) FROM ACTIVITY WHERE player_id = ?"; try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { preparedStatement.setString(1, playerId); @@ -165,14 +165,14 @@ public boolean hasActiveSession(String playerId) { return getActiveSessionByPlayerId(playerId) != null; } - public boolean deleteActivity(String activityId) throws ActivityNotFoundException, DataAccessException { + public boolean deleteSession(String sessionId) throws SessionNotFoundException, DataAccessException { String sql = "DELETE FROM ACTIVITY WHERE id = ?"; try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { - preparedStatement.setString(1, activityId); + preparedStatement.setString(1, sessionId); int rowsAffected = preparedStatement.executeUpdate(); if (rowsAffected == 0) { - throw new ActivityNotFoundException(); + throw new SessionNotFoundException(); } return true; } catch (SQLException e) { @@ -180,7 +180,7 @@ public boolean deleteActivity(String activityId) throws ActivityNotFoundExceptio } } - public int deleteActivitiesByPlayerId(String playerId) throws DataAccessException { + public int deletePlayerSessions(String playerId) throws DataAccessException { String sql = "DELETE FROM ACTIVITY WHERE player_id = ?"; try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { preparedStatement.setString(1, playerId); @@ -190,35 +190,35 @@ public int deleteActivitiesByPlayerId(String playerId) throws DataAccessExceptio } } - public List getAllSessions() throws ActivityNotFoundException { + public List getAllSessions() throws SessionNotFoundException { String sql = "SELECT id, player_id, start_date, end_date FROM ACTIVITY ORDER BY start_date DESC"; - List activities = new ArrayList<>(); + List sessions = new ArrayList<>(); try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { try (ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { - activities.add(mapResultSetToActivity(resultSet)); + sessions.add(mapResultSetToSession(resultSet)); } } } catch (SQLException e) { - throw new ActivityNotFoundException(e.getStackTrace()); + throw new SessionNotFoundException(e.getStackTrace()); } - return activities; + return sessions; } - public List getAllActiveSessions() throws DataAccessException { + public List getAllActiveSessions() throws DataAccessException { String sql = "SELECT id, player_id, start_date, end_date FROM ACTIVITY WHERE end_date IS NULL ORDER BY start_date DESC"; - List activities = new ArrayList<>(); + List sessions = new ArrayList<>(); try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { try (ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { - activities.add(mapResultSetToActivity(resultSet)); + sessions.add(mapResultSetToSession(resultSet)); } } } catch (SQLException e) { throw new DataAccessException(e.getStackTrace()); } - return activities; + return sessions; } public long getTotalPlayTimeMinutes(String playerId) throws DataAccessException { @@ -245,20 +245,20 @@ public long getTotalPlayTimeMinutes(String playerId) throws DataAccessException return totalMinutes; } - private ActivityPoint mapResultSetToActivity(ResultSet resultSet) throws SQLException { - ActivityPoint activity = new ActivityPoint(); - activity.setPlayerId(resultSet.getString("player_id")); + private Session mapResultSetToSession(ResultSet resultSet) throws SQLException { + Session session = new Session(); + session.setPlayerId(resultSet.getString("player_id")); Timestamp startTimestamp = resultSet.getTimestamp("start_date"); if (startTimestamp != null) { - activity.setStartTime(startTimestamp.toLocalDateTime()); + session.setStartTime(startTimestamp.toLocalDateTime()); } Timestamp endTimestamp = resultSet.getTimestamp("end_date"); if (endTimestamp != null) { - activity.setEndTime(endTimestamp.toLocalDateTime()); + session.setEndTime(endTimestamp.toLocalDateTime()); } - return activity; + return session; } } \ No newline at end of file diff --git a/src/main/java/com/mycompany/tictactoeserver/datasource/model/ActivityPoint.java b/src/main/java/com/mycompany/tictactoeserver/datasource/model/Session.java similarity index 90% rename from src/main/java/com/mycompany/tictactoeserver/datasource/model/ActivityPoint.java rename to src/main/java/com/mycompany/tictactoeserver/datasource/model/Session.java index 8a8cd4d..3146793 100644 --- a/src/main/java/com/mycompany/tictactoeserver/datasource/model/ActivityPoint.java +++ b/src/main/java/com/mycompany/tictactoeserver/datasource/model/Session.java @@ -1,20 +1,19 @@ package com.mycompany.tictactoeserver.datasource.model; import java.util.UUID; - - import java.time.LocalDateTime; -public class ActivityPoint { + +public class Session { private final String id; private String playerId; private LocalDateTime startTime; private LocalDateTime endTime; - public ActivityPoint() { + public Session() { this.id = UUID.randomUUID().toString(); this.startTime = LocalDateTime.now(); } - public ActivityPoint(String playerId) { + public Session(String playerId) { this.id = UUID.randomUUID().toString(); this.startTime = LocalDateTime.now(); this.playerId = playerId; diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/exception/ActivityNotFoundException.java b/src/main/java/com/mycompany/tictactoeserver/domain/exception/ActivityNotFoundException.java deleted file mode 100644 index d8361b1..0000000 --- a/src/main/java/com/mycompany/tictactoeserver/domain/exception/ActivityNotFoundException.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.mycompany.tictactoeserver.domain.exception; - -public class ActivityNotFoundException extends Exception { - public ActivityNotFoundException(StackTraceElement[] stackTraceElements) { - super("activity-not-found-exception"); - setStackTrace(stackTraceElements); - } - - public ActivityNotFoundException() { - super("activity-not-found-exception"); - } -} diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/exception/ExceptionHandlerMiddleware.java b/src/main/java/com/mycompany/tictactoeserver/domain/exception/ExceptionHandlerMiddleware.java index 23027f6..9c34547 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/exception/ExceptionHandlerMiddleware.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/exception/ExceptionHandlerMiddleware.java @@ -65,8 +65,8 @@ public void handleException(Exception ex, String[] data) { case "active-session-exists-exception": System.out.println("active-session-exists-exception for player " + data[0] + " in session " + data[1] + "."); break; - case "activity-not-found-exception": - System.out.println("activity-not-found-exception for activity " + data[0]); + case "session-not-found-exception": + System.out.println("session-not-found-exception for activity " + data[0]); break; default: System.out.println("unknown-exception"); diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/exception/SessionNotFoundException.java b/src/main/java/com/mycompany/tictactoeserver/domain/exception/SessionNotFoundException.java new file mode 100644 index 0000000..77b5642 --- /dev/null +++ b/src/main/java/com/mycompany/tictactoeserver/domain/exception/SessionNotFoundException.java @@ -0,0 +1,12 @@ +package com.mycompany.tictactoeserver.domain.exception; + +public class SessionNotFoundException extends Exception { + public SessionNotFoundException(StackTraceElement[] stackTraceElements) { + super("session-not-found-exception"); + setStackTrace(stackTraceElements); + } + + public SessionNotFoundException() { + super("session-not-found-exception"); + } +} diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/statistics/ActivityService.java b/src/main/java/com/mycompany/tictactoeserver/domain/statistics/PlayerSessionService.java similarity index 56% rename from src/main/java/com/mycompany/tictactoeserver/domain/statistics/ActivityService.java rename to src/main/java/com/mycompany/tictactoeserver/domain/statistics/PlayerSessionService.java index 6cf24bf..560c4e9 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/statistics/ActivityService.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/statistics/PlayerSessionService.java @@ -1,22 +1,22 @@ package com.mycompany.tictactoeserver.domain.statistics; -import com.mycompany.tictactoeserver.datasource.database.dao.ActivityDAO; -import com.mycompany.tictactoeserver.datasource.model.ActivityPoint; +import com.mycompany.tictactoeserver.datasource.database.dao.SessionDAO; +import com.mycompany.tictactoeserver.datasource.model.Session; import com.mycompany.tictactoeserver.domain.exception.*; -public class ActivityService { - private final ActivityDAO activityDao; +public class PlayerSessionService { + private final SessionDAO sessionDao; private final ExceptionHandlerMiddleware exceptionHandler; - public ActivityService() { - this.activityDao = new ActivityDAO(); + public PlayerSessionService() { + this.sessionDao = new SessionDAO(); this.exceptionHandler = ExceptionHandlerMiddleware.getInstance(); } - public boolean startPlayerActivity(String playerId) { + public boolean startPlayerSession(String playerId) { try { - ActivityPoint activity = new ActivityPoint(playerId); - return activityDao.startActivity(activity); + Session session = new Session(playerId); + return sessionDao.startSession(session); } catch (ActiveSessionExistsException e) { String[] data = {playerId, e.getMessage()}; @@ -25,11 +25,11 @@ public boolean startPlayerActivity(String playerId) { } } - public boolean endPlayerActivity(String playerId) { + public boolean endPlayerSession(String playerId) { try { - return activityDao.endActivityByPlayerId(playerId); + return sessionDao.endSessionByPlayerId(playerId); - } catch (ActivityNotFoundException e) { + } catch (SessionNotFoundException e) { String[] data = {playerId}; exceptionHandler.handleException(e, data); return false; @@ -41,12 +41,12 @@ public boolean endPlayerActivity(String playerId) { } public boolean isPlayerActive(String playerId) { - return activityDao.hasActiveSession(playerId); + return sessionDao.hasActiveSession(playerId); } public long getPlayerPlayTime(String playerId) { try { - return activityDao.getTotalPlayTimeMinutes(playerId); + return sessionDao.getTotalPlayTimeMinutes(playerId); } catch (DataAccessException e) { exceptionHandler.handleException(e); diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/statistics/StatisticsManager.java b/src/main/java/com/mycompany/tictactoeserver/domain/statistics/StatisticsManager.java index 12eba58..c55cef7 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/statistics/StatisticsManager.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/statistics/StatisticsManager.java @@ -1,11 +1,11 @@ package com.mycompany.tictactoeserver.domain.statistics; -import com.mycompany.tictactoeserver.datasource.model.ActivityPoint; +import com.mycompany.tictactoeserver.datasource.model.Session; import com.mycompany.tictactoeserver.datasource.model.Player; import java.util.Vector; public interface StatisticsManager { - Vector getActivity(); + Vector getActivity(); Vector getLeaderboard(); } From bec2cb5448064c08f4ff284cd928b64b236b1b38 Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Mon, 5 Jan 2026 19:09:43 +0200 Subject: [PATCH 02/13] feat: rename PlayerSessionService and add method to retrieve all player sessions --- .../PlayerSessionService.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) rename src/main/java/com/mycompany/tictactoeserver/domain/{statistics => service}/PlayerSessionService.java (83%) diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/statistics/PlayerSessionService.java b/src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerSessionService.java similarity index 83% rename from src/main/java/com/mycompany/tictactoeserver/domain/statistics/PlayerSessionService.java rename to src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerSessionService.java index 560c4e9..0b1d44e 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/statistics/PlayerSessionService.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerSessionService.java @@ -1,9 +1,11 @@ -package com.mycompany.tictactoeserver.domain.statistics; +package com.mycompany.tictactoeserver.domain.service; import com.mycompany.tictactoeserver.datasource.database.dao.SessionDAO; import com.mycompany.tictactoeserver.datasource.model.Session; import com.mycompany.tictactoeserver.domain.exception.*; +import java.util.List; + public class PlayerSessionService { private final SessionDAO sessionDao; private final ExceptionHandlerMiddleware exceptionHandler; @@ -13,6 +15,16 @@ public PlayerSessionService() { this.exceptionHandler = ExceptionHandlerMiddleware.getInstance(); } + public List getAllPlayerSessions() { + try { + return sessionDao.getAllSessions(); + + } catch (SessionNotFoundException e) { + exceptionHandler.handleException(e); + } + return List.of(); + } + public boolean startPlayerSession(String playerId) { try { Session session = new Session(playerId); From 7219a8b067cedcde313fdc41ff512c9ada9a880d Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Mon, 5 Jan 2026 20:50:25 +0200 Subject: [PATCH 03/13] feat: add ActivityPoint entity to track player activity statistics --- .../domain/entity/ActivityPoint.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/com/mycompany/tictactoeserver/domain/entity/ActivityPoint.java diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/entity/ActivityPoint.java b/src/main/java/com/mycompany/tictactoeserver/domain/entity/ActivityPoint.java new file mode 100644 index 0000000..5355a16 --- /dev/null +++ b/src/main/java/com/mycompany/tictactoeserver/domain/entity/ActivityPoint.java @@ -0,0 +1,32 @@ +package com.mycompany.tictactoeserver.domain.entity; + +import java.time.LocalDateTime; +/** + * + * @author Tasneem + */ +public class ActivityPoint { + private LocalDateTime timestamp; + private int playerCount; + + public ActivityPoint(LocalDateTime timestamp, int playerCount) { + this.timestamp = timestamp; + this.playerCount = playerCount; + } + + public LocalDateTime getTimestamp() { + return timestamp; + } + + public void setTimestamp(LocalDateTime timestamp) { + this.timestamp = timestamp; + } + + public int getPlayerCount() { + return playerCount; + } + + public void setPlayerCount(int playerCount) { + this.playerCount = playerCount; + } +} \ No newline at end of file From b921c53d79acb75b7a32de9a531b797f50f6f8d6 Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Mon, 5 Jan 2026 20:51:15 +0200 Subject: [PATCH 04/13] feat: implement StatisticsManager --- .../domain/statistics/StatisticsManager.java | 10 ++-- .../statistics/StatisticsManagerImpl.java | 57 +++++++++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/mycompany/tictactoeserver/domain/statistics/StatisticsManagerImpl.java diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/statistics/StatisticsManager.java b/src/main/java/com/mycompany/tictactoeserver/domain/statistics/StatisticsManager.java index c55cef7..6ffa699 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/statistics/StatisticsManager.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/statistics/StatisticsManager.java @@ -1,11 +1,13 @@ package com.mycompany.tictactoeserver.domain.statistics; -import com.mycompany.tictactoeserver.datasource.model.Session; import com.mycompany.tictactoeserver.datasource.model.Player; +import com.mycompany.tictactoeserver.domain.entity.ActivityPoint; +import com.mycompany.tictactoeserver.domain.entity.PlayerEntity; -import java.util.Vector; +import java.util.List; public interface StatisticsManager { - Vector getActivity(); - Vector getLeaderboard(); + List getAllPlayerSessions(); + List getLeaderboard(); + int getTotalPlayersCount(); } diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/statistics/StatisticsManagerImpl.java b/src/main/java/com/mycompany/tictactoeserver/domain/statistics/StatisticsManagerImpl.java new file mode 100644 index 0000000..0fc66eb --- /dev/null +++ b/src/main/java/com/mycompany/tictactoeserver/domain/statistics/StatisticsManagerImpl.java @@ -0,0 +1,57 @@ +package com.mycompany.tictactoeserver.domain.statistics; + +import com.mycompany.tictactoeserver.datasource.model.Player; +import com.mycompany.tictactoeserver.datasource.model.Session; +import com.mycompany.tictactoeserver.domain.entity.ActivityPoint; +import com.mycompany.tictactoeserver.domain.entity.PlayerEntity; +import com.mycompany.tictactoeserver.domain.service.PlayerService; +import com.mycompany.tictactoeserver.domain.service.PlayerSessionService; + +import java.util.*; +import java.util.List; +/** + * + * @author Tasneem + */ +public class StatisticsManagerImpl implements StatisticsManager { + private final PlayerSessionService playerSessionService; + private final PlayerService playerService; + + public StatisticsManagerImpl(PlayerService playerService) { + this.playerService = playerService; + this.playerSessionService = new PlayerSessionService(); + } + + @Override + public List getAllPlayerSessions() { + List sessions = playerSessionService.getAllPlayerSessions(); + + List activityPoints = new ArrayList<>(); + return activityPoints; + } + + + + @Override + public List getLeaderboard() { + List players = playerService.getAllPlayers(); + + List leaderboard = new ArrayList<>(); + for (Player player : players) { + PlayerEntity playerEntity = new PlayerEntity( + player.getUsername(), + player.getScore() + ); + leaderboard.add(playerEntity); + } + + leaderboard.sort((p1, p2) -> Integer.compare(p2.getScore(), p1.getScore())); + + return leaderboard; + } + + @Override + public int getTotalPlayersCount() { + return playerService.getAllPlayers().size(); + } +} From 3e230e0d33bb0a006e1307ed845b00f951d0ba7c Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Mon, 5 Jan 2026 20:51:47 +0200 Subject: [PATCH 05/13] feat: add PlayerEntity --- .../domain/entity/PlayerEntity.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/java/com/mycompany/tictactoeserver/domain/entity/PlayerEntity.java diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/entity/PlayerEntity.java b/src/main/java/com/mycompany/tictactoeserver/domain/entity/PlayerEntity.java new file mode 100644 index 0000000..50038cb --- /dev/null +++ b/src/main/java/com/mycompany/tictactoeserver/domain/entity/PlayerEntity.java @@ -0,0 +1,35 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package com.mycompany.tictactoeserver.domain.entity; + +/** + * + * @author Tasneem + */ +public class PlayerEntity { + private String username; + private int score; + + public PlayerEntity(String username, int score) { + this.username = username; + this.score = score; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public int getScore() { + return score; + } + + public void setScore(int score) { + this.score = score; + } +} From fd946a405d499ae63d50f4239c73ec78c086f6d0 Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Mon, 5 Jan 2026 20:52:03 +0200 Subject: [PATCH 06/13] feat: add PlayerService to manage --- .../domain/service/PlayerService.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerService.java diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerService.java b/src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerService.java new file mode 100644 index 0000000..7c80731 --- /dev/null +++ b/src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerService.java @@ -0,0 +1,22 @@ +package com.mycompany.tictactoeserver.domain.service; + +import com.mycompany.tictactoeserver.datasource.database.dao.PlayerDAO; +import com.mycompany.tictactoeserver.datasource.model.Player; + +import java.util.List; + +/** + * + * @author Tasneem + */ +public class PlayerService { + private final PlayerDAO playerDAO; + + public PlayerService(PlayerDAO playerDAO) { + this.playerDAO = playerDAO; + } + + public List getAllPlayers() { + return playerDAO.findAll(); + } +} From c8b55efdc01e3fb36e843661402724be99f456a1 Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Mon, 5 Jan 2026 23:56:09 +0200 Subject: [PATCH 07/13] fix: exception package --- .../domain/utils/exception/SessionNotFoundException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/utils/exception/SessionNotFoundException.java b/src/main/java/com/mycompany/tictactoeserver/domain/utils/exception/SessionNotFoundException.java index 77b5642..5b6c5b5 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/utils/exception/SessionNotFoundException.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/utils/exception/SessionNotFoundException.java @@ -1,4 +1,4 @@ -package com.mycompany.tictactoeserver.domain.exception; +package com.mycompany.tictactoeserver.domain.utils.exception; public class SessionNotFoundException extends Exception { public SessionNotFoundException(StackTraceElement[] stackTraceElements) { From 1fba9f26204d588886532c8af1dc05dfbe9ef184 Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Tue, 6 Jan 2026 01:16:55 +0200 Subject: [PATCH 08/13] refactor: reorganize service packages --- .../domain/{service => services/player}/PlayerService.java | 2 +- .../playerSession}/PlayerSessionService.java | 4 ++-- .../domain/services/statistics/StatisticsManager.java | 2 +- .../domain/services/statistics/StatisticsManagerImpl.java | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) rename src/main/java/com/mycompany/tictactoeserver/domain/{service => services/player}/PlayerService.java (87%) rename src/main/java/com/mycompany/tictactoeserver/domain/{service => services/playerSession}/PlayerSessionService.java (93%) diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerService.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/player/PlayerService.java similarity index 87% rename from src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerService.java rename to src/main/java/com/mycompany/tictactoeserver/domain/services/player/PlayerService.java index 7c80731..973f460 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerService.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/services/player/PlayerService.java @@ -1,4 +1,4 @@ -package com.mycompany.tictactoeserver.domain.service; +package com.mycompany.tictactoeserver.domain.services.player; import com.mycompany.tictactoeserver.datasource.database.dao.PlayerDAO; import com.mycompany.tictactoeserver.datasource.model.Player; diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerSessionService.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/playerSession/PlayerSessionService.java similarity index 93% rename from src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerSessionService.java rename to src/main/java/com/mycompany/tictactoeserver/domain/services/playerSession/PlayerSessionService.java index 0b1d44e..e07976e 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/service/PlayerSessionService.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/services/playerSession/PlayerSessionService.java @@ -1,8 +1,8 @@ -package com.mycompany.tictactoeserver.domain.service; +package com.mycompany.tictactoeserver.domain.services.playerSession; import com.mycompany.tictactoeserver.datasource.database.dao.SessionDAO; import com.mycompany.tictactoeserver.datasource.model.Session; -import com.mycompany.tictactoeserver.domain.exception.*; +import com.mycompany.tictactoeserver.domain.utils.exception.*; import java.util.List; diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManager.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManager.java index 6ffa699..9c45649 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManager.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManager.java @@ -1,4 +1,4 @@ -package com.mycompany.tictactoeserver.domain.statistics; +package com.mycompany.tictactoeserver.domain.services.statistics; import com.mycompany.tictactoeserver.datasource.model.Player; import com.mycompany.tictactoeserver.domain.entity.ActivityPoint; diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManagerImpl.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManagerImpl.java index 0fc66eb..eaaf797 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManagerImpl.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManagerImpl.java @@ -1,11 +1,11 @@ -package com.mycompany.tictactoeserver.domain.statistics; +package com.mycompany.tictactoeserver.domain.services.statistics; import com.mycompany.tictactoeserver.datasource.model.Player; import com.mycompany.tictactoeserver.datasource.model.Session; import com.mycompany.tictactoeserver.domain.entity.ActivityPoint; import com.mycompany.tictactoeserver.domain.entity.PlayerEntity; -import com.mycompany.tictactoeserver.domain.service.PlayerService; -import com.mycompany.tictactoeserver.domain.service.PlayerSessionService; +import com.mycompany.tictactoeserver.domain.services.player.PlayerService; +import com.mycompany.tictactoeserver.domain.services.playerSession.PlayerSessionService; import java.util.*; import java.util.List; From 116aa17970b9fe6dec88fb4723207c2fe2bbc0a9 Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Tue, 6 Jan 2026 01:19:52 +0200 Subject: [PATCH 09/13] refactor: remove unnecessary interface --- .../services/statistics/StatisticsManager.java | 13 ------------- ...sticsManagerImpl.java => StatisticsService.java} | 9 ++------- 2 files changed, 2 insertions(+), 20 deletions(-) delete mode 100644 src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManager.java rename src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/{StatisticsManagerImpl.java => StatisticsService.java} (90%) diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManager.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManager.java deleted file mode 100644 index 9c45649..0000000 --- a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManager.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.mycompany.tictactoeserver.domain.services.statistics; - -import com.mycompany.tictactoeserver.datasource.model.Player; -import com.mycompany.tictactoeserver.domain.entity.ActivityPoint; -import com.mycompany.tictactoeserver.domain.entity.PlayerEntity; - -import java.util.List; - -public interface StatisticsManager { - List getAllPlayerSessions(); - List getLeaderboard(); - int getTotalPlayersCount(); -} diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManagerImpl.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java similarity index 90% rename from src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManagerImpl.java rename to src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java index eaaf797..b99a9f0 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsManagerImpl.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java @@ -13,16 +13,15 @@ * * @author Tasneem */ -public class StatisticsManagerImpl implements StatisticsManager { +public class StatisticsService { private final PlayerSessionService playerSessionService; private final PlayerService playerService; - public StatisticsManagerImpl(PlayerService playerService) { + public StatisticsService(PlayerService playerService) { this.playerService = playerService; this.playerSessionService = new PlayerSessionService(); } - @Override public List getAllPlayerSessions() { List sessions = playerSessionService.getAllPlayerSessions(); @@ -30,9 +29,6 @@ public List getAllPlayerSessions() { return activityPoints; } - - - @Override public List getLeaderboard() { List players = playerService.getAllPlayers(); @@ -50,7 +46,6 @@ public List getLeaderboard() { return leaderboard; } - @Override public int getTotalPlayersCount() { return playerService.getAllPlayers().size(); } From c5700e4eafd6317e8a105e4ed726c25d2c2f7824 Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Tue, 6 Jan 2026 23:00:02 +0200 Subject: [PATCH 10/13] feat: add online players count functionality --- .../domain/server/GameServerManager.java | 6 ++++++ .../services/statistics/StatisticsService.java | 12 +++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/server/GameServerManager.java b/src/main/java/com/mycompany/tictactoeserver/domain/server/GameServerManager.java index 617f26c..e730534 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/server/GameServerManager.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/server/GameServerManager.java @@ -95,6 +95,12 @@ public void removePlayer(PlayerConnectionHandler player) { players.remove(player); } } + + public int getOnlinePlayersCount() { + synchronized (lock) { + return players.size(); + } + } } class ServerRunnable implements Runnable { diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java index b99a9f0..9d76868 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java @@ -4,6 +4,7 @@ import com.mycompany.tictactoeserver.datasource.model.Session; import com.mycompany.tictactoeserver.domain.entity.ActivityPoint; import com.mycompany.tictactoeserver.domain.entity.PlayerEntity; +import com.mycompany.tictactoeserver.domain.server.GameServerManager; import com.mycompany.tictactoeserver.domain.services.player.PlayerService; import com.mycompany.tictactoeserver.domain.services.playerSession.PlayerSessionService; @@ -16,17 +17,18 @@ public class StatisticsService { private final PlayerSessionService playerSessionService; private final PlayerService playerService; + private final GameServerManager gameServerManager; - public StatisticsService(PlayerService playerService) { + public StatisticsService(PlayerService playerService, GameServerManager gameServerManager, GameServerManager gameServerManager1) { this.playerService = playerService; + this.gameServerManager = gameServerManager1; this.playerSessionService = new PlayerSessionService(); } public List getAllPlayerSessions() { List sessions = playerSessionService.getAllPlayerSessions(); - List activityPoints = new ArrayList<>(); - return activityPoints; + return new ArrayList<>(); } public List getLeaderboard() { @@ -49,4 +51,8 @@ public List getLeaderboard() { public int getTotalPlayersCount() { return playerService.getAllPlayers().size(); } + + public int getOnlinePlayersCount() { + return gameServerManager.getOnlinePlayersCount(); + } } From f95151a098bb1b7e22250e679d8ca02109eab80e Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Wed, 7 Jan 2026 00:15:38 +0200 Subject: [PATCH 11/13] feat: track player sessions and add offline players count --- .../authentication/AuthenticationService.java | 4 ++++ .../services/playerSession/PlayerSessionService.java | 11 ++++------- .../domain/services/statistics/StatisticsService.java | 4 ++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/services/authentication/AuthenticationService.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/authentication/AuthenticationService.java index 8b80e2c..503cb8d 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/services/authentication/AuthenticationService.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/services/authentication/AuthenticationService.java @@ -7,6 +7,7 @@ import com.mycompany.tictactoeserver.domain.services.communication.Header; import com.mycompany.tictactoeserver.domain.services.communication.Message; import com.mycompany.tictactoeserver.domain.services.communication.MessageType; +import com.mycompany.tictactoeserver.domain.services.playerSession.PlayerSessionService; import com.mycompany.tictactoeserver.domain.services.security.ServerSecurityManager; import com.mycompany.tictactoeserver.domain.utils.exception.ExceptionHandlerMiddleware; import com.mycompany.tictactoeserver.domain.utils.exception.HashingException; @@ -18,9 +19,11 @@ public class AuthenticationService { private static AuthenticationService instance; private final PlayerDAO playerDao; + private final PlayerSessionService playerSessionService; private AuthenticationService() { this.playerDao = new PlayerDAO(); + this.playerSessionService = new PlayerSessionService(); } public static AuthenticationService getInstance() { @@ -86,6 +89,7 @@ public Message login(String username, String plainTextPassword) { return new Message(new Header(MessageType.ERROR, Action.LOGIN), json); } + playerSessionService.startPlayerSession(player.getId()); AuthResponseEntity responseEntity = new AuthResponseEntity(player); return new Message(new Header(MessageType.RESPONSE, Action.LOGIN), responseEntity.toJson()); diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/services/playerSession/PlayerSessionService.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/playerSession/PlayerSessionService.java index e07976e..adb570e 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/services/playerSession/PlayerSessionService.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/services/playerSession/PlayerSessionService.java @@ -25,30 +25,27 @@ public List getAllPlayerSessions() { return List.of(); } - public boolean startPlayerSession(String playerId) { + public void startPlayerSession(String playerId) { try { Session session = new Session(playerId); - return sessionDao.startSession(session); + sessionDao.startSession(session); } catch (ActiveSessionExistsException e) { String[] data = {playerId, e.getMessage()}; exceptionHandler.handleException(e, data); - return false; } } - public boolean endPlayerSession(String playerId) { + public void endPlayerSession(String playerId) { try { - return sessionDao.endSessionByPlayerId(playerId); + sessionDao.endSessionByPlayerId(playerId); } catch (SessionNotFoundException e) { String[] data = {playerId}; exceptionHandler.handleException(e, data); - return false; } catch (DataAccessException e) { exceptionHandler.handleException(e); - return false; } } diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java index 9d76868..cec1dae 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java @@ -55,4 +55,8 @@ public int getTotalPlayersCount() { public int getOnlinePlayersCount() { return gameServerManager.getOnlinePlayersCount(); } + + public int getOfflinePlayersCount() { + return getTotalPlayersCount() - getOnlinePlayersCount(); + } } From b0ecc68f36fb0960b160e914f0ec1a5f122472e2 Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Wed, 7 Jan 2026 00:52:50 +0200 Subject: [PATCH 12/13] feat: add online players count per hour functionality --- .../datasource/database/dao/SessionDAO.java | 9 ++--- .../datasource/model/Session.java | 1 - .../domain/entity/ActivityPoint.java | 15 ++++----- .../playerSession/PlayerSessionService.java | 10 ++++++ .../statistics/StatisticsService.java | 33 +++++++++++++++++-- 5 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/mycompany/tictactoeserver/datasource/database/dao/SessionDAO.java b/src/main/java/com/mycompany/tictactoeserver/datasource/database/dao/SessionDAO.java index 91d29a6..fb0028f 100644 --- a/src/main/java/com/mycompany/tictactoeserver/datasource/database/dao/SessionDAO.java +++ b/src/main/java/com/mycompany/tictactoeserver/datasource/database/dao/SessionDAO.java @@ -21,7 +21,7 @@ public SessionDAO() { this.connection = Database.getInstance().getConnection(); } - public boolean startSession(Session session) throws ActiveSessionExistsException { + public void startSession(Session session) throws ActiveSessionExistsException { Session existingSession = getActiveSessionByPlayerId(session.getPlayerId()); if (existingSession != null) { throw new ActiveSessionExistsException(); @@ -34,11 +34,9 @@ public boolean startSession(Session session) throws ActiveSessionExistsException preparedStatement.setTimestamp(3, Timestamp.valueOf(session.getStartTime())); preparedStatement.setTimestamp(4, session.getEndTime() != null ? Timestamp.valueOf(session.getEndTime()) : null); - int rowsAffected = preparedStatement.executeUpdate(); - return rowsAffected > 0; + preparedStatement.executeUpdate(); } catch (SQLException e) { System.err.println("Error starting session: " + e.getMessage()); - return false; } } @@ -58,7 +56,7 @@ public boolean endSession(Session session) throws SessionNotFoundException, Data } } - public boolean endSessionByPlayerId(String playerId) throws SessionNotFoundException, DataAccessException { + public void endSessionByPlayerId(String playerId) throws SessionNotFoundException, DataAccessException { Session activeSession = getActiveSessionByPlayerId(playerId); if (activeSession == null) { throw new SessionNotFoundException(); @@ -70,7 +68,6 @@ public boolean endSessionByPlayerId(String playerId) throws SessionNotFoundExcep preparedStatement.setString(2, activeSession.getId()); int rowsAffected = preparedStatement.executeUpdate(); - return rowsAffected > 0; } catch (SQLException e) { throw new DataAccessException(e.getStackTrace()); } diff --git a/src/main/java/com/mycompany/tictactoeserver/datasource/model/Session.java b/src/main/java/com/mycompany/tictactoeserver/datasource/model/Session.java index 46bec49..8fae2ee 100644 --- a/src/main/java/com/mycompany/tictactoeserver/datasource/model/Session.java +++ b/src/main/java/com/mycompany/tictactoeserver/datasource/model/Session.java @@ -16,7 +16,6 @@ public Session() { public Session(String playerId) { this.startTime = LocalDateTime.now(); this.playerId = playerId; - this.id = UUID.randomUUID().toString(); } public String getId() { diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/entity/ActivityPoint.java b/src/main/java/com/mycompany/tictactoeserver/domain/entity/ActivityPoint.java index 5355a16..358110c 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/entity/ActivityPoint.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/entity/ActivityPoint.java @@ -1,25 +1,24 @@ package com.mycompany.tictactoeserver.domain.entity; -import java.time.LocalDateTime; /** * * @author Tasneem */ public class ActivityPoint { - private LocalDateTime timestamp; + private int hour; private int playerCount; - public ActivityPoint(LocalDateTime timestamp, int playerCount) { - this.timestamp = timestamp; + public ActivityPoint(int hour, int playerCount) { + this.hour = hour; this.playerCount = playerCount; } - public LocalDateTime getTimestamp() { - return timestamp; + public int getHour() { + return hour; } - public void setTimestamp(LocalDateTime timestamp) { - this.timestamp = timestamp; + public void setHour(int hour) { + this.hour = hour; } public int getPlayerCount() { diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/services/playerSession/PlayerSessionService.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/playerSession/PlayerSessionService.java index adb570e..d85bf30 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/services/playerSession/PlayerSessionService.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/services/playerSession/PlayerSessionService.java @@ -4,6 +4,7 @@ import com.mycompany.tictactoeserver.datasource.model.Session; import com.mycompany.tictactoeserver.domain.utils.exception.*; +import java.time.LocalDateTime; import java.util.List; public class PlayerSessionService { @@ -62,4 +63,13 @@ public long getPlayerPlayTime(String playerId) { return 0; } } + + public List getSessionsByDateRange(LocalDateTime startDate, LocalDateTime endDate) { + try{ + return sessionDao.getSessionsByDateRange(startDate, endDate); + } catch (DataAccessException e) { + exceptionHandler.handleException(e); + return List.of(); + } + } } \ No newline at end of file diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java index cec1dae..3d632dc 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java @@ -8,6 +8,7 @@ import com.mycompany.tictactoeserver.domain.services.player.PlayerService; import com.mycompany.tictactoeserver.domain.services.playerSession.PlayerSessionService; +import java.time.LocalDateTime; import java.util.*; import java.util.List; /** @@ -25,10 +26,36 @@ public StatisticsService(PlayerService playerService, GameServerManager gameServ this.playerSessionService = new PlayerSessionService(); } - public List getAllPlayerSessions() { - List sessions = playerSessionService.getAllPlayerSessions(); + public List getOnlinePlayersCountPerHour() { + LocalDateTime now = LocalDateTime.now(); + LocalDateTime twentyFourHoursAgo = now.minusHours(24); - return new ArrayList<>(); + List recentSessions = playerSessionService.getSessionsByDateRange(twentyFourHoursAgo, now); + + if (recentSessions.isEmpty()) { + return new ArrayList<>(); + } + + List activityPoints = new ArrayList<>(); + + for (int i = 0; i < 24; i++) { + LocalDateTime hourStart = twentyFourHoursAgo.plusHours(i).withMinute(0).withSecond(0).withNano(0); + LocalDateTime hourEnd = hourStart.plusHours(1); + int playersOnline = 0; + + for (Session session : recentSessions) { + LocalDateTime sessionStart = session.getStartTime(); + LocalDateTime sessionEnd = session.getEndTime() != null ? session.getEndTime() : now; + + if (sessionStart.isBefore(hourEnd) && sessionEnd.isAfter(hourStart)) { + playersOnline++; + } + } + + activityPoints.add(new ActivityPoint(hourStart.getHour(), playersOnline)); + } + + return activityPoints; } public List getLeaderboard() { From 542cab6c67b4fd199dabb52967e296e7543696bb Mon Sep 17 00:00:00 2001 From: Tasneem AbdElhakeem Date: Wed, 7 Jan 2026 13:07:51 +0200 Subject: [PATCH 13/13] fix: GameServerManager instances duplication --- .../domain/services/statistics/StatisticsService.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java index 3d632dc..f273cfa 100644 --- a/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java +++ b/src/main/java/com/mycompany/tictactoeserver/domain/services/statistics/StatisticsService.java @@ -1,5 +1,6 @@ package com.mycompany.tictactoeserver.domain.services.statistics; +import com.mycompany.tictactoeserver.datasource.database.dao.PlayerDAO; import com.mycompany.tictactoeserver.datasource.model.Player; import com.mycompany.tictactoeserver.datasource.model.Session; import com.mycompany.tictactoeserver.domain.entity.ActivityPoint; @@ -20,9 +21,9 @@ public class StatisticsService { private final PlayerService playerService; private final GameServerManager gameServerManager; - public StatisticsService(PlayerService playerService, GameServerManager gameServerManager, GameServerManager gameServerManager1) { - this.playerService = playerService; - this.gameServerManager = gameServerManager1; + public StatisticsService() { + this.playerService = new PlayerService(new PlayerDAO()); + this.gameServerManager = GameServerManager.getInstance(); this.playerSessionService = new PlayerSessionService(); }