/**
* 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());
}
}