Overview
The Maintenance Proxy API extends the base Maintenance API with additional functionality for managing maintenance mode on individual backend servers in a proxy network. This is available on BungeeCord and Velocity platforms.Getting the Proxy API Instance
The proxy API is accessed through the sameMaintenanceProvider, but cast to MaintenanceProxy:
import eu.kennytv.maintenance.api.MaintenanceProvider;
import eu.kennytv.maintenance.api.proxy.MaintenanceProxy;
import net.md_5.bungee.api.plugin.Plugin;
public class MyBungeePlugin extends Plugin {
private MaintenanceProxy maintenanceProxy;
@Override
public void onEnable() {
// Get the proxy API instance
maintenanceProxy = (MaintenanceProxy) MaintenanceProvider.get();
if (maintenanceProxy == null) {
getLogger().warning("Maintenance plugin not loaded yet!");
return;
}
getLogger().info("Successfully hooked into Maintenance v" + maintenanceProxy.getVersion());
}
}
The
MaintenanceProxy interface extends Maintenance, so you have access to all base API methods plus proxy-specific functionality.Managing Per-Server Maintenance
Control maintenance mode for individual backend servers:import eu.kennytv.maintenance.api.MaintenanceProvider;
import eu.kennytv.maintenance.api.proxy.MaintenanceProxy;
import eu.kennytv.maintenance.api.proxy.Server;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command;
public class ServerMaintenanceCommand extends Command {
private final MaintenanceProxy maintenanceProxy;
public ServerMaintenanceCommand() {
super("servermaintenance", "maintenance.admin", "sm");
this.maintenanceProxy = (MaintenanceProxy) MaintenanceProvider.get();
}
@Override
public void execute(CommandSender sender, String[] args) {
if (maintenanceProxy == null) {
sender.sendMessage("§cMaintenance plugin not available!");
return;
}
if (args.length < 2) {
sender.sendMessage("§cUsage: /servermaintenance <server> <on|off|status>");
return;
}
String serverName = args[0];
String action = args[1].toLowerCase();
// Get the server wrapper
Server server = maintenanceProxy.getServer(serverName);
if (server == null) {
sender.sendMessage("§cServer '" + serverName + "' not found!");
return;
}
switch (action) {
case "on" -> {
boolean changed = maintenanceProxy.setMaintenanceToServer(server, true);
if (changed) {
sender.sendMessage("§aMaintenance enabled for " + serverName);
} else {
sender.sendMessage("§eMaintenance was already enabled for " + serverName);
}
}
case "off" -> {
boolean changed = maintenanceProxy.setMaintenanceToServer(server, false);
if (changed) {
sender.sendMessage("§aMaintenance disabled for " + serverName);
} else {
sender.sendMessage("§eMaintenance was already disabled for " + serverName);
}
}
case "status" -> {
boolean maintenance = maintenanceProxy.isMaintenance(server);
sender.sendMessage("§7Maintenance on " + serverName + ": " +
(maintenance ? "§cEnabled" : "§aDisabled"));
if (maintenanceProxy.isServerTaskRunning(server)) {
sender.sendMessage("§eA timer task is currently running for this server");
}
}
default -> sender.sendMessage("§cUsage: /servermaintenance <server> <on|off|status>");
}
}
}
Listing Servers and Maintenance Status
Get information about all registered servers:import eu.kennytv.maintenance.api.MaintenanceProvider;
import eu.kennytv.maintenance.api.proxy.MaintenanceProxy;
import eu.kennytv.maintenance.api.proxy.Server;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command;
import java.util.Set;
public class MaintenanceListCommand extends Command {
private final MaintenanceProxy maintenanceProxy;
public MaintenanceListCommand() {
super("maintenancelist", "maintenance.admin", "mlist");
this.maintenanceProxy = (MaintenanceProxy) MaintenanceProvider.get();
}
@Override
public void execute(CommandSender sender, String[] args) {
if (maintenanceProxy == null) {
sender.sendMessage("§cMaintenance plugin not available!");
return;
}
// Get all registered servers
Set<String> servers = maintenanceProxy.getServers();
// Get servers currently under maintenance
Set<String> maintenanceServers = maintenanceProxy.getMaintenanceServers();
sender.sendMessage("§7----- Maintenance Status -----");
sender.sendMessage("§7Global Maintenance: " +
(maintenanceProxy.isMaintenance() ? "§cEnabled" : "§aDisabled"));
sender.sendMessage("");
sender.sendMessage("§7Server Status:");
for (String serverName : servers) {
Server server = maintenanceProxy.getServer(serverName);
if (server == null) continue;
boolean inMaintenance = maintenanceServers.contains(serverName);
boolean hasPlayers = server.hasPlayers();
sender.sendMessage("§7- " + serverName + ": " +
(inMaintenance ? "§cMaintenance" : "§aOnline") +
(hasPlayers ? " §7(" + "has players" + ")" : ""));
}
sender.sendMessage("§7Total: " + servers.size() + " servers, " +
maintenanceServers.size() + " in maintenance");
}
}
Working with Server Objects
TheServer interface provides information and actions for backend servers:
import eu.kennytv.maintenance.api.proxy.MaintenanceProxy;
import eu.kennytv.maintenance.api.proxy.Server;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
public void manageServer(MaintenanceProxy proxy, String serverName) {
// Get server wrapper
Server server = proxy.getServer(serverName);
if (server == null) {
System.out.println("Server not found!");
return;
}
// Get server information
String name = server.getName();
boolean hasPlayers = server.hasPlayers();
boolean isRegistered = server.isRegisteredServer();
System.out.println("Server: " + name);
System.out.println("Has players: " + hasPlayers);
System.out.println("Registered: " + isRegistered);
// Broadcast a message to all players on the server
if (hasPlayers) {
Component message = Component.text("Server entering maintenance mode!")
.color(NamedTextColor.RED);
server.broadcast(message);
}
// Enable maintenance on the server
proxy.setMaintenanceToServer(server, true);
}
public void getServerSafely(MaintenanceProxy proxy, String serverName) {
// Use getServerOrDummy to always get a Server object
// (useful when maintenance is disabled on a previously registered server)
Server server = proxy.getServerOrDummy(serverName);
if (!server.isRegisteredServer()) {
System.out.println("Warning: " + serverName + " is not currently registered");
}
}
The
Server.isRegisteredServer() method will return false if maintenance is disabled on a previously registered server that has been removed from the proxy.Handling ServerMaintenanceChangedEvent
Listen for per-server maintenance changes:import eu.kennytv.maintenance.api.MaintenanceProvider;
import eu.kennytv.maintenance.api.event.manager.EventListener;
import eu.kennytv.maintenance.api.proxy.MaintenanceProxy;
import eu.kennytv.maintenance.api.event.proxy.ServerMaintenanceChangedEvent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.md_5.bungee.api.plugin.Plugin;
public class ServerMaintenanceListener extends Plugin {
@Override
public void onEnable() {
MaintenanceProxy proxy = (MaintenanceProxy) MaintenanceProvider.get();
if (proxy == null) {
getLogger().warning("Maintenance plugin not available!");
return;
}
// Register listener for per-server maintenance changes
proxy.getEventManager().registerListener(
new EventListener<ServerMaintenanceChangedEvent>() {
@Override
public void onEvent(ServerMaintenanceChangedEvent event) {
handleServerMaintenanceChange(event);
}
},
ServerMaintenanceChangedEvent.class
);
}
private void handleServerMaintenanceChange(ServerMaintenanceChangedEvent event) {
var server = event.getServer();
boolean maintenance = event.isMaintenance();
if (!server.isRegisteredServer()) {
getLogger().warning("Maintenance changed for unregistered server: " + server.getName());
return;
}
if (maintenance) {
getLogger().info("Server " + server.getName() + " entered maintenance mode");
// Warn players on the server
if (server.hasPlayers()) {
Component warning = Component.text("This server is now in maintenance mode!")
.color(NamedTextColor.RED);
server.broadcast(warning);
}
} else {
getLogger().info("Server " + server.getName() + " exited maintenance mode");
// Notify players
if (server.hasPlayers()) {
Component notice = Component.text("This server is now open!")
.color(NamedTextColor.GREEN);
server.broadcast(notice);
}
}
}
}
Complete Proxy Plugin Example
Here’s a complete BungeeCord plugin that integrates with the Maintenance Proxy API:import eu.kennytv.maintenance.api.MaintenanceProvider;
import eu.kennytv.maintenance.api.event.MaintenanceChangedEvent;
import eu.kennytv.maintenance.api.event.MaintenanceReloadedEvent;
import eu.kennytv.maintenance.api.event.manager.EventListener;
import eu.kennytv.maintenance.api.event.proxy.ServerMaintenanceChangedEvent;
import eu.kennytv.maintenance.api.proxy.MaintenanceProxy;
import eu.kennytv.maintenance.api.proxy.Server;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.Plugin;
import java.util.Set;
public class ProxyMaintenanceIntegration extends Plugin {
private MaintenanceProxy maintenanceProxy;
@Override
public void onEnable() {
// Get the proxy API
maintenanceProxy = (MaintenanceProxy) MaintenanceProvider.get();
if (maintenanceProxy == null) {
getLogger().severe("Maintenance plugin not found! Disabling...");
return;
}
// Register event listeners
registerEventListeners();
// Register commands
getProxy().getPluginManager().registerCommand(this, new MaintenanceInfoCommand());
getLogger().info("Successfully hooked into Maintenance v" + maintenanceProxy.getVersion());
}
private void registerEventListeners() {
var eventManager = maintenanceProxy.getEventManager();
// Listen for global maintenance changes
eventManager.registerListener(
new EventListener<MaintenanceChangedEvent>() {
@Override
public void onEvent(MaintenanceChangedEvent event) {
onGlobalMaintenanceChanged(event.isMaintenance());
}
},
MaintenanceChangedEvent.class
);
// Listen for per-server maintenance changes
eventManager.registerListener(
new EventListener<ServerMaintenanceChangedEvent>() {
@Override
public void onEvent(ServerMaintenanceChangedEvent event) {
onServerMaintenanceChanged(event);
}
},
ServerMaintenanceChangedEvent.class
);
// Listen for config reloads
eventManager.registerListener(
new EventListener<MaintenanceReloadedEvent>() {
@Override
public void onEvent(MaintenanceReloadedEvent event) {
onConfigReloaded();
}
},
MaintenanceReloadedEvent.class
);
}
private void onGlobalMaintenanceChanged(boolean enabled) {
if (enabled) {
getLogger().info("Global maintenance mode enabled");
} else {
getLogger().info("Global maintenance mode disabled");
}
}
private void onServerMaintenanceChanged(ServerMaintenanceChangedEvent event) {
Server server = event.getServer();
boolean maintenance = event.isMaintenance();
getLogger().info("Server " + server.getName() + " maintenance: " + maintenance);
// Broadcast to the affected server
if (server.isRegisteredServer() && server.hasPlayers()) {
Component message = maintenance
? Component.text("This server is now in maintenance mode").color(NamedTextColor.RED)
: Component.text("This server is now operational").color(NamedTextColor.GREEN);
server.broadcast(message);
}
}
private void onConfigReloaded() {
getLogger().info("Maintenance configuration reloaded");
getLogger().info("Servers in maintenance: " + maintenanceProxy.getMaintenanceServers());
}
private class MaintenanceInfoCommand extends Command {
public MaintenanceInfoCommand() {
super("maintenanceinfo", "maintenance.info", "minfo");
}
@Override
public void execute(CommandSender sender, String[] args) {
if (maintenanceProxy == null) {
sender.sendMessage("§cMaintenance API not available!");
return;
}
sender.sendMessage("§7----- Maintenance Information -----");
sender.sendMessage("§7Version: " + maintenanceProxy.getVersion());
sender.sendMessage("§7Global Maintenance: " +
(maintenanceProxy.isMaintenance() ? "§cEnabled" : "§aDisabled"));
Set<String> maintenanceServers = maintenanceProxy.getMaintenanceServers();
sender.sendMessage("§7Servers in Maintenance: " + maintenanceServers.size());
if (!maintenanceServers.isEmpty()) {
sender.sendMessage("§7Maintenance Servers:");
for (String serverName : maintenanceServers) {
Server server = maintenanceProxy.getServer(serverName);
if (server != null) {
sender.sendMessage("§7 - " + serverName +
(server.hasPlayers() ? " §e(has players)" : ""));
}
}
}
sender.sendMessage("§7Whitelisted Players: " +
maintenanceProxy.getSettings().getWhitelistedPlayers().size());
}
}
}
Redis Integration
When Redis is enabled in the Maintenance configuration, per-server maintenance status changes are automatically synchronized across all proxy instances in your network.
public void enableMaintenanceWithRedis(MaintenanceProxy proxy, String serverName) {
Server server = proxy.getServer(serverName);
if (server == null) {
return;
}
// This will automatically sync to Redis if enabled
boolean changed = proxy.setMaintenanceToServer(server, true);
if (changed) {
System.out.println("Maintenance enabled for " + serverName);
System.out.println("Status synchronized to Redis (if enabled)");
}
}
Best Practices
Check server registration
Check server registration
Always verify
server.isRegisteredServer() before performing operations on a server, especially when handling events.Use getServerOrDummy carefully
Use getServerOrDummy carefully
The
getServerOrDummy() method is useful for ensuring you always get a Server object, but remember to check isRegisteredServer() before using it.Handle both global and per-server events
Handle both global and per-server events
When running on a proxy, listen for both
MaintenanceChangedEvent (global) and ServerMaintenanceChangedEvent (per-server) to handle all scenarios.Notify players before kicking
Notify players before kicking
Use
server.broadcast() to warn players before enabling maintenance mode on their server.Next Steps
Basic Usage
Learn basic API operations and usage
Event Listeners
Listen to maintenance events in your plugin