Refactoring in CommandSelector to allow manually loading of plugins.
authorcli
Mon Aug 24 14:40:37 2009 +0200 (2009-08-24)
changeset 214b2c8bedb094
parent 20 6ae5e4f8329b
child 22 2541bdb54cb2
Refactoring in CommandSelector to allow manually loading of plugins.
helpers/usage
org/sonews/Main.java
org/sonews/acl/AuthInfoCommand.java
org/sonews/daemon/CommandSelector.java
org/sonews/daemon/command/XDaemonCommand.java
org/sonews/plugin/Plugin.java
     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 +}