/** * Copyright (C) 2002-2012 The FreeCol Team * * This file is part of FreeCol. * * FreeCol is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * FreeCol is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with FreeCol. If not, see <http://www.gnu.org/licenses/>. */ package net.sf.freecol.metaserver; import java.io.IOException; import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; import net.sf.freecol.FreeCol; import net.sf.freecol.common.networking.Connection; import net.sf.freecol.common.networking.DOMMessage; import org.w3c.dom.Element; /** * The <code>MetaRegister</code> stores information about running servers. * Each server has it's own {@link MetaItem} object. */ public final class MetaRegister { private static Logger logger = Logger.getLogger(MetaRegister.class.getName()); private ArrayList<MetaItem> items = new ArrayList<MetaItem>(); /** * Gets the server entry with the diven address and port. * * @param address The IP-address of the server. * @param port The port number of the server. * @return The server entry or <code>null</code> if the given * entry could not be found. */ private MetaItem getItem(String address, int port) { int index = indexOf(address, port); if (index >= 0) { return items.get(index); } else { return null; } } /** * Gets the index of the server entry with the diven address and port. * * @param address The IP-address of the server. * @param port The port number of the server. * @return The index or <code>-1</code> if the given entry could * not be found. */ private int indexOf(String address, int port) { for (int i=0; i<items.size(); i++) { if (address.equals(items.get(i).getAddress()) && port == items.get(i).getPort()) { return i; } } return -1; } /** * Removes servers that have not sent an update for some time. */ public synchronized void removeDeadServers() { logger.info("Removing dead servers."); long time = System.currentTimeMillis() - MetaServer.REMOVE_OLDER_THAN; for (int i=0; i<items.size(); i++) { if (items.get(i).getLastUpdated() < time) { logger.info("Removing: " + items.get(i)); items.remove(i); } } } /** * Adds a new server with the given attributes. * * @param name The name of the server. * @param address The IP-address of the server. * @param port The port number in which clients may connect. * @param slotsAvailable Number of players that may conncet. * @param currentlyPlaying Number of players that are currently connected. * @param isGameStarted <i>true</i> if the game has started. * @param version The version of the server. * @param gameState The current state of the game. */ public synchronized void addServer(String name, String address, int port, int slotsAvailable, int currentlyPlaying, boolean isGameStarted, String version, int gameState) throws IOException { MetaItem mi = getItem(address, port); if (mi == null) { // Check connection before adding the server: Connection mc = null; try { mc = new Connection(address, port, null, FreeCol.METASERVER_THREAD); mc.send(DOMMessage.createMessage("disconnect")); } catch (IOException e) { logger.log(Level.WARNING, "Server rejected disconnect.", e); throw e; } finally { if (mc != null) mc.close(); } items.add(new MetaItem(name, address, port, slotsAvailable, currentlyPlaying, isGameStarted, version, gameState)); logger.info("Server added:" + address + ":" + port); } else { updateServer(mi, name, address, port, slotsAvailable, currentlyPlaying, isGameStarted, version, gameState); } } /** * Updates a server with the given attributes. * * @param name The name of the server. * @param address The IP-address of the server. * @param port The port number in which clients may connect. * @param slotsAvailable Number of players that may conncet. * @param currentlyPlaying Number of players that are currently connected. * @param isGameStarted <i>true</i> if the game has started. * @param version The version of the server. * @param gameState The current state of the game. */ public synchronized void updateServer(String name, String address, int port, int slotsAvailable, int currentlyPlaying, boolean isGameStarted, String version, int gameState) throws IOException { MetaItem mi = getItem(address, port); if (mi == null) { addServer(name, address, port, slotsAvailable, currentlyPlaying, isGameStarted, version, gameState); } else { updateServer(mi, name, address, port, slotsAvailable, currentlyPlaying, isGameStarted, version, gameState); } } /** * Removes a server from the register. * * @param address The IP-address of the server to remove. * @param port The port number of the server to remove. */ public synchronized void removeServer(String address, int port) { int index = indexOf(address, port); if (index >= 0) { items.remove(index); logger.info("Removing server:" + address + ":" + port); } else { logger.info("Trying to remove non-existing server:" + address + ":" + port); } } /** * Creates a server list. * * @return The server list as an XML DOM Element. */ public synchronized Element createServerList() { Element element = DOMMessage.createMessage("serverList"); for (int i = 0; i < items.size(); i++) { element.appendChild(items.get(i).toXMLElement(element.getOwnerDocument())); } return element; } /** * Updates a given <code>MetaItem</code>. * * @param mi The <code>MetaItem</code> that should be updated. * @param name The name of the server. * @param address The IP-address of the server. * @param port The port number in which clients may connect. * @param slotsAvailable Number of players that may conncet. * @param currentlyPlaying Number of players that are currently connected. * @param isGameStarted <i>true</i> if the game has started. * @param version The version of the server. * @param gameState The current state of the game: * {@link net.sf.freecol.server.FreeColServer.GameState#STARTING_GAME}, * {@link net.sf.freecol.server.FreeColServer.GameState#IN_GAME} or * {@link net.sf.freecol.server.FreeColServer.GameState#ENDING_GAME}. */ private void updateServer(MetaItem mi, String name, String address, int port, int slotsAvailable, int currentlyPlaying, boolean isGameStarted, String version, int gameState) { mi.update(name, address, port, slotsAvailable, currentlyPlaying, isGameStarted, version, gameState); logger.info("Server updated:" + mi.toString()); } }