org/sonews/daemon/NNTPConnection.java
changeset 3 2fdc9cc89502
parent 1 6fceb66e1ad7
child 15 f2293e8566f5
     1.1 --- a/org/sonews/daemon/NNTPConnection.java	Wed Jul 01 10:48:22 2009 +0200
     1.2 +++ b/org/sonews/daemon/NNTPConnection.java	Wed Jul 22 14:04:05 2009 +0200
     1.3 @@ -21,33 +21,19 @@
     1.4  import org.sonews.util.Log;
     1.5  import java.io.IOException;
     1.6  import java.net.InetSocketAddress;
     1.7 +import java.net.SocketException;
     1.8  import java.nio.ByteBuffer;
     1.9  import java.nio.CharBuffer;
    1.10  import java.nio.channels.ClosedChannelException;
    1.11  import java.nio.channels.SelectionKey;
    1.12  import java.nio.channels.SocketChannel;
    1.13  import java.nio.charset.Charset;
    1.14 +import java.util.Arrays;
    1.15  import java.util.Timer;
    1.16  import java.util.TimerTask;
    1.17 -import org.sonews.daemon.command.ArticleCommand;
    1.18 -import org.sonews.daemon.command.CapabilitiesCommand;
    1.19 -import org.sonews.daemon.command.AbstractCommand;
    1.20 -import org.sonews.daemon.command.GroupCommand;
    1.21 -import org.sonews.daemon.command.HelpCommand;
    1.22 -import org.sonews.daemon.command.ListCommand;
    1.23 -import org.sonews.daemon.command.ListGroupCommand;
    1.24 -import org.sonews.daemon.command.ModeReaderCommand;
    1.25 -import org.sonews.daemon.command.NewGroupsCommand;
    1.26 -import org.sonews.daemon.command.NextPrevCommand;
    1.27 -import org.sonews.daemon.command.OverCommand;
    1.28 -import org.sonews.daemon.command.PostCommand;
    1.29 -import org.sonews.daemon.command.QuitCommand;
    1.30 -import org.sonews.daemon.command.StatCommand;
    1.31 -import org.sonews.daemon.command.UnsupportedCommand;
    1.32 -import org.sonews.daemon.command.XDaemonCommand;
    1.33 -import org.sonews.daemon.command.XPatCommand;
    1.34 -import org.sonews.daemon.storage.Article;
    1.35 -import org.sonews.daemon.storage.Group;
    1.36 +import org.sonews.daemon.command.Command;
    1.37 +import org.sonews.storage.Article;
    1.38 +import org.sonews.storage.Channel;
    1.39  import org.sonews.util.Stats;
    1.40  
    1.41  /**
    1.42 @@ -67,9 +53,9 @@
    1.43    /** SocketChannel is generally thread-safe */
    1.44    private SocketChannel   channel        = null;
    1.45    private Charset         charset        = Charset.forName("UTF-8");
    1.46 -  private AbstractCommand command        = null;
    1.47 +  private Command         command        = null;
    1.48    private Article         currentArticle = null;
    1.49 -  private Group           currentGroup   = null;
    1.50 +  private Channel         currentGroup   = null;
    1.51    private volatile long   lastActivity   = System.currentTimeMillis();
    1.52    private ChannelLineBuffers lineBuffers = new ChannelLineBuffers();
    1.53    private int             readLock       = 0;
    1.54 @@ -201,6 +187,11 @@
    1.55            channel.socket().shutdownOutput();
    1.56            channel.close();
    1.57          }
    1.58 +        catch(SocketException ex)
    1.59 +        {
    1.60 +          // Socket was already disconnected
    1.61 +          Log.msg("NNTPConnection.shutdownOutput(): " + ex, true);
    1.62 +        }
    1.63          catch(Exception ex)
    1.64          {
    1.65            Log.msg("NNTPConnection.shutdownOutput(): " + ex, false);
    1.66 @@ -213,7 +204,7 @@
    1.67      }, 3000);
    1.68    }
    1.69    
    1.70 -  public SocketChannel getChannel()
    1.71 +  public SocketChannel getSocketChannel()
    1.72    {
    1.73      return this.channel;
    1.74    }
    1.75 @@ -227,8 +218,11 @@
    1.76    {
    1.77      return this.charset;
    1.78    }
    1.79 -  
    1.80 -  public Group getCurrentGroup()
    1.81 +
    1.82 +  /**
    1.83 +   * @return The currently selected communication channel (not SocketChannel)
    1.84 +   */
    1.85 +  public Channel getCurrentChannel()
    1.86    {
    1.87      return this.currentGroup;
    1.88    }
    1.89 @@ -238,7 +232,7 @@
    1.90      this.currentArticle = article;
    1.91    }
    1.92    
    1.93 -  public void setCurrentGroup(final Group group)
    1.94 +  public void setCurrentGroup(final Channel group)
    1.95    {
    1.96      this.currentGroup = group;
    1.97    }
    1.98 @@ -275,6 +269,7 @@
    1.99      if(line.endsWith("\r"))
   1.100      {
   1.101        line = line.substring(0, line.length() - 1);
   1.102 +      raw  = Arrays.copyOf(raw, raw.length - 1);
   1.103      }
   1.104      
   1.105      Log.msg("<< " + line, true);
   1.106 @@ -288,7 +283,7 @@
   1.107      try
   1.108      {
   1.109        // The command object will process the line we just received
   1.110 -      command.processLine(line);
   1.111 +      command.processLine(this, line, raw);
   1.112      }
   1.113      catch(ClosedChannelException ex0)
   1.114      {
   1.115 @@ -324,86 +319,14 @@
   1.116    }
   1.117    
   1.118    /**
   1.119 -   * This method performes several if/elseif constructs to determine the
   1.120 -   * fitting command object. 
   1.121 -   * TODO: This string comparisons are probably slow!
   1.122 +   * This method determines the fitting command processing class.
   1.123     * @param line
   1.124     * @return
   1.125     */
   1.126 -  private AbstractCommand parseCommandLine(String line)
   1.127 +  private Command parseCommandLine(String line)
   1.128    {
   1.129 -    AbstractCommand  cmd    = new UnsupportedCommand(this);
   1.130 -    String   cmdStr = line.split(" ")[0];
   1.131 -    
   1.132 -    if(cmdStr.equalsIgnoreCase("ARTICLE") || 
   1.133 -      cmdStr.equalsIgnoreCase("BODY"))
   1.134 -    {
   1.135 -      cmd = new ArticleCommand(this);
   1.136 -    }
   1.137 -    else if(cmdStr.equalsIgnoreCase("CAPABILITIES"))
   1.138 -    {
   1.139 -      cmd = new CapabilitiesCommand(this);
   1.140 -    }
   1.141 -    else if(cmdStr.equalsIgnoreCase("GROUP"))
   1.142 -    {
   1.143 -      cmd = new GroupCommand(this);
   1.144 -    }
   1.145 -    else if(cmdStr.equalsIgnoreCase("HEAD"))
   1.146 -    {
   1.147 -      cmd = new ArticleCommand(this);
   1.148 -    }
   1.149 -    else if(cmdStr.equalsIgnoreCase("HELP"))
   1.150 -    {
   1.151 -      cmd = new HelpCommand(this);
   1.152 -    }
   1.153 -    else if(cmdStr.equalsIgnoreCase("LIST"))
   1.154 -    {
   1.155 -      cmd = new ListCommand(this);
   1.156 -    }
   1.157 -    else if(cmdStr.equalsIgnoreCase("LISTGROUP"))
   1.158 -    {
   1.159 -      cmd = new ListGroupCommand(this);
   1.160 -    }
   1.161 -    else if(cmdStr.equalsIgnoreCase("MODE"))
   1.162 -    {
   1.163 -      cmd = new ModeReaderCommand(this);
   1.164 -    }
   1.165 -    else if(cmdStr.equalsIgnoreCase("NEWGROUPS"))
   1.166 -    {
   1.167 -      cmd = new NewGroupsCommand(this);
   1.168 -    }
   1.169 -    else if(cmdStr.equalsIgnoreCase("NEXT") ||
   1.170 -      cmdStr.equalsIgnoreCase("PREV"))
   1.171 -    {
   1.172 -      cmd = new NextPrevCommand(this);
   1.173 -    }
   1.174 -    else if(cmdStr.equalsIgnoreCase("OVER") ||
   1.175 -      cmdStr.equalsIgnoreCase("XOVER")) // for compatibility with older RFCs
   1.176 -    {
   1.177 -      cmd = new OverCommand(this);
   1.178 -    }
   1.179 -    else if(cmdStr.equalsIgnoreCase("POST"))
   1.180 -    {
   1.181 -      cmd = new PostCommand(this);
   1.182 -    }
   1.183 -    else if(cmdStr.equalsIgnoreCase("QUIT"))
   1.184 -    {
   1.185 -      cmd = new QuitCommand(this);
   1.186 -    }
   1.187 -    else if(cmdStr.equalsIgnoreCase("STAT"))
   1.188 -    {
   1.189 -      cmd = new StatCommand(this);
   1.190 -    }
   1.191 -    else if(cmdStr.equalsIgnoreCase("XDAEMON"))
   1.192 -    {
   1.193 -      cmd = new XDaemonCommand(this);
   1.194 -    }
   1.195 -    else if(cmdStr.equalsIgnoreCase("XPAT"))
   1.196 -    {
   1.197 -      cmd = new XPatCommand(this);
   1.198 -    }
   1.199 -    
   1.200 -    return cmd;
   1.201 +    String cmdStr = line.split(" ")[0];
   1.202 +    return CommandSelector.getInstance().get(cmdStr);
   1.203    }
   1.204    
   1.205    /**
   1.206 @@ -419,6 +342,18 @@
   1.207      writeToChannel(CharBuffer.wrap(line), charset, line);
   1.208      writeToChannel(CharBuffer.wrap(NEWLINE), charset, null);
   1.209    }
   1.210 +
   1.211 +  /**
   1.212 +   * Writes the given raw lines to the output buffers and finishes with
   1.213 +   * a newline character (\r\n).
   1.214 +   * @param rawLines
   1.215 +   */
   1.216 +  public void println(final byte[] rawLines)
   1.217 +    throws IOException
   1.218 +  {
   1.219 +    this.lineBuffers.addOutputBuffer(ByteBuffer.wrap(rawLines));
   1.220 +    writeToChannel(CharBuffer.wrap(NEWLINE), charset, null);
   1.221 +  }
   1.222    
   1.223    /**
   1.224     * Encodes the given CharBuffer using the given Charset to a bunch of
   1.225 @@ -440,6 +375,11 @@
   1.226      LineEncoder lenc = new LineEncoder(characters, charset);
   1.227      lenc.encode(lineBuffers);
   1.228      
   1.229 +    enableWriteEvents(debugLine);
   1.230 +  }
   1.231 +
   1.232 +  private void enableWriteEvents(CharSequence debugLine)
   1.233 +  {
   1.234      // Enable OP_WRITE events so that the buffers are processed
   1.235      try
   1.236      {