OpenNapServerManager.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
org.xnap.plugin.opennap.net |
![]() |
![]() |
XNap 3 |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/*
* XNap - A P2P framework and client.
*
* See the file AUTHORS for copyright information.
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.xnap.plugin.opennap.net;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.log4j.Logger;
import org.xnap.XNap;
import org.xnap.event.ListListener;
import org.xnap.event.ListSupport;
import org.xnap.event.StatusListener;
import org.xnap.io.Library;
import org.xnap.io.MetaInfoFile;
import org.xnap.io.MetaInfoManager;
import org.xnap.net.NetHelper;
import org.xnap.plugin.opennap.OpenNapPlugin;
import org.xnap.plugin.opennap.net.msg.ExceptionListener;
import org.xnap.plugin.opennap.net.msg.MessageHandler;
import org.xnap.plugin.opennap.net.msg.client.AddHotlistEntryMessage;
import org.xnap.plugin.opennap.net.msg.client.ShareFileMessage;
import org.xnap.plugin.opennap.user.OpenNapGlobalUser;
import org.xnap.plugin.opennap.util.OpenNapPreferences;
import org.xnap.search.SearchManager;
import org.xnap.util.Formatter;
import org.xnap.util.IllegalOperationException;
import org.xnap.util.Notifier;
import org.xnap.util.PortRange;
import org.xnap.util.Range;
import org.xnap.util.Scheduler;
import org.xnap.util.XNapTask;
public class OpenNapServerManager implements PropertyChangeListener {
//--- Constant(s) ---
//--- Data field(s) ---
private static Logger logger = Logger.getLogger(OpenNapServerManager.class);
private OpenNapPreferences napPrefs = OpenNapPlugin.getPreferences();
private String stats;
private OpenNapListener listener = new OpenNapListener();
protected ListSupport ls = new ListSupport(this);
/**
* A list of {@link StatusListener} objects.
*/
private LinkedList sl = new LinkedList();
/**
* Set to true by {@link #add(OpenNapServer,boolean)} if a
* temporary server has been added.
*/
private boolean addedTemporary = false;
/**
* A list of {@link OpenNapServer} objects.
*/
private List servers = new ArrayList();
/**
* A list of connected {@link OpenNapServer} objects.
*
* @see #setConnected(OpenNapServer, boolean)
*/
private List connectedServers = new LinkedList();
/**
* A list of {@link OpenNapNetwork} objects.
*/
private HashMap networkByName = new HashMap();
private AutoConnector connector = new AutoConnector();
/**
* The indes of the next repository file to share.
*
* @see PostLoginRunner.shareFiles()
*/
private int repositoryIndex = 0;
private AutoFetchTask autoFetchTask;
/**
* Set to true once downloads have been auto resumed.
*/
private boolean resumed = false;
//--- Constructor(s) ---
public OpenNapServerManager()
{
OpenNapPlugin.getPreferences().addPropertyChangeListener(this);
// Repository.getInstance().addListListener(this);
// use the "Other" network as a fallback
networkByName.put("", new OpenNapDefaultNetwork());
updateStats();
}
//--- Method(s) ---
/**
* <code>listener</code> is notified when a server is added or removed.
*/
public void addListListener(ListListener listener)
{
ls.addListListener(listener);
}
public void removeListListener(ListListener listener)
{
ls.removeListListener(listener);
}
/**
* <code>listener</code> is notified when a server is added or removed.
*/
public synchronized void addStatsListener(StatusListener listener)
{
sl.add(listener);
}
public synchronized void removeStatsListener(StatusListener listener)
{
sl.remove(listener);
}
public boolean add(String url, String network, boolean login)
{
StringTokenizer s = new StringTokenizer(url, ":");
if (s.countTokens() != 2) {
return false;
}
String ip = s.nextToken();
int port = 0;
try {
port = Integer.parseInt(s.nextToken());
}
catch (NumberFormatException e) {
}
if (ip.length() == 0
|| port < PortRange.MIN_PORT || port > PortRange.MAX_PORT) {
return false;
}
OpenNapServer server = new OpenNapServer(ip, port, network);
add(server, true);
// if (login) {
// server.connect();
// }
return true;
}
/**
* Adds <code>server</code> if it is not already in the list.
*
* @return true, if the server was added; false, otherwise
*/
public boolean add(OpenNapServer server, boolean login)
{
synchronized (this) {
// keep servers sorted by lastConnect, higher values come first
int index = 0;
for (int i = 0; i < servers.size(); i++) {
OpenNapServer next = (OpenNapServer)servers.get(i);
if (next.equals(server)) {
// we already have the server
return false;
}
if (next.getLastConnect() > server.getLastConnect()) {
index++;
}
}
OpenNapNetwork network = getNetworkByName(server.getNetworkName());
server.setNetwork(network);
server.setListener(listener);
servers.add(index, server);
addedTemporary |= server.isTemporary();
server.addPropertyChangeListener(this);
ls.fireItemAdded(server);
network.add(server);
}
if (login) {
server.connect();
}
connector.wakeup();
return true;
}
/**
* Returns the number of servers that were added.
*/
public int addFrom(OpenNapServerReader reader, boolean temporary)
throws IOException
{
int count = 0;
try {
reader.open();
OpenNapServer s;
while ((s = reader.read()) != null) {
s.setTemporary(temporary);
if (s.getAutoConnect()) {
if (add(s, true)) {
count++;
}
}
else {
if (add(s, false)) {
count++;
}
}
}
}
finally {
reader.close();
}
return count;
}
public void die()
{
setAutoFetchInterval(-1);
OpenNapPlugin.getPreferences().removePropertyChangeListener(this);
connector.die();
try {
saveTo(new OpenNapServerFileWriter(napPrefs.getServerFile()), false);
}
catch (IOException e) {
logger.debug("could not write file", e);
}
if (addedTemporary) {
try {
saveTo(new OpenNapServerFileWriter(napPrefs.getNapigatorFile()), true);
}
catch (IOException e) {
logger.debug("could not write file", e);
}
}
removeAll();
listener.die();
}
public void fetchServerLists()
{
Notifier.info(XNap.tr("Downloading list of OpenNap servers") + "...");
Runnable r = new Runnable()
{
public void run()
{
String urls
= OpenNapPlugin.getPreferences().getNapigatorURL();
StringTokenizer t = new StringTokenizer(urls, "\n");
while (t.hasMoreTokens()) {
String url = t.nextToken().trim();
if (!url.startsWith("#")) {
try {
addFrom(new NapigatorReader(url), true);
}
catch (IOException e) {
Notifier.error(XNap.tr("Could not get list of OpenNap servers: {0}", NetHelper.getErrorMessage(e)), e);
}
}
}
updateStats();
}
};
Thread t = new Thread(r, "AskNapigator");
t.start();
}
public void remove(OpenNapServer server)
{
try {
server.disconnect();
}
catch (IllegalOperationException e) {
// ignore exception, server might not be connected at all
}
synchronized (this) {
server.removePropertyChangeListener(this);
servers.remove(server);
ls.fireItemRemoved(server);
}
}
public synchronized void removeAll()
{
for (Iterator i = servers.iterator(); i.hasNext();) {
OpenNapServer server = (OpenNapServer)i.next();
try {
server.disconnect();
}
catch (IllegalOperationException e) {
// ignore exception, server might not be connected at all
}
server.removePropertyChangeListener(this);
}
servers.clear();
}
public synchronized OpenNapServer getServerByHost(String host)
{
for (Iterator i = servers.iterator(); i.hasNext();) {
OpenNapServer s = (OpenNapServer)i.next();
if (s.getHost().equals(host)) {
return s;
}
}
return null;
}
public AutoConnector getConnector()
{
return connector;
}
public synchronized int getConnectedCount()
{
return connectedServers.size();
}
public synchronized OpenNapServer[] getConnectedServers()
{
return (OpenNapServer[])connectedServers.toArray(new OpenNapServer[0]);
}
public OpenNapNetwork getNetworkByName(String name)
{
OpenNapNetwork n = (OpenNapNetwork)networkByName.get(name);
if (n == null) {
n = new OpenNapNetwork(name);
networkByName.put(name, n);
}
return n;
}
public synchronized OpenNapServer[] getServers()
{
return (OpenNapServer[])servers.toArray(new OpenNapServer[0]);
}
/**
* Returns the stats that were calculated during the last call to
* {@link #updateStats()}.
*/
public String getStats()
{
return stats;
}
public void init()
{
updateListener();
Thread t = new Thread(new InitRunner(), "OpenNapServerManagerInit");
t.start();
}
public void changeNetwork(OpenNapServer server, String newNetworkName)
{
if (!newNetworkName.equals(server.getNetworkName())) {
OpenNapNetwork oldNetwork = server.getNetwork();
oldNetwork.remove(server);
OpenNapNetwork newNetwork = getNetworkByName(newNetworkName);
server.setNetwork(newNetwork);
newNetwork.add(server);
}
}
public int saveTo(OpenNapServerWriter writer, boolean temporary)
throws IOException
{
int count = 0;
try {
writer.open();
for (Iterator i = servers.iterator(); i.hasNext();) {
OpenNapServer s = (OpenNapServer)i.next();
if (s.isTemporary() == temporary) {
writer.write(s);
count++;
}
}
}
finally {
writer.close();
}
return count;
}
public int saveTo(OpenNapServerWriter writer)
throws IOException
{
int count = 0;
try {
writer.open();
for (Iterator i = servers.iterator(); i.hasNext();) {
OpenNapServer s = (OpenNapServer)i.next();
writer.write(s);
count++;
}
}
finally {
writer.close();
}
return count;
}
/**
* Sets the interval for the auto fetch task.
*
* @param interval the auto fetch interval in milli seconds; if <= 0,
* auto fetching is disabled */
public synchronized void setAutoFetchInterval(long interval)
{
if (interval <= 0) {
if (autoFetchTask != null) {
autoFetchTask.cancel();
autoFetchTask = null;
}
}
else {
autoFetchTask = new AutoFetchTask();
Scheduler.run(0, interval, autoFetchTask);
}
}
/**
* Invoked by {@link OpenNapServer} objects once their state
* changes to connected. */
void setConnected(OpenNapServer server, boolean connected)
{
synchronized (connectedServers) {
synchronized (this) {
if (connected) {
connectedServers.add(server);
Thread t
= new Thread(new PostLoginRunner(server), "PostLogin");
t.start();
}
else {
connectedServers.remove(server);
}
}
int size = connectedServers.size();
if (size == 1) {
SearchManager.getInstance().add
(OpenNapPlugin.getSearchManager());
}
else if (size == 0) {
SearchManager.getInstance().remove
(OpenNapPlugin.getSearchManager());
}
if (!resumed
&& napPrefs.getAutoResumeDownloads()
&& size == napPrefs.getAutoResumeConnectedCount()) {
resumed = true;
OpenNapPlugin.getTransferManager().startAllDownloads();
}
}
updateStats();
}
public void propertyChange(PropertyChangeEvent e)
{
String p = e.getPropertyName();
if (p.equals("stats")) {
updateStats();
}
else if (p.equals("firewalled") || p.equals("localPort")) {
updateListener();
}
else if (p.equals("autoFetchNapigator")
|| p.equals("autoFetchNapigatorInterval")) {
updateAutoFetch();
}
}
private void updateAutoFetch()
{
setAutoFetchInterval
(napPrefs.getAutoFetchNapigator()
? napPrefs.getAutoFetchNapigatorInterval() * 60 * 60 * 1000
: -1);
}
private void updateListener()
{
if (napPrefs.getFirewalled()) {
listener.setPortRange(null);
}
else {
PortRange range = new PortRange(napPrefs.getLocalPortRange());
listener.setPortRange(range);
if (listener.getPort() == 0) {
logger.info(XNap.tr("Could not start listener (check local port)"));
}
}
}
/**
* Iterates through all servers and notifies the stats listeners.
*/
private synchronized void updateStats()
{
long userCount = 0;
long fileCount = 0;
long fileSize = 0;
if (connectedServers.size() > 0) {
for (Iterator i = connectedServers.iterator(); i.hasNext();) {
OpenNapServer s = (OpenNapServer)i.next();
userCount += s.getUserCount();
fileCount += s.getFileCount();
fileSize += s.getFileSize();
}
// gb -> byte
fileSize = fileSize * 1024 * 1024 * 1024;
StringBuffer sb = new StringBuffer();
sb.append(Formatter.formatNumber(connectedServers.size()));
sb.append(" " + XNap.tr("of") + " ");
sb.append(Formatter.formatNumber(servers.size()));
sb.append(" " + XNap.tr("Servers") + " / ");
sb.append(Formatter.formatNumber(userCount));
sb.append(" " + XNap.tr("Users") + " / ");
sb.append(Formatter.formatNumber(fileCount));
sb.append(" " + XNap.tr("Files") + " / ");
sb.append(Formatter.formatSize(fileSize));
sb.append(" " + XNap.tr("Shared"));
stats = sb.toString();
}
else {
stats = XNap.tr("{0} Servers (Not Connected)",
new Integer(servers.size()));
}
for (Iterator i = sl.iterator(); i.hasNext();) {
((StatusListener)i.next()).setStatus(stats);
}
}
/**
* Spin-locks until library is read. */
private void waitUntilLibraryIsRead()
{
while (!Library.getInstance().isRead()) {
try {
Thread.sleep(512);
}
catch (InterruptedException e) {
return;
}
}
}
//--- Inner Class(es) ---
private class InitRunner implements Runnable
{
public void run()
{
try {
String filename = napPrefs.getServerFile();
addFrom(new OpenNapServerFileReader(filename), false);
}
catch (IOException e) {
logger.debug("Could not add hosts from file" , e);
}
if (napPrefs.getAutoLoadNapigator()) {
try {
String filename = napPrefs.getNapigatorFile();
addFrom(new OpenNapServerFileReader(filename), true);
}
catch (IOException e) {
logger.debug("Could not add hosts from file" , e);
}
}
updateAutoFetch();
}
}
private class ServerIterator {
private int start;
private boolean looped;
private int next = 0;
/**
* This needs to called prior to each cycle.
*/
public void init()
{
start = next;
looped = false;
}
/**
* Called by AutoConnector to cycle through servers.
*/
public OpenNapServer getNext()
{
synchronized (OpenNapServerManager.this) {
if (servers.isEmpty()) {
return null;
}
if (next > servers.size()) {
if (looped) {
return null;
}
if (start > servers.size() - 1) {
start = servers.size() - 1;
}
next = 0;
looped = true;
}
int index = next;
next++;
if (next >= servers.size()) {
next = 0;
looped = true;
}
if (looped && next >= start) {
return null;
}
return (OpenNapServer)servers.get(index);
}
}
}
public class AutoConnector implements Runnable
{
private boolean die = false;
private boolean enabled = false;
private Thread runner;
private ServerIterator iterator = new ServerIterator();
void die()
{
die = true;
synchronized (this) {
this.notify();
}
}
public synchronized boolean isEnabled()
{
return enabled;
}
public synchronized void setEnabled(boolean newValue)
{
enabled = newValue;
if (enabled) {
if (runner != null) {
wakeup();
}
else {
runner = new Thread(this, "OpenNapConnector");
runner.start();
}
}
}
public void wakeup()
{
if (isEnabled()) {
synchronized (this) {
this.notify();
}
}
}
/**
* Auto connects servers.
*/
public void run()
{
waitUntilLibraryIsRead();
while (!die) {
int left = 2 * (napPrefs.getMaxAutoconnectServers()
- connectedServers.size());
left -= OpenNapNetwork.getTotalConnecting();
iterator.init();
OpenNapServer s;
while ((s = iterator.getNext()) != null && left > 0
&& enabled) {
if (!s.getNetwork().isBusy() && s.isDisconnected()) {
long t = s.getNextAutoConnectTime();
if (t >= 0 && System.currentTimeMillis() >= t) {
s.connect();
left--;
}
}
}
synchronized (this) {
try {
if (enabled) {
this.wait(OpenNapServer.FAILED_INTERVAL);
}
else {
this.wait();
}
}
catch (InterruptedException e) {
}
}
}
}
}
public class PostLoginRunner implements Runnable, ExceptionListener {
OpenNapServer server;
boolean die;
public PostLoginRunner(OpenNapServer server)
{
this.server = server;
}
public void exceptionThrown(Exception e)
{
die = true;
}
public void run()
{
sendHotlist();
shareFiles();
}
public void sendHotlist()
{
// add hotlist users
OpenNapGlobalUser[] users
= OpenNapPlugin.getUserManager().getHotlistUsers();
for (int i = 0; i < users.length && !die; i++) {
AddHotlistEntryMessage msg
= new AddHotlistEntryMessage(users[i].getName());
msg.setExceptionListener(this);
MessageHandler.send(server, msg);
}
}
public void shareFiles()
{
waitUntilLibraryIsRead();
int size = Library.getInstance().size();
if (size == 0) {
return;
}
// share files
if (napPrefs.getLimitSharesPerServer()) {
boolean looped = false;
int toShare = napPrefs.getMaxSharesPerServer();
int start;
int next;
synchronized(OpenNapServerManager.this) {
if (repositoryIndex >= size) {
repositoryIndex = 0;
}
start = repositoryIndex;
next = start;
repositoryIndex += toShare;
}
while (toShare > 0 && !die) {
if (shareFile(next)) {
toShare--;
}
next++;
if (next >= size) {
server.setShared(new Range(start, size - 1));
next = 0;
looped = true;
}
if (next >= start && looped) {
break;
}
}
if (looped) {
if (next > 0) {
server.setShared(new Range(0, next - 1));
}
}
else {
server.setShared(new Range(start, next - 1));
}
synchronized(OpenNapServerManager.this) {
repositoryIndex = next;
}
}
else {
for (int i = 0; i < size; i++) {
shareFile(i);
}
server.setShared(new Range(0, size - 1));
}
}
/**
* Returns the number of files that have been shared.
*
* @return -1, if server disconnected
*/
public boolean shareFile(int index)
{
MetaInfoFile f = Library.getInstance().get(index);
if (f != null && f.isShared()) {
MetaInfoManager.handle(f);
ShareFileMessage msg = new ShareFileMessage(index, f);
msg.setExceptionListener(this);
MessageHandler.send(server, msg);
return true;
}
return false;
}
}
private class AutoFetchTask extends XNapTask {
public AutoFetchTask()
{
}
public void run()
{
fetchServerLists();
}
}
// public synchronized void elementAdded(ListEvent e)
// {
// if (e.getSource() == Repository.getInstance()) {
// if (!napPrefs.getLimitSharesPerOpenNapServer()) {
// RepositoryFile f = (RepositoryFile)e.getElement();
// MessageHandler.send(new ShareFileMessage(e.getIndex(), f));
// }
// }
// }
// public synchronized void elementRemoved(ListEvent e)
// {
// if (e.getSource() == Repository.getInstance()) {
// // FIX ME: check if file is really shared
// RepositoryFile f = (RepositoryFile)e.getElement();
// MessageHandler.send(new UnshareFileMessage(e.getIndex(), f));
// }
// }
}
The table below shows all metrics for OpenNapServerManager.java.



