# HG changeset patch # User cli # Date 1315753279 -7200 # Node ID 8df94bfd3e2f943cebeafe2224e88aced804fd99 # Parent b78e7761915246923ab36c027531325cc069d4a0 Fix for #14 diff -r b78e77619152 -r 8df94bfd3e2f src/org/sonews/Main.java --- a/src/org/sonews/Main.java Sun Sep 11 15:05:04 2011 +0200 +++ b/src/org/sonews/Main.java Sun Sep 11 17:01:19 2011 +0200 @@ -45,6 +45,8 @@ /** Version information of the sonews daemon */ public static final String VERSION = "sonews/1.1.0"; + + /** The server's startup date */ public static final Date STARTDATE = new Date(); /** @@ -81,13 +83,16 @@ mlgw = true; } else if (args[n].equals("-p")) { port = Integer.parseInt(args[++n]); - } else if (args[n].equals("-plugin")) { + } else if (args[n].equals("-plugin-storage")) { System.out.println("Warning: -plugin-storage is not implemented!"); } else if (args[n].equals("-plugin-command")) { try { CommandSelector.addCommandHandler(args[++n]); } catch (Exception ex) { - Log.get().warning("Could not load command plugin: " + args[n]); + StringBuilder strBuf = new StringBuilder(); + strBuf.append("Could not load command plugin: "); + strBuf.append(args[n]); + Log.get().warning(strBuf.toString()); Log.get().log(Level.INFO, "Main.java", ex); } } else if (args[n].equals("-plugin-storage")) { @@ -113,10 +118,10 @@ Log.get().info("Group 'control' created."); } } catch (StorageBackendException ex) { - ex.printStackTrace(); + Log.get().log(Level.SEVERE, ex.getLocalizedMessage(), ex); System.err.println("Database initialization failed with " + ex.toString()); System.err.println("Make sure you have specified the correct database" - + " settings in sonews.conf!"); + + " settings in sonews.conf!"); return; } diff -r b78e77619152 -r 8df94bfd3e2f src/org/sonews/ShutdownHook.java --- a/src/org/sonews/ShutdownHook.java Sun Sep 11 15:05:04 2011 +0200 +++ b/src/org/sonews/ShutdownHook.java Sun Sep 11 17:01:19 2011 +0200 @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package org.sonews; import java.sql.SQLException; @@ -27,15 +26,13 @@ * @author Christian Lins * @since sonews/0.5.0 */ -class ShutdownHook extends Thread -{ +class ShutdownHook extends Thread { /** * Called when the JVM exits. */ @Override - public void run() - { + public void run() { System.out.println("sonews: Trying to shutdown all threads..."); Map threadsMap = Thread.getAllStackTraces(); diff -r b78e77619152 -r 8df94bfd3e2f src/org/sonews/acl/AccessControl.java --- a/src/org/sonews/acl/AccessControl.java Sun Sep 11 15:05:04 2011 +0200 +++ b/src/org/sonews/acl/AccessControl.java Sun Sep 11 17:01:19 2011 +0200 @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package org.sonews.acl; /** @@ -23,8 +22,7 @@ * @author Christian Lins * @since sonews/1.1 */ -public interface AccessControl -{ +public interface AccessControl { boolean hasPermission(String user, char[] secret, String permission); } diff -r b78e77619152 -r 8df94bfd3e2f src/org/sonews/acl/AuthInfoCommand.java --- a/src/org/sonews/acl/AuthInfoCommand.java Sun Sep 11 15:05:04 2011 +0200 +++ b/src/org/sonews/acl/AuthInfoCommand.java Sun Sep 11 17:01:19 2011 +0200 @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package org.sonews.acl; import java.io.IOException; @@ -28,37 +27,31 @@ * @author Christian Lins * @since sonews/1.1 */ -public class AuthInfoCommand implements Command -{ +public class AuthInfoCommand implements Command { @Override - public String[] getSupportedCommandStrings() - { + public String[] getSupportedCommandStrings() { throw new UnsupportedOperationException("Not supported yet."); } @Override - public boolean hasFinished() - { + public boolean hasFinished() { throw new UnsupportedOperationException("Not supported yet."); } @Override - public String impliedCapability() - { + public String impliedCapability() { throw new UnsupportedOperationException("Not supported yet."); } @Override - public boolean isStateful() - { + public boolean isStateful() { throw new UnsupportedOperationException("Not supported yet."); } @Override public void processLine(NNTPConnection conn, String line, byte[] rawLine) - throws IOException, StorageBackendException - { + throws IOException, StorageBackendException { throw new UnsupportedOperationException("Not supported yet."); } } diff -r b78e77619152 -r 8df94bfd3e2f src/org/sonews/config/AbstractConfig.java --- a/src/org/sonews/config/AbstractConfig.java Sun Sep 11 15:05:04 2011 +0200 +++ b/src/org/sonews/config/AbstractConfig.java Sun Sep 11 17:01:19 2011 +0200 @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package org.sonews.config; /** @@ -23,19 +22,16 @@ * @author Christian Lins * @since sonews/0.5.0 */ -public abstract class AbstractConfig -{ +public abstract class AbstractConfig { public abstract String get(String key, String defVal); - public int get(final String key, final int defVal) - { + public int get(final String key, final int defVal) { return Integer.parseInt( - get(key, Integer.toString(defVal))); + get(key, Integer.toString(defVal))); } - public boolean get(String key, boolean defVal) - { + public boolean get(String key, boolean defVal) { String val = get(key, Boolean.toString(defVal)); return Boolean.parseBoolean(val); } @@ -46,8 +42,7 @@ * @param defVal * @return */ - public long get(String key, long defVal) - { + public long get(String key, long defVal) { String val = get(key, Long.toString(defVal)); return Long.parseLong(val); } diff -r b78e77619152 -r 8df94bfd3e2f src/org/sonews/config/BackendConfig.java --- a/src/org/sonews/config/BackendConfig.java Sun Sep 11 15:05:04 2011 +0200 +++ b/src/org/sonews/config/BackendConfig.java Sun Sep 11 17:01:19 2011 +0200 @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package org.sonews.config; import java.util.logging.Level; @@ -30,19 +29,16 @@ * @author Christian Lins * @since sonews/0.5.0 */ -class BackendConfig extends AbstractConfig -{ +class BackendConfig extends AbstractConfig { private static BackendConfig instance = new BackendConfig(); - public static BackendConfig getInstance() - { + public static BackendConfig getInstance() { return instance; } private final TimeoutMap values = new TimeoutMap(); - private BackendConfig() - { + private BackendConfig() { super(); } @@ -54,8 +50,7 @@ * @return */ @Override - public String get(String key, String defaultValue) - { + public String get(String key, String defaultValue) { try { String configValue = values.get(key); if (configValue == null) { @@ -85,8 +80,7 @@ * @param key * @param value */ - public void set(String key, String value) - { + public void set(String key, String value) { values.put(key, value); try { diff -r b78e77619152 -r 8df94bfd3e2f src/org/sonews/config/CommandLineConfig.java --- a/src/org/sonews/config/CommandLineConfig.java Sun Sep 11 15:05:04 2011 +0200 +++ b/src/org/sonews/config/CommandLineConfig.java Sun Sep 11 17:01:19 2011 +0200 @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package org.sonews.config; import java.util.Map; @@ -25,24 +24,20 @@ * * @author Christian Lins */ -class CommandLineConfig extends AbstractConfig -{ +class CommandLineConfig extends AbstractConfig { private static final CommandLineConfig instance = new CommandLineConfig(); - public static CommandLineConfig getInstance() - { + public static CommandLineConfig getInstance() { return instance; } private final Map values = new HashMap(); - private CommandLineConfig() - { + private CommandLineConfig() { } @Override - public String get(String key, String def) - { + public String get(String key, String def) { synchronized (this.values) { if (this.values.containsKey(key)) { def = this.values.get(key); @@ -52,8 +47,7 @@ } @Override - public void set(String key, String val) - { + public void set(String key, String val) { synchronized (this.values) { this.values.put(key, val); } diff -r b78e77619152 -r 8df94bfd3e2f src/org/sonews/config/Config.java --- a/src/org/sonews/config/Config.java Sun Sep 11 15:05:04 2011 +0200 +++ b/src/org/sonews/config/Config.java Sun Sep 11 17:01:19 2011 +0200 @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package org.sonews.config; /** @@ -23,8 +22,7 @@ * @author Christian Lins * @since sonews/1.0 */ -public class Config extends AbstractConfig -{ +public class Config extends AbstractConfig { public static final int LEVEL_CLI = 1; public static final int LEVEL_FILE = 2; @@ -91,18 +89,15 @@ }; private static Config instance = new Config(); - public static Config inst() - { + public static Config inst() { return instance; } - private Config() - { + private Config() { } @Override - public String get(String key, String def) - { + public String get(String key, String def) { String val = CommandLineConfig.getInstance().get(key, null); if (val == null) { @@ -116,8 +111,7 @@ return val; } - public String get(int maxLevel, String key, String def) - { + public String get(int maxLevel, String key, String def) { String val = CommandLineConfig.getInstance().get(key, null); if (val == null && maxLevel >= LEVEL_FILE) { @@ -131,13 +125,11 @@ } @Override - public void set(String key, String val) - { + public void set(String key, String val) { set(LEVEL_BACKEND, key, val); } - public void set(int level, String key, String val) - { + public void set(int level, String key, String val) { switch (level) { case LEVEL_CLI: { CommandLineConfig.getInstance().set(key, val); diff -r b78e77619152 -r 8df94bfd3e2f src/org/sonews/daemon/NNTPConnection.java --- a/src/org/sonews/daemon/NNTPConnection.java Sun Sep 11 15:05:04 2011 +0200 +++ b/src/org/sonews/daemon/NNTPConnection.java Sun Sep 11 17:01:19 2011 +0200 @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package org.sonews.daemon; import java.io.IOException; @@ -30,6 +29,7 @@ import java.util.Arrays; import java.util.Timer; import java.util.TimerTask; +import java.util.logging.Level; import org.sonews.daemon.command.Command; import org.sonews.storage.Article; import org.sonews.storage.Group; @@ -43,8 +43,7 @@ * @author Christian Lins * @since sonews/0.5.0 */ -public final class NNTPConnection -{ +public final class NNTPConnection { public static final String NEWLINE = "\r\n"; // RFC defines this as newline public static final String MESSAGE_ID_PATTERN = "<[^>]+>"; @@ -62,8 +61,7 @@ private SelectionKey writeSelKey = null; public NNTPConnection(final SocketChannel channel) - throws IOException - { + throws IOException { if (channel == null) { throw new IllegalArgumentException("channel is null"); } @@ -77,8 +75,7 @@ * safe and returns true of the read lock was successfully set. If the lock * is still hold by another Thread the method returns false. */ - boolean tryReadLock() - { + boolean tryReadLock() { // As synchronizing simple types may cause deadlocks, // we use a gate object. synchronized (readLockGate) { @@ -96,8 +93,7 @@ * @throws IllegalMonitorStateException if a Thread not holding the lock * tries to release it. */ - void unlockReadLock() - { + void unlockReadLock() { synchronized (readLockGate) { if (readLock == Thread.currentThread().hashCode()) { readLock = 0; @@ -110,8 +106,7 @@ /** * @return Current input buffer of this NNTPConnection instance. */ - public ByteBuffer getInputBuffer() - { + public ByteBuffer getInputBuffer() { return this.lineBuffers.getInputBuffer(); } @@ -119,34 +114,29 @@ * @return Output buffer of this NNTPConnection which has at least one byte * free storage. */ - public ByteBuffer getOutputBuffer() - { + public ByteBuffer getOutputBuffer() { return this.lineBuffers.getOutputBuffer(); } /** * @return ChannelLineBuffers instance associated with this NNTPConnection. */ - public ChannelLineBuffers getBuffers() - { + public ChannelLineBuffers getBuffers() { return this.lineBuffers; } /** * @return true if this connection comes from a local remote address. */ - public boolean isLocalConnection() - { + public boolean isLocalConnection() { return ((InetSocketAddress) this.channel.socket().getRemoteSocketAddress()).getHostName().equalsIgnoreCase("localhost"); } - void setWriteSelectionKey(SelectionKey selKey) - { + void setWriteSelectionKey(SelectionKey selKey) { this.writeSelKey = selKey; } - public void shutdownInput() - { + public void shutdownInput() { try { // Closes the input line of the channel's socket, so no new data // will be received and a timeout can be triggered. @@ -156,14 +146,10 @@ } } - public void shutdownOutput() - { - cancelTimer.schedule(new TimerTask() - { - + public void shutdownOutput() { + cancelTimer.schedule(new TimerTask() { @Override - public void run() - { + public void run() { try { // Closes the output line of the channel's socket. channel.socket().shutdownOutput(); @@ -178,41 +164,34 @@ }, 3000); } - public SocketChannel getSocketChannel() - { + public SocketChannel getSocketChannel() { return this.channel; } - public Article getCurrentArticle() - { + public Article getCurrentArticle() { return this.currentArticle; } - public Charset getCurrentCharset() - { + public Charset getCurrentCharset() { return this.charset; } /** * @return The currently selected communication channel (not SocketChannel) */ - public Group getCurrentChannel() - { + public Group getCurrentChannel() { return this.currentGroup; } - public void setCurrentArticle(final Article article) - { + public void setCurrentArticle(final Article article) { this.currentArticle = article; } - public void setCurrentGroup(final Group group) - { + public void setCurrentGroup(final Group group) { this.currentGroup = group; } - public long getLastActivity() - { + public long getLastActivity() { return this.lastActivity; } @@ -222,8 +201,7 @@ * @throws IllegalArgumentException if raw is null. * @throws IllegalStateException if calling thread does not own the readLock. */ - void lineReceived(byte[] raw) - { + void lineReceived(byte[] raw) { if (raw == null) { throw new IllegalArgumentException("raw is null"); } @@ -262,17 +240,25 @@ } } catch (ClosedChannelException ex0) { try { - Log.get().info("Connection to " + channel.socket().getRemoteSocketAddress() - + " closed: " + ex0); + StringBuilder strBuf = new StringBuilder(); + strBuf.append("Connection to "); + strBuf.append(channel.socket().getRemoteSocketAddress()); + strBuf.append(" closed: "); + strBuf.append(ex0); + Log.get().info(strBuf.toString()); } catch (Exception ex0a) { ex0a.printStackTrace(); } - } catch (Exception ex1) // This will catch a second StorageBackendException - { + } catch (Exception ex1) { // This will catch a second StorageBackendException try { command = null; - ex1.printStackTrace(); - println("500 Internal server error"); + Log.get().log(Level.WARNING, ex1.getLocalizedMessage(), ex1); + println("403 Internal server error"); + + // Should we end the connection here? + // RFC says we MUST return 400 before closing the connection + shutdownInput(); + shutdownOutput(); } catch (Exception ex2) { ex2.printStackTrace(); } @@ -289,8 +275,7 @@ * @param line * @return */ - private Command parseCommandLine(String line) - { + private Command parseCommandLine(String line) { String cmdStr = line.split(" ")[0]; return CommandSelector.getInstance().get(cmdStr); } @@ -303,8 +288,7 @@ * @param line */ public void println(final CharSequence line, final Charset charset) - throws IOException - { + throws IOException { writeToChannel(CharBuffer.wrap(line), charset, line); writeToChannel(CharBuffer.wrap(NEWLINE), charset, null); } @@ -315,8 +299,7 @@ * @param rawLines */ public void println(final byte[] rawLines) - throws IOException - { + throws IOException { this.lineBuffers.addOutputBuffer(ByteBuffer.wrap(rawLines)); writeToChannel(CharBuffer.wrap(NEWLINE), charset, null); } @@ -328,9 +311,8 @@ * @throws java.io.IOException */ private void writeToChannel(CharBuffer characters, final Charset charset, - CharSequence debugLine) - throws IOException - { + CharSequence debugLine) + throws IOException { if (!charset.canEncode()) { Log.get().severe("FATAL: Charset " + charset + " cannot encode!"); return; @@ -343,8 +325,7 @@ enableWriteEvents(debugLine); } - private void enableWriteEvents(CharSequence debugLine) - { + private void enableWriteEvents(CharSequence debugLine) { // Enable OP_WRITE events so that the buffers are processed try { this.writeSelKey.interestOps(SelectionKey.OP_WRITE); @@ -363,24 +344,20 @@ } public void println(final CharSequence line) - throws IOException - { + throws IOException { println(line, charset); } public void print(final String line) - throws IOException - { + throws IOException { writeToChannel(CharBuffer.wrap(line), charset, line); } - public void setCurrentCharset(final Charset charset) - { + public void setCurrentCharset(final Charset charset) { this.charset = charset; } - void setLastActivity(long timestamp) - { + void setLastActivity(long timestamp) { this.lastActivity = timestamp; } } diff -r b78e77619152 -r 8df94bfd3e2f src/org/sonews/daemon/command/ListCommand.java --- a/src/org/sonews/daemon/command/ListCommand.java Sun Sep 11 15:05:04 2011 +0200 +++ b/src/org/sonews/daemon/command/ListCommand.java Sun Sep 11 17:01:19 2011 +0200 @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package org.sonews.daemon.command; import java.io.IOException; @@ -34,37 +33,31 @@ * @author Dennis Schwerdel * @since n3tpd/0.1 */ -public class ListCommand implements Command -{ +public class ListCommand implements Command { @Override - public String[] getSupportedCommandStrings() - { - return new String[] {"LIST"}; + public String[] getSupportedCommandStrings() { + return new String[]{"LIST"}; } @Override - public boolean hasFinished() - { + public boolean hasFinished() { return true; } @Override - public String impliedCapability() - { + public String impliedCapability() { return null; } @Override - public boolean isStateful() - { + public boolean isStateful() { return false; } @Override public void processLine(NNTPConnection conn, final String line, byte[] raw) - throws IOException, StorageBackendException - { + throws IOException, StorageBackendException { final String[] command = line.split(" "); if (command.length >= 2) { @@ -90,7 +83,7 @@ conn.println("."); } else if (command[1].equalsIgnoreCase("ACTIVE")) { String pattern = command.length == 2 - ? null : command[2].replace("*", "\\w*"); + ? null : command[2].replace("*", "\\w*"); printGroupInfo(conn, pattern); } else { conn.println("500 unknown argument to LIST command"); @@ -101,21 +94,20 @@ } private void printGroupInfo(NNTPConnection conn, String pattern) - throws IOException, StorageBackendException - { + throws IOException, StorageBackendException { final List groups = Group.getAll(); if (groups != null) { conn.println("215 list of newsgroups follows"); for (Group g : groups) { try { Matcher matcher = pattern == null - ? null : Pattern.compile(pattern).matcher(g.getName()); + ? null : Pattern.compile(pattern).matcher(g.getName()); if (!g.isDeleted() - && (matcher == null || matcher.find())) { + && (matcher == null || matcher.find())) { String writeable = g.isWriteable() ? " y" : " n"; // Indeed first the higher article number then the lower conn.println(g.getName() + " " + g.getLastArticleNumber() + " " - + g.getFirstArticleNumber() + writeable); + + g.getFirstArticleNumber() + writeable); } } catch (PatternSyntaxException ex) { Log.get().info(ex.toString()); diff -r b78e77619152 -r 8df94bfd3e2f src/org/sonews/util/Stats.java --- a/src/org/sonews/util/Stats.java Sun Sep 11 15:05:04 2011 +0200 +++ b/src/org/sonews/util/Stats.java Sun Sep 11 17:01:19 2011 +0200 @@ -18,6 +18,7 @@ package org.sonews.util; import java.util.Calendar; +import java.util.logging.Level; import org.sonews.config.Config; import org.sonews.storage.Group; import org.sonews.storage.StorageBackendException; @@ -63,10 +64,14 @@ System.currentTimeMillis(), type, group.getInternalID()); } } else { - Log.get().info("Group " + groupname + " does not exist."); + StringBuilder strBuf = new StringBuilder(); + strBuf.append("Group "); + strBuf.append(groupname); + strBuf.append(" does not exist."); + Log.get().info(strBuf.toString()); } } catch (StorageBackendException ex) { - ex.printStackTrace(); + Log.get().log(Level.SEVERE, ex.getLocalizedMessage(), ex); } } @@ -86,7 +91,7 @@ try { return StorageManager.current().countGroups(); } catch (StorageBackendException ex) { - ex.printStackTrace(); + Log.get().log(Level.SEVERE, ex.getLocalizedMessage(), ex); return -1; } } @@ -95,7 +100,7 @@ try { return StorageManager.current().countArticles(); } catch (StorageBackendException ex) { - ex.printStackTrace(); + Log.get().log(Level.SEVERE, ex.getLocalizedMessage(), ex); return -1; } } @@ -117,7 +122,7 @@ try { return StorageManager.current().getEventsCount(eventType, startTimestamp, endTimestamp, group); } catch (StorageBackendException ex) { - ex.printStackTrace(); + Log.get().log(Level.SEVERE, ex.getLocalizedMessage(), ex); return -1; } } @@ -146,7 +151,7 @@ try { return StorageManager.current().getEventsPerHour(key, gid); } catch (StorageBackendException ex) { - ex.printStackTrace(); + Log.get().log(Level.SEVERE, ex.getLocalizedMessage(), ex); return -1; } }