Refactoring in CommandSelector to allow manually loading of plugins.
1.1 --- a/helpers/usage Mon Aug 24 13:00:05 2009 +0200
1.2 +++ b/helpers/usage Mon Aug 24 14:40:37 2009 +0200
1.3 @@ -1,9 +1,16 @@
1.4 java -jar sonews.jar [arguments]
1.5 where arguments:
1.6 - -c|-config <path to config file> if custom config file preferred
1.7 - -dumpjdbcdriver Prints out a list of available JDBC drivers
1.8 - -feed Enables feed daemon for pulling news from peer servers
1.9 - -h|-help This output
1.10 - -mlgw Enables the Mailinglist Gateway poller
1.11 - -p <port> Forces sonews to listen on the specified port.
1.12 - -v|-version Prints out the version info an exits.
1.13 + -c|-config <config file> If custom config file preferred
1.14 + -dumpjdbcdriver Prints out a list of available JDBC drivers
1.15 + -feed Enables feed daemon for pulling/pushing news
1.16 + from/to peer servers
1.17 + -h|-help This output
1.18 + -mlgw Enables the Mailinglist Gateway poller
1.19 + -p <port> Forces sonews to listen on the specified port
1.20 + -plugin <name|class|file> Loads the given plugin.
1.21 + -plugin-command <class> Loads the given class on startup as NNTP command
1.22 + handler. Can be specified multiple times. The
1.23 + class must be found in the JVMs classpath.
1.24 + -plugin-storage <class> Loads the given StorageProvider class. The class
1.25 + must be found in the JVMs classpath.
1.26 + -v|-version Prints out the version info an exits.
2.1 --- a/org/sonews/Main.java Mon Aug 24 13:00:05 2009 +0200
2.2 +++ b/org/sonews/Main.java Mon Aug 24 14:40:37 2009 +0200
2.3 @@ -22,8 +22,10 @@
2.4 import java.sql.DriverManager;
2.5 import java.util.Enumeration;
2.6 import java.util.Date;
2.7 +import java.util.logging.Level;
2.8 import org.sonews.config.Config;
2.9 import org.sonews.daemon.ChannelLineBuffers;
2.10 +import org.sonews.daemon.CommandSelector;
2.11 import org.sonews.daemon.Connections;
2.12 import org.sonews.daemon.NNTPDaemon;
2.13 import org.sonews.feed.FeedManager;
2.14 @@ -100,6 +102,26 @@
2.15 {
2.16 port = Integer.parseInt(args[++n]);
2.17 }
2.18 + else if(args[n].equals("-plugin"))
2.19 + {
2.20 + System.out.println("Warning: -plugin-storage is not implemented!");
2.21 + }
2.22 + else if(args[n].equals("-plugin-command"))
2.23 + {
2.24 + try
2.25 + {
2.26 + CommandSelector.addCommandHandler(args[++n]);
2.27 + }
2.28 + catch(Exception ex)
2.29 + {
2.30 + Log.get().warning("Could not load command plugin: " + args[n]);
2.31 + Log.get().log(Level.INFO, "Main.java", ex);
2.32 + }
2.33 + }
2.34 + else if(args[n].equals("-plugin-storage"))
2.35 + {
2.36 + System.out.println("Warning: -plugin-storage is not implemented!");
2.37 + }
2.38 else if(args[n].equals("-v") || args[n].equals("-version"))
2.39 {
2.40 // Simply return as the version info is already printed above
3.1 --- a/org/sonews/acl/AuthInfoCommand.java Mon Aug 24 13:00:05 2009 +0200
3.2 +++ b/org/sonews/acl/AuthInfoCommand.java Mon Aug 24 14:40:37 2009 +0200
3.3 @@ -18,12 +18,47 @@
3.4
3.5 package org.sonews.acl;
3.6
3.7 +import java.io.IOException;
3.8 +import org.sonews.daemon.NNTPConnection;
3.9 +import org.sonews.daemon.command.Command;
3.10 +import org.sonews.storage.StorageBackendException;
3.11 +
3.12 /**
3.13 *
3.14 * @author Christian Lins
3.15 * @since sonews/1.1
3.16 */
3.17 -public class AuthInfoCommand
3.18 +public class AuthInfoCommand implements Command
3.19 {
3.20
3.21 + @Override
3.22 + public String[] getSupportedCommandStrings()
3.23 + {
3.24 + throw new UnsupportedOperationException("Not supported yet.");
3.25 + }
3.26 +
3.27 + @Override
3.28 + public boolean hasFinished()
3.29 + {
3.30 + throw new UnsupportedOperationException("Not supported yet.");
3.31 + }
3.32 +
3.33 + @Override
3.34 + public String impliedCapability()
3.35 + {
3.36 + throw new UnsupportedOperationException("Not supported yet.");
3.37 + }
3.38 +
3.39 + @Override
3.40 + public boolean isStateful()
3.41 + {
3.42 + throw new UnsupportedOperationException("Not supported yet.");
3.43 + }
3.44 +
3.45 + @Override
3.46 + public void processLine(NNTPConnection conn, String line, byte[] rawLine) throws IOException, StorageBackendException
3.47 + {
3.48 + throw new UnsupportedOperationException("Not supported yet.");
3.49 + }
3.50 +
3.51 }
4.1 --- a/org/sonews/daemon/CommandSelector.java Mon Aug 24 13:00:05 2009 +0200
4.2 +++ b/org/sonews/daemon/CommandSelector.java Mon Aug 24 14:40:37 2009 +0200
4.3 @@ -29,28 +29,17 @@
4.4 /**
4.5 * Selects the correct command processing class.
4.6 * @author Christian Lins
4.7 + * @since sonews/1.0
4.8 */
4.9 -class CommandSelector
4.10 +public class CommandSelector
4.11 {
4.12
4.13 private static Map<Thread, CommandSelector> instances
4.14 = new ConcurrentHashMap<Thread, CommandSelector>();
4.15 -
4.16 - public static CommandSelector getInstance()
4.17 - {
4.18 - CommandSelector csel = instances.get(Thread.currentThread());
4.19 - if(csel == null)
4.20 - {
4.21 - csel = new CommandSelector();
4.22 - instances.put(Thread.currentThread(), csel);
4.23 - }
4.24 - return csel;
4.25 - }
4.26 + private static Map<String, Class<?>> commandClassesMapping
4.27 + = new ConcurrentHashMap<String, Class<?>>();
4.28
4.29 - private Map<String, Command> commandMapping = new HashMap<String, Command>();
4.30 - private Command unsupportedCmd = new UnsupportedCommand();
4.31 -
4.32 - private CommandSelector()
4.33 + static
4.34 {
4.35 String[] classes = Resource.getAsString("helpers/commands.list", true).split("\n");
4.36 for(String className : classes)
4.37 @@ -63,13 +52,7 @@
4.38
4.39 try
4.40 {
4.41 - Class<?> clazz = Class.forName(className);
4.42 - Command cmd = (Command)clazz.newInstance();
4.43 - String[] cmdStrs = cmd.getSupportedCommandStrings();
4.44 - for(String cmdStr : cmdStrs)
4.45 - {
4.46 - this.commandMapping.put(cmdStr, cmd);
4.47 - }
4.48 + addCommandHandler(className);
4.49 }
4.50 catch(ClassNotFoundException ex)
4.51 {
4.52 @@ -86,6 +69,35 @@
4.53 }
4.54 }
4.55
4.56 + public static void addCommandHandler(String className)
4.57 + throws ClassNotFoundException, InstantiationException, IllegalAccessException
4.58 + {
4.59 + Class<?> clazz = Class.forName(className);
4.60 + Command cmd = (Command)clazz.newInstance();
4.61 + String[] cmdStrs = cmd.getSupportedCommandStrings();
4.62 + for (String cmdStr : cmdStrs)
4.63 + {
4.64 + commandClassesMapping.put(cmdStr, clazz);
4.65 + }
4.66 + }
4.67 +
4.68 + public static CommandSelector getInstance()
4.69 + {
4.70 + CommandSelector csel = instances.get(Thread.currentThread());
4.71 + if(csel == null)
4.72 + {
4.73 + csel = new CommandSelector();
4.74 + instances.put(Thread.currentThread(), csel);
4.75 + }
4.76 + return csel;
4.77 + }
4.78 +
4.79 + private Map<String, Command> commandMapping = new HashMap<String, Command>();
4.80 + private Command unsupportedCmd = new UnsupportedCommand();
4.81 +
4.82 + private CommandSelector()
4.83 + {}
4.84 +
4.85 public Command get(String commandName)
4.86 {
4.87 try
4.88 @@ -95,16 +107,23 @@
4.89
4.90 if(cmd == null)
4.91 {
4.92 - return this.unsupportedCmd;
4.93 + Class<?> clazz = commandClassesMapping.get(commandName);
4.94 + if(clazz == null)
4.95 + {
4.96 + cmd = this.unsupportedCmd;
4.97 + }
4.98 + else
4.99 + {
4.100 + cmd = (Command)clazz.newInstance();
4.101 + this.commandMapping.put(commandName, cmd);
4.102 + }
4.103 }
4.104 else if(cmd.isStateful())
4.105 {
4.106 - return cmd.getClass().newInstance();
4.107 + cmd = cmd.getClass().newInstance();
4.108 }
4.109 - else
4.110 - {
4.111 - return cmd;
4.112 - }
4.113 +
4.114 + return cmd;
4.115 }
4.116 catch(Exception ex)
4.117 {
5.1 --- a/org/sonews/daemon/command/XDaemonCommand.java Mon Aug 24 13:00:05 2009 +0200
5.2 +++ b/org/sonews/daemon/command/XDaemonCommand.java Mon Aug 24 14:40:37 2009 +0200
5.3 @@ -237,6 +237,10 @@
5.4 conn.println("401 unknown sub command");
5.5 }
5.6 }
5.7 + else if(commands.length >= 3 && commands[1].equalsIgnoreCase("PLUGIN"))
5.8 + {
5.9 +
5.10 + }
5.11 else
5.12 {
5.13 conn.println("400 invalid command usage");
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/org/sonews/plugin/Plugin.java Mon Aug 24 14:40:37 2009 +0200
6.3 @@ -0,0 +1,42 @@
6.4 +/*
6.5 + * SONEWS News Server
6.6 + * see AUTHORS for the list of contributors
6.7 + *
6.8 + * This program is free software: you can redistribute it and/or modify
6.9 + * it under the terms of the GNU General Public License as published by
6.10 + * the Free Software Foundation, either version 3 of the License, or
6.11 + * (at your option) any later version.
6.12 + *
6.13 + * This program is distributed in the hope that it will be useful,
6.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
6.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6.16 + * GNU General Public License for more details.
6.17 + *
6.18 + * You should have received a copy of the GNU General Public License
6.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
6.20 + */
6.21 +
6.22 +package org.sonews.plugin;
6.23 +
6.24 +/**
6.25 + * A generic Plugin for sonews. Implementing classes do not really add new
6.26 + * functionality to sonews but can use this interface as convenient procedure
6.27 + * for installing functionality plugins, e.g. Command-Plugins or Storage-Plugins.
6.28 + * @author Christian Lins
6.29 + * @since sonews/1.1
6.30 + */
6.31 +public interface Plugin
6.32 +{
6.33 +
6.34 + /**
6.35 + * Called when the Plugin is loaded by sonews. This method can be used
6.36 + * by implementing classes to install additional or required plugins.
6.37 + */
6.38 + void load();
6.39 +
6.40 + /**
6.41 + * Called when the Plugin is unloaded by sonews.
6.42 + */
6.43 + void unload();
6.44 +
6.45 +}