src/org/sonews/daemon/NNTPConnection.java
changeset 76 b5690fc25af6
parent 48 b78e77619152
child 101 d54786065fa3
     1.1 --- a/src/org/sonews/daemon/NNTPConnection.java	Sun Sep 11 15:05:04 2011 +0200
     1.2 +++ b/src/org/sonews/daemon/NNTPConnection.java	Fri Oct 14 00:45:06 2011 +0200
     1.3 @@ -15,7 +15,6 @@
     1.4   *   You should have received a copy of the GNU General Public License
     1.5   *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
     1.6   */
     1.7 -
     1.8  package org.sonews.daemon;
     1.9  
    1.10  import java.io.IOException;
    1.11 @@ -30,6 +29,7 @@
    1.12  import java.util.Arrays;
    1.13  import java.util.Timer;
    1.14  import java.util.TimerTask;
    1.15 +import java.util.logging.Level;
    1.16  import org.sonews.daemon.command.Command;
    1.17  import org.sonews.storage.Article;
    1.18  import org.sonews.storage.Group;
    1.19 @@ -43,8 +43,7 @@
    1.20   * @author Christian Lins
    1.21   * @since sonews/0.5.0
    1.22   */
    1.23 -public final class NNTPConnection
    1.24 -{
    1.25 +public final class NNTPConnection {
    1.26  
    1.27  	public static final String NEWLINE = "\r\n";    // RFC defines this as newline
    1.28  	public static final String MESSAGE_ID_PATTERN = "<[^>]+>";
    1.29 @@ -62,8 +61,7 @@
    1.30  	private SelectionKey writeSelKey = null;
    1.31  
    1.32  	public NNTPConnection(final SocketChannel channel)
    1.33 -		throws IOException
    1.34 -	{
    1.35 +			throws IOException {
    1.36  		if (channel == null) {
    1.37  			throw new IllegalArgumentException("channel is null");
    1.38  		}
    1.39 @@ -77,8 +75,7 @@
    1.40  	 * safe and returns true of the read lock was successfully set. If the lock
    1.41  	 * is still hold by another Thread the method returns false.
    1.42  	 */
    1.43 -	boolean tryReadLock()
    1.44 -	{
    1.45 +	boolean tryReadLock() {
    1.46  		// As synchronizing simple types may cause deadlocks,
    1.47  		// we use a gate object.
    1.48  		synchronized (readLockGate) {
    1.49 @@ -96,8 +93,7 @@
    1.50  	 * @throws IllegalMonitorStateException if a Thread not holding the lock
    1.51  	 * tries to release it.
    1.52  	 */
    1.53 -	void unlockReadLock()
    1.54 -	{
    1.55 +	void unlockReadLock() {
    1.56  		synchronized (readLockGate) {
    1.57  			if (readLock == Thread.currentThread().hashCode()) {
    1.58  				readLock = 0;
    1.59 @@ -110,8 +106,7 @@
    1.60  	/**
    1.61  	 * @return Current input buffer of this NNTPConnection instance.
    1.62  	 */
    1.63 -	public ByteBuffer getInputBuffer()
    1.64 -	{
    1.65 +	public ByteBuffer getInputBuffer() {
    1.66  		return this.lineBuffers.getInputBuffer();
    1.67  	}
    1.68  
    1.69 @@ -119,34 +114,29 @@
    1.70  	 * @return Output buffer of this NNTPConnection which has at least one byte
    1.71  	 * free storage.
    1.72  	 */
    1.73 -	public ByteBuffer getOutputBuffer()
    1.74 -	{
    1.75 +	public ByteBuffer getOutputBuffer() {
    1.76  		return this.lineBuffers.getOutputBuffer();
    1.77  	}
    1.78  
    1.79  	/**
    1.80  	 * @return ChannelLineBuffers instance associated with this NNTPConnection.
    1.81  	 */
    1.82 -	public ChannelLineBuffers getBuffers()
    1.83 -	{
    1.84 +	public ChannelLineBuffers getBuffers() {
    1.85  		return this.lineBuffers;
    1.86  	}
    1.87  
    1.88  	/**
    1.89  	 * @return true if this connection comes from a local remote address.
    1.90  	 */
    1.91 -	public boolean isLocalConnection()
    1.92 -	{
    1.93 +	public boolean isLocalConnection() {
    1.94  		return ((InetSocketAddress) this.channel.socket().getRemoteSocketAddress()).getHostName().equalsIgnoreCase("localhost");
    1.95  	}
    1.96  
    1.97 -	void setWriteSelectionKey(SelectionKey selKey)
    1.98 -	{
    1.99 +	void setWriteSelectionKey(SelectionKey selKey) {
   1.100  		this.writeSelKey = selKey;
   1.101  	}
   1.102  
   1.103 -	public void shutdownInput()
   1.104 -	{
   1.105 +	public void shutdownInput() {
   1.106  		try {
   1.107  			// Closes the input line of the channel's socket, so no new data
   1.108  			// will be received and a timeout can be triggered.
   1.109 @@ -156,14 +146,10 @@
   1.110  		}
   1.111  	}
   1.112  
   1.113 -	public void shutdownOutput()
   1.114 -	{
   1.115 -		cancelTimer.schedule(new TimerTask()
   1.116 -		{
   1.117 -
   1.118 +	public void shutdownOutput() {
   1.119 +		cancelTimer.schedule(new TimerTask() {
   1.120  			@Override
   1.121 -			public void run()
   1.122 -			{
   1.123 +			public void run() {
   1.124  				try {
   1.125  					// Closes the output line of the channel's socket.
   1.126  					channel.socket().shutdownOutput();
   1.127 @@ -178,41 +164,34 @@
   1.128  		}, 3000);
   1.129  	}
   1.130  
   1.131 -	public SocketChannel getSocketChannel()
   1.132 -	{
   1.133 +	public SocketChannel getSocketChannel() {
   1.134  		return this.channel;
   1.135  	}
   1.136  
   1.137 -	public Article getCurrentArticle()
   1.138 -	{
   1.139 +	public Article getCurrentArticle() {
   1.140  		return this.currentArticle;
   1.141  	}
   1.142  
   1.143 -	public Charset getCurrentCharset()
   1.144 -	{
   1.145 +	public Charset getCurrentCharset() {
   1.146  		return this.charset;
   1.147  	}
   1.148  
   1.149  	/**
   1.150  	 * @return The currently selected communication channel (not SocketChannel)
   1.151  	 */
   1.152 -	public Group getCurrentChannel()
   1.153 -	{
   1.154 +	public Group getCurrentChannel() {
   1.155  		return this.currentGroup;
   1.156  	}
   1.157  
   1.158 -	public void setCurrentArticle(final Article article)
   1.159 -	{
   1.160 +	public void setCurrentArticle(final Article article) {
   1.161  		this.currentArticle = article;
   1.162  	}
   1.163  
   1.164 -	public void setCurrentGroup(final Group group)
   1.165 -	{
   1.166 +	public void setCurrentGroup(final Group group) {
   1.167  		this.currentGroup = group;
   1.168  	}
   1.169  
   1.170 -	public long getLastActivity()
   1.171 -	{
   1.172 +	public long getLastActivity() {
   1.173  		return this.lastActivity;
   1.174  	}
   1.175  
   1.176 @@ -222,8 +201,7 @@
   1.177  	 * @throws IllegalArgumentException if raw is null.
   1.178  	 * @throws IllegalStateException if calling thread does not own the readLock.
   1.179  	 */
   1.180 -	void lineReceived(byte[] raw)
   1.181 -	{
   1.182 +	void lineReceived(byte[] raw) {
   1.183  		if (raw == null) {
   1.184  			throw new IllegalArgumentException("raw is null");
   1.185  		}
   1.186 @@ -262,17 +240,25 @@
   1.187  			}
   1.188  		} catch (ClosedChannelException ex0) {
   1.189  			try {
   1.190 -				Log.get().info("Connection to " + channel.socket().getRemoteSocketAddress()
   1.191 -					+ " closed: " + ex0);
   1.192 +				StringBuilder strBuf = new StringBuilder();
   1.193 +				strBuf.append("Connection to ");
   1.194 +				strBuf.append(channel.socket().getRemoteSocketAddress());
   1.195 +				strBuf.append(" closed: ");
   1.196 +				strBuf.append(ex0);
   1.197 +				Log.get().info(strBuf.toString());
   1.198  			} catch (Exception ex0a) {
   1.199  				ex0a.printStackTrace();
   1.200  			}
   1.201 -		} catch (Exception ex1) // This will catch a second StorageBackendException
   1.202 -		{
   1.203 +		} catch (Exception ex1) { // This will catch a second StorageBackendException
   1.204  			try {
   1.205  				command = null;
   1.206 -				ex1.printStackTrace();
   1.207 -				println("500 Internal server error");
   1.208 +				Log.get().log(Level.WARNING, ex1.getLocalizedMessage(), ex1);
   1.209 +				println("403 Internal server error");
   1.210 +
   1.211 +				// Should we end the connection here?
   1.212 +				// RFC says we MUST return 400 before closing the connection
   1.213 +				shutdownInput();
   1.214 +				shutdownOutput();
   1.215  			} catch (Exception ex2) {
   1.216  				ex2.printStackTrace();
   1.217  			}
   1.218 @@ -289,8 +275,7 @@
   1.219  	 * @param line
   1.220  	 * @return
   1.221  	 */
   1.222 -	private Command parseCommandLine(String line)
   1.223 -	{
   1.224 +	private Command parseCommandLine(String line) {
   1.225  		String cmdStr = line.split(" ")[0];
   1.226  		return CommandSelector.getInstance().get(cmdStr);
   1.227  	}
   1.228 @@ -303,8 +288,7 @@
   1.229  	 * @param line
   1.230  	 */
   1.231  	public void println(final CharSequence line, final Charset charset)
   1.232 -		throws IOException
   1.233 -	{
   1.234 +			throws IOException {
   1.235  		writeToChannel(CharBuffer.wrap(line), charset, line);
   1.236  		writeToChannel(CharBuffer.wrap(NEWLINE), charset, null);
   1.237  	}
   1.238 @@ -315,8 +299,7 @@
   1.239  	 * @param rawLines
   1.240  	 */
   1.241  	public void println(final byte[] rawLines)
   1.242 -		throws IOException
   1.243 -	{
   1.244 +			throws IOException {
   1.245  		this.lineBuffers.addOutputBuffer(ByteBuffer.wrap(rawLines));
   1.246  		writeToChannel(CharBuffer.wrap(NEWLINE), charset, null);
   1.247  	}
   1.248 @@ -328,9 +311,8 @@
   1.249  	 * @throws java.io.IOException
   1.250  	 */
   1.251  	private void writeToChannel(CharBuffer characters, final Charset charset,
   1.252 -		CharSequence debugLine)
   1.253 -		throws IOException
   1.254 -	{
   1.255 +			CharSequence debugLine)
   1.256 +			throws IOException {
   1.257  		if (!charset.canEncode()) {
   1.258  			Log.get().severe("FATAL: Charset " + charset + " cannot encode!");
   1.259  			return;
   1.260 @@ -343,8 +325,7 @@
   1.261  		enableWriteEvents(debugLine);
   1.262  	}
   1.263  
   1.264 -	private void enableWriteEvents(CharSequence debugLine)
   1.265 -	{
   1.266 +	private void enableWriteEvents(CharSequence debugLine) {
   1.267  		// Enable OP_WRITE events so that the buffers are processed
   1.268  		try {
   1.269  			this.writeSelKey.interestOps(SelectionKey.OP_WRITE);
   1.270 @@ -363,24 +344,20 @@
   1.271  	}
   1.272  
   1.273  	public void println(final CharSequence line)
   1.274 -		throws IOException
   1.275 -	{
   1.276 +			throws IOException {
   1.277  		println(line, charset);
   1.278  	}
   1.279  
   1.280  	public void print(final String line)
   1.281 -		throws IOException
   1.282 -	{
   1.283 +			throws IOException {
   1.284  		writeToChannel(CharBuffer.wrap(line), charset, line);
   1.285  	}
   1.286  
   1.287 -	public void setCurrentCharset(final Charset charset)
   1.288 -	{
   1.289 +	public void setCurrentCharset(final Charset charset) {
   1.290  		this.charset = charset;
   1.291  	}
   1.292  
   1.293 -	void setLastActivity(long timestamp)
   1.294 -	{
   1.295 +	void setLastActivity(long timestamp) {
   1.296  		this.lastActivity = timestamp;
   1.297  	}
   1.298  }