Package xnap.plugin.nap.net

Source Code of xnap.plugin.nap.net.Server

/*
*  XNap
*
*  A pure java file sharing client.
*
*  See 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; either version 2 of the License, or
*  (at your option) any later version.
*
*  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 xnap.plugin.nap.net;

import xnap.XNap;
import xnap.net.*;
import xnap.plugin.nap.Plugin;
import xnap.plugin.nap.net.msg.MessageHandler;
import xnap.plugin.nap.net.msg.SendQueue;
import xnap.plugin.nap.net.msg.MessageStrings;
import xnap.plugin.nap.net.msg.client.ClientMessage;
import xnap.plugin.nap.net.msg.client.ListChannelsMessage;
import xnap.plugin.nap.net.msg.client.NickCheckMessage;
import xnap.plugin.nap.net.msg.server.*;
import xnap.plugin.nap.util.Channel;
import xnap.plugin.nap.util.NapPreferences;
import xnap.util.*;
import xnap.util.prefs.StringValidator;
import xnap.io.*;

import java.beans.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.text.MessageFormat;
import org.apache.log4j.Logger;

public class Server extends AbstractRunnable implements IChatServer, Runnable {

    //--- Constant(s) ---

    // wait 30 seconds for login ack
    //public static final int LOGIN_TIMEOUT = 30 * 1000;
    public static final int SOCKET_TIMEOUT = 1 * 1000;

  public static final int MAX_RETRY_ON_CONNECTION_REFUSED = 3;

    public static final int STATUS_NOT_CONNECTED = 0;
    public static final int STATUS_CONNECTING    = 1;
    public static final int STATUS_CONNECTED     = 2;
    public static final int STATUS_LOGIN_FAILED  = 4;
    // recoverable error
    public static final int STATUS_FAILED        = 5;
    // unrecoverable error
    public static final int STATUS_ERROR         = 6;
    // FIX ME
    public static final int STATUS_NEW_STATS     = 7;

    public static final String[] STATUS_MSGS = {
    "", Plugin.tr("connecting") + "...", Plugin.tr("connected"),
    Plugin.tr("login failed"), Plugin.tr("failed"),
    Plugin.tr("connected"), Plugin.tr("error"),
    };

    //--- Data field(s) ---

    protected static Logger logger = Logger.getLogger(Server.class);
    protected static Preferences prefs = Preferences.getInstance();

    private String remoteHost;
    private int remotePort;
    private String remoteIP = null;
    private String network;
    private int userCount = -1;
    private String username = null;
    private String password = null;
    private String email = null;
    private boolean newUser;
    private int fileCount = -1;
    private int fileSize = -1;
    private int ping = -1;
    /**
     * Server was fetched from index service.
     */
    private boolean temporay = false;
    private boolean redirector = false;

    private String redirectedHost;
    private int redirectedPort;

    private Socket socket;
    private InputStream in;
    private OutputStream out;
    private long lastLogin = 0;
    private NapListener listener = null;
    protected Search currentSearch = null;
    protected Browse currentBrowse = null;
    /**
     * Remembers the last <code>ErrorMessage</code>.
     */
    protected String lastError;

    /**
     * Queue of pending searches.
     */
    private PriorityQueue searchQueue = new PriorityQueue();

    /**
     * Queue of pending browses.
     */
    private LinkedList browseQueue = new LinkedList();

    /**
     * Queue of pending messages.
     */
    //private SendQueue sendQueue = new SendQueue(this);

    /* contains last n searchesTexts and their collectors */
    private SearchResultCache searchCache = new SearchResultCache();
    private long lastSearch = 0;
    /**
     * Hashes nick to user objects.
     */
    protected Hashtable users = new Hashtable();
    protected int searchCount = 0;
    /**
     * Hashes channel names to <code>Channel</code> objects.
     */
    protected Hashtable channels = new Hashtable();
    protected ServerVersion version = ServerVersion.UNKNOWN;
    protected Range shared;

    // do not flood server
    private int maxPacketsPerTick
    = NapPreferences.getInstance().getMaxPacketsPerTick();
    private long tickLength
    = NapPreferences.getInstance().getTickLength();
    private long writeTickPacketCount = 0;
    private long writeTickStart = 0;

    //--- Constructor(s) ---

    public Server(String host, String ip, int port, String network,
          int fileCount, int fileSize, int userCount)
    {
    status = STATUS_NOT_CONNECTED;

    this.remoteHost = host;
    this.remoteIP = ip;
    this.remotePort = port;
    this.network = network;
    this.userCount = userCount;
    this.fileCount = fileCount;
    this.fileSize = fileSize;
    }

    public Server(String host, int port, String network)
    {
    this(host, null, port, network, -1, -1, -1);
    }

    public Server(String host, int port)
    {
    this(host, port, "");
    }

    public Server()
    {
    this("", 8888);
    }

    //--- Method(s) ---

    public boolean isConnected()
    {
    return (status == STATUS_CONNECTED);
    }

    public boolean isLoginCustomized()
    {
    return (username != null) || (password != null) || (email != null);
    }

    /**
     * The server is accepting messages.
     */
    public boolean isReady()
    {
    return (status == STATUS_CONNECTING
        || status == STATUS_CONNECTED);
    }

    protected String getStatusMsg(int index)
    {
    StringBuffer sb = new StringBuffer();
    sb.append(STATUS_MSGS[index]);
    if (index == STATUS_CONNECTED) {
      if (getLocalPort() == 0) {
        sb.append(" (firewalled)");
      }
      sb.append(" [");
      sb.append(searchCount);
      sb.append("]");
    }

    return sb.toString();
    }

    public IChannel create(String name)
    {
    Channel c = new Channel(this, name, "", 0);
    channels.put(name, c);
    return c;
    }

    public boolean equals(Object obj)
    {
    if (obj instanceof Server) {
      Server s = (Server)obj;
      return (getHost().equalsIgnoreCase(s.getHost())
          && getPort() == s.getPort());
    }
 
    return false;
    }

    public Channel getChannel(String name)
    {
    Channel c = (Channel)channels.get(name);
    if (c == null) {
      c = new Channel(this, name, "", 0);
      channels.put(name, c);
    }
    return c;
    }

    public IChannel[] getChannels()
    {
    Object[] values = channels.values().toArray();
    IChannel[] array = new IChannel[values.length];
    System.arraycopy(values, 0, array, 0, array.length);
    return array;
    }

    public int getFileCount()
    {
    return fileCount;
    }

    public int getFileSize()
    {
    return fileSize;
    }

    public String getEmail()
    {
    return (email != null) ? email : prefs.getEmail();
    }

    public void setEmail(String newValue)
    {
    if (newValue != null) {
      try {
        StringValidator.EMAIL.validate(newValue);
      }
      catch (IllegalArgumentException e) {
        return;
      }
    }
   
    email = newValue;
    }

    public String getHost()
    {
    return remoteHost;
    }

    public void setHost(String newValue)
    {
    remoteHost = newValue;
    }

    /**
     * Napigator sends an ip which is sometimes more reliable than
     * the hostname.
     */
    public void setIP(String newValue)
    {
    remoteIP = newValue;
    }

    public String getIP()
    {
    //return remoteIP != null ? remoteIP : socket.getInetAddress().toString();
    return remoteIP;
    }

    public long getLastLogin()
    {
    return lastLogin;
    }

    /**
     * Returns the associated listener for incoming requests. Needed
     * for reverse downloads.
     */
    public NapListener getListener()
    {
    return listener;
    }

    public void setListener(NapListener newValue)
    {
    listener = newValue;
    }

    /**
     * Returns port of listener or 0 if there is no listener running, which
     * means XNap is behind a firewall.
     */
    public int getLocalPort() {
        return listener != null ? listener.getPort() : 0;
    }

    public String getName()
    {
    String network = getNetwork();
    if (network.length() > 0) {
      return network;
    }
    else {
      return getHost();
    }
    }

    public String getNetwork() {
    return network;
    }

    public void setNetwork(String newValue)
    {
    network = newValue;
    }

    public String getPassword()
    {
    return (password != null) ? password : prefs.getPassword();
    }

    public void setPassword(String newValue)
    {
    if (newValue != null) {
      try {
        StringValidator.REGULAR_STRING.validate(newValue);
      }
      catch (IllegalArgumentException e) {
        return;
      }
    }

    password = newValue;
    }

    public int getPort()
    {
    return remotePort;
    }

    public void setPort(int newValue)
    {
    remotePort = newValue;
    }

    public String getRedirectedHost()
    {
    return redirectedHost;
    }

    public int getRedirectedPort()
    {
    return redirectedPort;
    }


  //     public SendQueue getSendQueue()
  //     {
  //   return sendQueue;
  //     }

    /**
     * Returns the index range of shared files.
     */
    public Range getShared()
    {
    return (Range)shared.clone();
    }

    public void setShared(Range newValue)
    {
    shared = (Range)newValue.clone();
    }

    public boolean isTemporary()
    {
    return temporay;
    }

    public boolean isRedirector()
    {
    return redirector;
    }

    public void setTemporary(boolean newValue)
    {
    temporay = newValue;
    }

    public User getUser(String nick)
    {
    User u = (User)users.get(nick);
    if (u == null) {
      u = new User(nick, this);
      users.put(nick, u);
    }
    return u;
    }

    public IUser getUser()
    {
    return getUser(getUsername());
    }

    public int getUserCount()
    {
    return userCount;
    }

    public String getUsername()
    {
    return (username != null) ? username : prefs.getUsername();
    }

    public void setUsername(String newValue)
    {
    if (newValue != null) {
      try {
        StringValidator.REGULAR_STRING.validate(newValue);
      }
      catch (IllegalArgumentException e) {
        return;
      }
    }

    username = newValue;
    }

    public ServerVersion getVersion()
    {
    return version;
    }

    public void setVersion(String newValue)
    {
    version = new ServerVersion(newValue);
    }

    public void setRedirectedHost(String redirectedHost)
    {
    this.redirectedHost = redirectedHost;
    }

    public void setRedirectedPort(int redirectedPort)
    {
    this.redirectedPort = redirectedPort;
    }

    public void setRedirector(boolean newValue)
    {
    this.redirector = newValue;
    }



    /**
     * Logs into server.
     */
    public void login(boolean newUser)
    {

    if (!canStart()) {
      return;
    }

    lastLogin = System.currentTimeMillis();
    setStatus(STATUS_CONNECTING);
 
    this.newUser = newUser;

    // start main loop to listen for msgs
    runner = new Thread(this, "OpenNapServer " + getHost());
    runner.start();
    }

    /**
     * Connects to a redirector server and reads the host information.
     *
     * @return true, if successful; false, if failed
     */
    public boolean fetchHost(String host, int port) throws IOException
    {
    Socket socket = null;
    InputStream in = null;
    try {
      socket = new Socket(host, port);
      in = new BufferedInputStream(socket.getInputStream());

      byte[] b = new byte[1024];
      int c = in.read(b, 0, 1024);
      if (c > 0) {
        // chop the \n
        String response = new String(b, 0, c - 1);
        StringTokenizer t = new StringTokenizer(response, ":");
        if (t.countTokens() == 2) {
          try {
            setRedirectedHost(t.nextToken());
            setRedirectedPort
              (Integer.parseInt(t.nextToken()));
            return true;
          }
          catch (NumberFormatException e) {
          }

        }
      }
    }
    finally {
      try {
        if (in != null) {
          in.close();
        }
        if (socket != null) {
          socket.close();
        }
      }
      catch (IOException e) {
      }
    }

    return false;
    }


    public void logout()
    {
    die(STATUS_NOT_CONNECTED);
    }

    public void messageReceived(String channelName, String nick, String message)
    {
    Channel c = (Channel)channels.get(channelName);
    if (c != null) {
      c.messageReceived(getUser(nick), message);
    }
    else {
      StringBuffer sb = new StringBuffer();
      sb.append(getHost());
      sb.append(" (");
      sb.append(channelName);
      sb.append(") : ");
      sb.append(message);
      ChatManager.getInstance().globalMessageReceived(sb.toString());
    }
    }

    public synchronized void addBrowse(Browse b) throws IOException
    {
    if (!isConnected()) {
      throw new IOException("server disconnected");
    }

    browseQueue.add(b);
    allowBrowse();
    }

    public synchronized void addSearch(Search s) throws IOException
    {
    if (!isConnected()) {
      throw new IOException("server disconnected");
    }

    int i;
    if (currentSearch != null && currentSearch.equals(s)) {
      for (Iterator it = currentSearch.getResults().iterator();
         it.hasNext();) {
        s.add((SearchResult)it.next());
      }

      currentSearch.addPeer(s);
    }
    else if ((i = searchQueue.indexOf(s)) != -1) {
      ((Search)searchQueue.get(i)).addPeer(s);
    }
    else if (!useSearchCache(s)) {
      searchQueue.add(s, s.getPriority());
      allowSearch();
    }
    }

    /**
     * Sleeps until ready to send.
     */
    public void waitUntilReadyToSend()
    {
    long tickLeft
      = tickLength - (System.currentTimeMillis() - writeTickStart);
    if (tickLeft <= 0) {
      writeTickStart = System.currentTimeMillis();
      writeTickPacketCount = 0;
    }
    else if (writeTickPacketCount >= maxPacketsPerTick) {
      //logger.debug("flood protection: stalling for "
      //              + tickLeft + " ms");
      try {
        Thread.currentThread().sleep(tickLeft);
      }
      catch (InterruptedException e) {
      }
    }
    }
   
    public synchronized void removeBrowse(Browse b)
    {
    browseQueue.remove(b);
    }

    /**
     * Is only called when search didn't take place or was aborted. That's
     * why the cache entry is removed too.
     */
    public synchronized void removeSearch(Search s)
    {
    searchQueue.remove(s);
    }

    public void send(ClientMessage msg) throws IOException
    {
        sendPacket(new Packet(msg.getType(), msg.getData(version)));
    }

    public void updateChannels() throws IOException
    {
    MessageHandler.send(this, new ListChannelsMessage());
    }

    private ServerMessage getNextMessage()
    {
    Packet p = null;
    while (!die) {
      try {
        p = recvPacket();
        return MessageFactory.create(this, p.id, p.data);
      }
      catch (InterruptedIOException e) {
      }
      catch (IOException e) {
        logger.error(getHost() + ":" + getPort()
               + " getNextMessage: " + e.getMessage());
        logger.debug(getHost() + ":" + getPort()
               + " getNextMessage ", e);
        if (getStatus() == STATUS_CONNECTING) {
          die(STATUS_LOGIN_FAILED, lastError);
        }
        else {
          die(STATUS_FAILED, lastError);
        }
      }
      catch (InvalidMessageException e) {
        logger.error(getHost() + ":" + getPort()
               + " getNextMessage: " + p, e);
      }
    }

    return null;
    }

    private byte[] read(int length) throws IOException
    {
    byte[] textBuf = new byte[length];
 
    int read = 0;
    while (read < length) {
      try {
        int c = in.read(textBuf, read, length - read);
        if (c == -1) {
          throw new IOException("Connection closed");
        }
        read += c;
      }
      catch (InterruptedIOException e) {
        if (die) {
          throw e;
        }
      }
    }

    return textBuf;
    }

    private Packet recvPacket() throws IOException
    {
    String content = "";

    byte[] header = read(4);

    // byte types are signed...
    int lo = 0xFF & (int)header[0];
    int hi = 0xFF & (int)header[1];
    int length = 0xFFFF & (hi << 8 | lo);

    lo = 0xFF & (int)header[2];
    hi = 0xFF & (int)header[3];
    int id = 0xFFFF & (hi << 8 | lo);
 
    if (length > 0) {
      content = new String(read(length));
    }

    logger.debug("< " + getHost() + ":" + getPort() + " " +
           MessageFactory.getMessageName(id) + "(" +id + ") " + content);

    return new Packet(id, content);
    }

    private void sendPacket(Packet p) throws IOException
    {

    logger.debug("> " + getHost() + ":" + getPort() + " " +
           MessageStrings.getMessageName(p.id) + "(" + p.id + ") "
           + p.data);

    //    logger.debug("> " + getHost() + ":" + getPort() + " (" + p.id + ") "
    //           + p.data);

        try {
      int dataLength = p.data.getBytes().length;
            byte[] data = new byte[2 + 2 + dataLength];

            int type = (short)p.id;
            int len = (short)dataLength;

            data[0] = (byte)len;
            data[1] = (byte)(len >> 8);
            data[2] = (byte)type;
            data[3] = (byte)(type >> 8);

            System.arraycopy(p.data.getBytes(), 0,
               data, 4, dataLength);

      // maybe we should do some synchronization here
      // we don't want to have multiple threads write half packets
            out.write(data);
            out.flush();

      // flood protection
      writeTickPacketCount++;
        }
    catch (NullPointerException e) {
      logger.debug(getHost() + ":" + getPort() + " sendPacket " + p, e);
      if (getStatus() == STATUS_CONNECTING) {
        die(STATUS_LOGIN_FAILED, e.getMessage());
      }
      else {
        die(STATUS_FAILED, e.getMessage());
      }
      throw(new IOException("Internal error"));
    }
    catch (IOException e) {
      logger.debug(getHost() + ":" + getPort() + " sendPacket " + p, e);
      if (getStatus() == STATUS_CONNECTING) {
        die(STATUS_LOGIN_FAILED, e.getMessage());
      }
      else {
        die(STATUS_FAILED, e.getMessage());
      }
      throw(e);
        }
    }


    /**
     * Opens the socket to the server and connects the streams.
     * If host1 != null, it is tried first.
     *
     * @param host1 the ip address of the server or null if unknown
     * @param host2 the hostname of the server
     * @param port the port of the server
     */
    private void connect(String host1, String host2, int port)
    throws IOException
    {
    socket = null;
    if (host1 != null) {
      try {
        socket = new Socket(host1, port);
      }
      catch (IOException e) {
        setIP(null);
      }
    }
 
    if (socket == null) {
      for (int i = 0; i < MAX_RETRY_ON_CONNECTION_REFUSED
           && socket == null; i++) {

        try {
          socket = new Socket(host2, port);
        }
        catch (ConnectException e) {
          if (i == MAX_RETRY_ON_CONNECTION_REFUSED - 1) {
            throw e;
          }
          try {
            Thread.sleep(10);
          }
          catch (InterruptedException e2) {
          }
        }
      }
    }

    socket.setSoTimeout(SOCKET_TIMEOUT);

    in = new BufferedInputStream(socket.getInputStream());
    out = socket.getOutputStream();
 

    setStatus(STATUS_CONNECTING, XNap.tr("logging in") + "...");
    //  server.setStateDescription(XNap.tr("logging in") + "...");
 
    try {
      if (newUser) {
        send(new NickCheckMessage(getUsername()));
      }
      else {
        //    login(false);
        MessageHandler.login(this, false);
      }
    }
    catch (IOException e) {
      die(STATUS_LOGIN_FAILED, XNap.tr("login failed"));
    }
    }


    /**
     * Waits for msgs from napster server and passes them on to the
     * individual MsgQueues.
     */
    public void run()
    {
    Thread.currentThread().setPriority(Thread.MIN_PRIORITY);


    die = false;
    currentBrowse = null;
    currentSearch = null;
    searchCount = 0;
    lastError = null;

    searchCache.clear();
    users.clear();

    try {
      if (isRedirector()) {
        if (fetchHost(getHost(), getPort())) {
          connect(null, getRedirectedHost(),
              getRedirectedPort());
        }
        else {
          die(STATUS_FAILED, "invalid response");
        }
      }
      else {
        connect(remoteIP, getHost(), getPort());
      }
    }
    catch (ConnectException e) {
      // this is connection refused, try again later
      //        die(STATUS_FAILED, MessageFormat.format
      //      (XNap.tr("failed: {0}"),
      //       new Object[] { e.getLocalizedMessage() }));
      die(STATUS_FAILED, XNap.tr("connection refused"));
    }
    catch (UnknownHostException e) {
      die(STATUS_ERROR, XNap.tr("unknown host"));
    }
    catch (IOException e) {
      // not route to host or something, probably unrecoverable
      die(STATUS_ERROR, XNap.tr("error: {0}", e.getLocalizedMessage()));
    }
 
    while (!die) {
      ServerMessage msg = getNextMessage();

      if (die) {
        break;
      }

      if (msg instanceof NickNotRegisteredMessage) {
        if (getStatus() == STATUS_CONNECTING) {
          try {
            MessageHandler.login(this, true);
          }
          catch (IOException e) {
            setStatus(STATUS_LOGIN_FAILED, e.getMessage());
          }
        }
      }
      else if (msg instanceof NickAlreadyRegisteredMessage) {
        die(STATUS_LOGIN_FAILED, Plugin.tr("nick already registered"));
      }
      else if (msg instanceof InvalidNickMessage) {
        die(STATUS_LOGIN_FAILED, Plugin.tr("invalid nick"));
      }
      else if (msg instanceof LoginAckMessage) {
        if (getStatus() == STATUS_CONNECTING) {
          //sendQueue.clear();
          setStatus(STATUS_CONNECTED);
        }
      }
      else if (msg instanceof LoginErrorMessage) {
        die(STATUS_LOGIN_FAILED, ((LoginErrorMessage)msg).message);
      }
      else if (msg instanceof BrowseResponseMessage) {
        if (currentBrowse != null) {
          currentBrowse.add((BrowseResponseMessage)msg);
        }
      }
      else if (msg instanceof EndBrowseMessage) {
        if (currentBrowse != null) {
          currentBrowse.finished();
          currentBrowse = null;
          updateStatus();
        }
      }
      else if (msg instanceof SearchResponseMessage) {
        if (currentSearch != null) {
          currentSearch.add((SearchResponseMessage)msg);
        }
      }
      else if (msg instanceof EndSearchMessage) {
        if (currentSearch != null) {
          synchronized (this) {
            currentSearch.finished();
     
            // create cache entry if auto download search
            if (currentSearch.getPriority()
              == ISearch.PRIORITY_BACKGROUND) {
              searchCache.put(currentSearch.getRequest(),
                      currentSearch.getResults());
            }

            currentSearch = null;
          }
          updateStatus();
        }
      }
      else if (msg instanceof ServerStatsMessage) {
        ServerStatsMessage ssm = (ServerStatsMessage)msg;
        userCount = ssm.userCount;
        fileCount = ssm.fileCount;
        fileSize = ssm.fileSize;
        fireStatusChange(status, STATUS_NEW_STATS);
      }
      else if (msg instanceof ErrorMessage) {
        lastError = ((ErrorMessage)msg).message;
       
        if (lastError.startsWith("You have been killed by server")
          || lastError.startsWith("You were killed by server"))
          {
            setStatus(STATUS_ERROR, lastError);
          }
      }
     
      MessageHandler.handle(msg);
     
      allowSearch();
      allowBrowse();
    }
 
    try {
      if (in != null)
        in.close();
      if (out != null)
        out.close();
      if (socket != null)
        socket.close();
    }
    catch (IOException e) {
    }

    synchronized (this) {
      if (currentBrowse != null) {
        currentBrowse.failed(Plugin.tr("Server disconnected"));
      }
      for (Iterator i = browseQueue.iterator(); i.hasNext();) {
        ((Browse)i.next()).failed(Plugin.tr("Server disconnected"));
      }
      browseQueue.clear();
    }

    synchronized (this) {
      if (currentSearch != null) {
        currentSearch.failed(Plugin.tr("Server disconnected"));
      }
      Object[] searches = searchQueue.toArray();
      for (int i = 0; i < searches.length; i++) {
        ((Search)searches[i]).failed(Plugin.tr("Server disconnected"));
      }
      searchQueue.clear();
    }

    // close all open chat channels
    for (Iterator i = channels.values().iterator(); i.hasNext();) {
      ((IChannel)i.next()).close();
    }


    logger.debug(toString() + " has died");
    died();
    }

    private void updateStatus()
    {
    if (status == STATUS_CONNECTED) {
      StringBuffer sb = new StringBuffer(getStatusMsg(status));

      if (currentSearch != null) {
        sb.append(", searching");
      }
      if (searchQueue.size() > 0) {
        sb.append(", ");
        sb.append(searchQueue.size());
        sb.append(" searches pending");
      }
      if (currentBrowse != null) {
        sb.append(", browsing");
      }

      setStatus(status, sb.toString());
    }
    }
 
    public String toString()
    {
    StringBuffer sb = new StringBuffer();
    sb.append(getHost());
    sb.append(":");
    sb.append(getPort());
    String network = getNetwork();
    if (network != null && !network.equals("")) {
      sb.append(" (");
      sb.append(network);
      sb.append(")");
    }
    return sb.toString();
    }

    private synchronized void allowBrowse()
    {
    if (currentBrowse != null || browseQueue.size() == 0) {
      return;
    }

    currentBrowse = (Browse)browseQueue.removeFirst();
    currentBrowse.start();

    updateStatus();
    }

    private synchronized void allowSearch()
    {
    if (currentSearch != null || searchQueue.size() == 0) {
      return;
    }

    Search s = (Search)searchQueue.peek();

    if (useSearchCache(s)) {
      searchQueue.pop();
      return;
    }

    searchQueue.pop();
    currentSearch = s;

    lastSearch = System.currentTimeMillis();
    searchCount++;
    currentSearch.start();

    updateStatus();
    }

    private synchronized boolean useSearchCache(Search s)
    {
    if (s.getPriority() < ISearch.PRIORITY_USER) {
      searchCache.purge();
      LinkedList results = searchCache.get(s.getRequest());
      if (results != null) {
        // cache hit
        logger.debug("nap server: reuse of searchresults");
        for (Iterator i = results.iterator(); i.hasNext();) {
          SearchResult sr = (SearchResult)i.next();
          s.add(sr);
        }
        s.close();
        return true;
      }
    }

    return false;
    }

}
TOP

Related Classes of xnap.plugin.nap.net.Server

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.