From 8b1d001ac06875e61c5df9adcab7bd093bf56c4f Mon Sep 17 00:00:00 2001 From: Jonah Bauer Date: Mon, 31 Jan 2022 23:25:09 +0100 Subject: [PATCH] JMX --- .../eu/jonahbauer/wizard/server/Lobby.java | 79 ++++++++++++++++++- .../eu/jonahbauer/wizard/server/Session.java | 29 ++++++- .../wizard/server/debug/DebugSession.java | 17 ++-- .../wizard/server/machine/Player.java | 13 ++- .../wizard/server/management/LobbyMBean.java | 11 +++ .../server/management/SessionMBean.java | 19 +++++ 6 files changed, 148 insertions(+), 20 deletions(-) create mode 100644 wizard-server/src/main/java/eu/jonahbauer/wizard/server/management/LobbyMBean.java create mode 100644 wizard-server/src/main/java/eu/jonahbauer/wizard/server/management/SessionMBean.java diff --git a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Lobby.java b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Lobby.java index 6423853..0a1bfa8 100644 --- a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Lobby.java +++ b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Lobby.java @@ -4,14 +4,22 @@ import eu.jonahbauer.wizard.common.messages.server.*; import eu.jonahbauer.wizard.common.model.Configuration; import eu.jonahbauer.wizard.server.debug.DebugSession; import eu.jonahbauer.wizard.server.machine.Player; +import eu.jonahbauer.wizard.server.management.LobbyMBean; +import eu.jonahbauer.wizard.server.management.SessionMBean; +import lombok.extern.log4j.Log4j2; import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.NotNull; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.StandardMBean; +import java.lang.management.ManagementFactory; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; -public class Lobby { +@Log4j2 +public class Lobby implements LobbyMBean { @Language("RegExp") private static final String SESSION_NAME_PATTERN = "[a-zA-Z0-9_' ]{1,20}"; private static final Lobby INSTANCE = new Lobby(); @@ -19,12 +27,17 @@ public class Lobby { return INSTANCE; } + private final MBeanServer mBeanServer; + private final Map sessions = new ConcurrentHashMap<>(); private final List players = new ArrayList<>(); // read lock is required whenever players are read or sessions are modified, write lock is required when players are modified private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - private Lobby() {} + private Lobby() { + mBeanServer = ManagementFactory.getPlatformMBeanServer(); + registerLobbyMBean(); + } public Session createSession(@NotNull String name, long timeout, @NotNull Configuration configuration) { if (!name.matches(SESSION_NAME_PATTERN)) { @@ -42,6 +55,9 @@ public class Lobby { session = new Session(UUID.randomUUID(), name, timeout, configuration); } while (sessions.putIfAbsent(session.getUuid(), session) != null); + log.info("Created session {}.", session.getUuid()); + registerSessionMBean(session); + notifyPlayers(new SessionCreatedMessage(session.toData())); return session; @@ -58,6 +74,9 @@ public class Lobby { session = new DebugSession(UUID.randomUUID(), name, timeout, configuration); } while (sessions.putIfAbsent(session.getUuid(), session) != null); + log.info("Created debug session {}.", session.getUuid()); + registerSessionMBean(session); + notifyPlayers(new SessionCreatedMessage(session.toData())); return session; @@ -73,8 +92,11 @@ public class Lobby { public void removeSession(UUID uuid) { lock.readLock().lock(); try { - sessions.remove(uuid); - notifyPlayers(new SessionRemovedMessage(uuid)); + if (sessions.remove(uuid) != null) { + log.info("Removed session {}.", uuid); + unregisterSessionMBean(uuid); + notifyPlayers(new SessionRemovedMessage(uuid)); + } } finally { lock.readLock().unlock(); } @@ -117,4 +139,53 @@ public class Lobby { lock.readLock().unlock(); } } + + // + private void registerLobbyMBean() { + try { + var name = new ObjectName("eu.jonahbauer.wizard.server:type=Lobby"); + mBeanServer.registerMBean(new StandardMBean(this, LobbyMBean.class), name); + } catch (Exception e) { + log.warn("Could not register LobbyMBean.", e); + } + } + + private void registerSessionMBean(@NotNull Session session) { + try { + var name = new ObjectName("eu.jonahbauer.wizard.server:type=Session,name=" + session.getUuid()); + mBeanServer.registerMBean(new StandardMBean(session, SessionMBean.class), name); + } catch (Exception e) { + log.warn("Could not register SessionMBean for session {}.", session.getUuid(), e); + } + } + + private void unregisterSessionMBean(@NotNull UUID uuid) { + try { + var name = new ObjectName("eu.jonahbauer.wizard.server:type=Session,name=" + uuid); + mBeanServer.unregisterMBean(name); + } catch (Exception e) { + log.warn("Could not unregister SessionMBean for session {}.", uuid, e); + } + } + + @Override + public int getPlayerCount() { + lock.readLock().lock(); + try { + return players.size(); + } finally { + lock.readLock().unlock(); + } + } + + @Override + public int getTotalPlayerCount() { + return sessions.values().stream().mapToInt(Session::getPlayerCount).sum() + getPlayerCount(); + } + + @Override + public int getSessionCount() { + return sessions.size(); + } + // } diff --git a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Session.java b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Session.java index e85d06c..406f40e 100644 --- a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Session.java +++ b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Session.java @@ -1,6 +1,5 @@ package eu.jonahbauer.wizard.server; -import eu.jonahbauer.wizard.common.messages.client.InteractionMessage; import eu.jonahbauer.wizard.common.messages.data.PlayerData; import eu.jonahbauer.wizard.common.messages.data.SessionData; import eu.jonahbauer.wizard.common.messages.observer.ObserverMessage; @@ -14,6 +13,7 @@ import eu.jonahbauer.wizard.core.messages.Observer; import eu.jonahbauer.wizard.core.model.Configurations; import eu.jonahbauer.wizard.core.util.Pair; import eu.jonahbauer.wizard.server.machine.Player; +import eu.jonahbauer.wizard.server.management.SessionMBean; import lombok.AccessLevel; import lombok.Data; import lombok.EqualsAndHashCode; @@ -29,7 +29,7 @@ import java.util.concurrent.ThreadLocalRandom; @Getter @Log4j2 @EqualsAndHashCode(of = "uuid") -public class Session implements Observer { +public class Session implements Observer, SessionMBean { @Language("RegExp") private static final String PLAYER_NAME_PATTERN = "[a-zA-Z0-9_' ]{1,20}"; protected static final int MIN_PLAYERS = 3; @@ -271,6 +271,31 @@ public class Session implements Observer { } } + public void close() { + for (var sessionPlayer : getPlayers().values()) { + var player = sessionPlayer.getPlayer(); + if (player != null) { + player.disconnect("Session was forcibly closed."); + } + } + } + + // + @Override + public boolean isRunning() { + return game != null; + } + + public boolean isDebug() { + return false; + } + + @Override + public synchronized int getPlayerCount() { + return players.size(); + } + // + @Data @EqualsAndHashCode(of = "uuid") protected static class SessionPlayer { diff --git a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/debug/DebugSession.java b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/debug/DebugSession.java index 1bf8c4c..2aceaa0 100644 --- a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/debug/DebugSession.java +++ b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/debug/DebugSession.java @@ -10,7 +10,6 @@ import eu.jonahbauer.wizard.server.NackException; import eu.jonahbauer.wizard.server.Session; import eu.jonahbauer.wizard.server.machine.Player; -import java.io.IOException; import java.util.UUID; public class DebugSession extends Session { @@ -60,19 +59,13 @@ public class DebugSession extends Session { @Override protected void startGame() {} - public void close() { - for (var sessionPlayer : getPlayers().values()) { - try { - var player = sessionPlayer.getPlayer(); - if (player != null) { - player.disconnect(); - } - } catch (IOException ignored) {} - } - } - @Override public void notifyPlayers(ServerMessage message) { super.notifyPlayers(message); } + + @Override + public boolean isDebug() { + return true; + } } diff --git a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/machine/Player.java b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/machine/Player.java index 2915ae0..c88b9c0 100644 --- a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/machine/Player.java +++ b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/machine/Player.java @@ -6,6 +6,7 @@ import eu.jonahbauer.wizard.common.messages.server.Response; import eu.jonahbauer.wizard.common.messages.server.ServerMessage; import eu.jonahbauer.wizard.server.machine.states.CreatedState; import lombok.SneakyThrows; +import org.jetbrains.annotations.Nullable; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; @@ -44,8 +45,16 @@ public class Player extends Context { shouldBuffer = Response.class; } - public void disconnect() throws IOException { - session.close(CloseStatus.SERVER_ERROR); + public void disconnect() { + disconnect(null); + } + + public void disconnect(@Nullable String reason) { + try { + session.close(new CloseStatus(CloseStatus.GOING_AWAY.getCode(), reason)); + } catch (IOException ignored) { + // ignored + } } @SneakyThrows diff --git a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/management/LobbyMBean.java b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/management/LobbyMBean.java new file mode 100644 index 0000000..872029f --- /dev/null +++ b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/management/LobbyMBean.java @@ -0,0 +1,11 @@ +package eu.jonahbauer.wizard.server.management; + +@SuppressWarnings("unused") +public interface LobbyMBean { + + int getPlayerCount(); + + int getTotalPlayerCount(); + + int getSessionCount(); +} diff --git a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/management/SessionMBean.java b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/management/SessionMBean.java new file mode 100644 index 0000000..161bc53 --- /dev/null +++ b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/management/SessionMBean.java @@ -0,0 +1,19 @@ +package eu.jonahbauer.wizard.server.management; + +import java.util.UUID; + +@SuppressWarnings("unused") +public interface SessionMBean { + + UUID getUuid(); + + String getName(); + + int getPlayerCount(); + + boolean isRunning(); + + boolean isDebug(); + + void close(); +}