File Source: CommandParser.java

         /* 
    P/P   *  Method: com.dmdirc.commandparser.parsers.CommandParser__static_init
          */
     1  /*
     2   * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
     3   *
     4   * Permission is hereby granted, free of charge, to any person obtaining a copy
     5   * of this software and associated documentation files (the "Software"), to deal
     6   * in the Software without restriction, including without limitation the rights
     7   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8   * copies of the Software, and to permit persons to whom the Software is
     9   * furnished to do so, subject to the following conditions:
    10   *
    11   * The above copyright notice and this permission notice shall be included in
    12   * all copies or substantial portions of the Software.
    13   *
    14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20   * SOFTWARE.
    21   */
    22  
    23  package com.dmdirc.commandparser.parsers;
    24  
    25  import com.dmdirc.Server;
    26  import com.dmdirc.actions.ActionManager;
    27  import com.dmdirc.actions.CoreActionType;
    28  import com.dmdirc.commandparser.CommandArguments;
    29  import com.dmdirc.commandparser.CommandInfo;
    30  import com.dmdirc.commandparser.CommandManager;
    31  import com.dmdirc.commandparser.CommandType;
    32  import com.dmdirc.commandparser.commands.Command;
    33  import com.dmdirc.commandparser.commands.CommandOptions;
    34  import com.dmdirc.commandparser.commands.ExternalCommand;
    35  import com.dmdirc.commandparser.commands.PreviousCommand;
    36  import com.dmdirc.config.IdentityManager;
    37  import com.dmdirc.ui.interfaces.InputWindow;
    38  import com.dmdirc.util.RollingList;
    39  
    40  import java.io.Serializable;
    41  import java.util.HashMap;
    42  import java.util.Hashtable;
    43  import java.util.Map;
    44  
    45  /**
    46   * Represents a generic command parser. A command parser takes a line of input
    47   * from the user, determines if it is an attempt at executing a command (based
    48   * on the character at the start of the string), and handles it appropriately.
    49   *
    50   * @author chris
    51   */
    52  public abstract class CommandParser implements Serializable {
    53  
    54      /**
    55       * A version number for this class. It should be changed whenever the class
    56       * structure is changed (or anything else that would prevent serialized
    57       * objects being unserialized with the new class).
    58       */
    59      private static final long serialVersionUID = 1;
    60  
    61      /**
    62       * Commands that are associated with this parser.
    63       */
    64      private final Map<String, Command> commands;
    65  
    66      /**
    67       * A history of commands that have been entered into this parser.
    68       */
    69      private final RollingList<PreviousCommand> history;
    70  
    71      /** Creates a new instance of CommandParser. */
             /* 
    P/P       *  Method: void com.dmdirc.commandparser.parsers.CommandParser()
              * 
              *  Preconditions:
              *    init'ed(com/dmdirc/config/IdentityManager.globalconfig)
              *    (soft) init'ed(com.dmdirc.config.ConfigManager$1__static_init.new int[](ConfigManager$1__static_init#1)[...])
              * 
              *  Postconditions:
              *    com/dmdirc/config/IdentityManager.globalconfig == One-of{old com/dmdirc/config/IdentityManager.globalconfig, &amp;new ConfigManager(getGlobalConfig#1)}
              *    com/dmdirc/config/IdentityManager.globalconfig != null
              *    java.lang.StringBuilder:toString(...)._tainted == 0
              *    this.commands == &amp;new Hashtable(CommandParser#1)
              *    this.history == &amp;new RollingList(CommandParser#2)
              *    new ArrayList(getSources#1) num objects <= 1
              *    new ConfigManager(getGlobalConfig#1) num objects == new ArrayList(getSources#1) num objects
              *    new MapList(ConfigManager#1) num objects == new ArrayList(getSources#1) num objects
              *    new ConfigManager(getGlobalConfig#1).channel == &amp;java.lang.StringBuilder:toString(...)
              *    init'ed(new ConfigManager(getGlobalConfig#1).file)
              *    ...
              */
    72      public CommandParser() {
    73          commands = new Hashtable<String, Command>();
    74          history = new RollingList<PreviousCommand>(
    75                  IdentityManager.getGlobalConfig().getOptionInt("general",
    76                      "commandhistory"));
    77          loadCommands();
    78      }
    79  
    80      /** Loads the relevant commands into the parser. */
    81      protected abstract void loadCommands();
    82  
    83      /**
    84       * Registers the specified command with this parser.
    85       *
    86       * @since 0.6.3m1
    87       * @param command Command to be registered
    88       * @param info The information the command should be registered with
    89       */
    90      public final void registerCommand(final Command command, final CommandInfo info) {
                 /* 
    P/P           *  Method: void registerCommand(Command, CommandInfo)
                  * 
                  *  Preconditions:
                  *    info != null
                  *    this.commands != null
                  * 
                  *  Presumptions:
                  *    getName(...)@91 != null
                  */
    91          commands.put(info.getName().toLowerCase(), command);
    92      }
    93  
    94      /**
    95       * Unregisters the specified command with this parser.
    96       *
    97       * @param info Command information to be unregistered
    98       * @since 0.6.3m1
    99       */
   100      public final void unregisterCommand(final CommandInfo info) {
                 /* 
    P/P           *  Method: void unregisterCommand(CommandInfo)
                  * 
                  *  Preconditions:
                  *    info != null
                  *    this.commands != null
                  * 
                  *  Presumptions:
                  *    getName(...)@101 != null
                  */
   101          commands.remove(info.getName().toLowerCase());
   102      }
   103  
   104      /**
   105       * Retrieves a map of commands known by this command parser.
   106       *
   107       * @since 0.6.3m1
   108       * @return A map of commands known to this parser
   109       */
   110      public Map<String, Command> getCommands() {
                 /* 
    P/P           *  Method: Map getCommands()
                  * 
                  *  Postconditions:
                  *    return_value == &amp;new HashMap(getCommands#1)
                  *    new HashMap(getCommands#1) num objects == 1
                  */
   111          return new HashMap<String, Command>(commands);
   112      }
   113  
   114      /**
   115       * Parses the specified string as a command.
   116       *
   117       * @param origin The window in which the command was typed
   118       * @param line The line to be parsed
   119       * @param parseChannel Whether or not to try and parse the first argument
   120       * as a channel name
   121       */
   122      public final void parseCommand(final InputWindow origin,
   123              final String line, final boolean parseChannel) {
                 /* 
    P/P           *  Method: void parseCommand(InputWindow, String, bool)
                  * 
                  *  Preconditions:
                  *    line != null
                  *    (soft) init'ed(com/dmdirc/commandparser/CommandManager.commandChar)
                  *    (soft) init'ed(com/dmdirc/commandparser/CommandManager.silenceChar)
                  *    (soft) this.commands != null
                  *    (soft) this.history != null
                  * 
                  *  Presumptions:
                  *    args.words.length@131 <= 232-1
                  *    args.words.length@139 <= 232-1
                  *    cargs.length@131 >= 1
                  *    com.dmdirc.Channel:getFrame(...)@139 != null
                  *    com.dmdirc.Server:getChannel(...)@139 != null
                  *    ...
                  * 
                  *  Test Vectors:
                  *    origin: Addr_Set{null}, Inverse{null}
                  *    parseChannel: {0}, {1}
                  *    com.dmdirc.Server:hasChannel(...)@138: {0}, {1}
                  *    com.dmdirc.Server:isValidChannelName(...)@131: {0}, {1}
                  *    com.dmdirc.WritableFrameContainer:getServer(...)@131: Addr_Set{null}, Inverse{null}
                  *    com.dmdirc.ui.interfaces.InputWindow:getContainer(...)@131: Addr_Set{null}, Inverse{null}
                  *    getArguments(...).length@131: {0}, {1..+Inf}
                  *    java.util.Map:containsKey(...)@156: {0}, {1}
                  */
   124          final CommandArguments args = new CommandArguments(line);
   125  
   126          if (args.isCommand()) {
   127              final boolean silent = args.isSilent();
   128              final String command = args.getCommandName();
   129              final String[] cargs = args.getArguments();
   130  
   131              if (args.getArguments().length > 0 && parseChannel && origin != null
   132                      && origin.getContainer() != null
   133                      && origin.getContainer().getServer() != null
   134                      && origin.getContainer().getServer().isValidChannelName(cargs[0])
   135                      && CommandManager.isChannelCommand(command)) {
   136                  final Server server = origin.getContainer().getServer();
   137  
   138                  if (server.hasChannel(cargs[0])) {
   139                      server.getChannel(cargs[0]).getFrame().getCommandParser()
   140                              .parseCommand(origin, CommandManager.getCommandChar()
   141                              + args.getCommandName() + " " + args.getWordsAsString(2), false);
   142                      return;
   143                  } else {
   144                      final Map.Entry<CommandInfo, Command> actCommand = CommandManager.getCommand(
   145                              CommandType.TYPE_CHANNEL, command);
   146  
   147                      if (actCommand != null && actCommand.getValue() instanceof ExternalCommand) {
   148                          ((ExternalCommand) actCommand.getValue()).execute(
   149                                  origin, server, cargs[0], silent,
   150                                  new CommandArguments(args.getWordsAsString(2)));
   151                          return;
   152                      }
   153                  }
   154              }
   155  
   156              if (commands.containsKey(command.toLowerCase())) {
   157                  addHistory(args.getStrippedLine());
   158                  executeCommand(origin, silent, commands.get(command.toLowerCase()), args);
   159             } else {
   160                  handleInvalidCommand(origin, args);
   161              }
   162          } else {
   163              handleNonCommand(origin, line);
   164          }
   165      }
   166  
   167      /**
   168       * Adds a command to this parser's history.
   169       *
   170       * @param command The command name and arguments that were used
   171       */
   172      private void addHistory(final String command) {
                 /* 
    P/P           *  Method: void addHistory(String)
                  * 
                  *  Preconditions:
                  *    this.history != null
                  */
   173          synchronized(history) {
   174              final PreviousCommand pc = new PreviousCommand(command);
   175              history.remove(pc);
   176              history.add(pc);
   177          }
   178      }
   179  
   180      /**
   181       * Retrieves the most recent time that the specified command was used.
   182       * Commands should not include command or silence chars.
   183       *
   184       * @param command The command to search for
   185       * @return The timestamp that the command was used, or 0 if it wasn't
   186       */
   187      public long getCommandTime(final String command) {
                 /* 
    P/P           *  Method: long getCommandTime(String)
                  * 
                  *  Preconditions:
                  *    this.history != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.util.RollingList:getList(...)@191 != null
                  *    java.util.Iterator:next(...)@191 != null
                  *    pc.line@191 != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  * 
                  *  Test Vectors:
                  *    java.lang.String:matches(...)@192: {0}, {1}
                  *    java.util.Iterator:hasNext(...)@191: {1}, {0}
                  */
   188          long res = 0;
   189  
   190          synchronized(history) {
   191              for (PreviousCommand pc : history.getList()) {
   192                  if (pc.getLine().matches("(?i)" + command)) {
   193                      res = Math.max(res, pc.getTime());
   194                  }
   195              }
   196          }
   197  
   198          return res;
   199      }
   200  
   201      /**
   202       * Parses the specified string as a command.
   203       *
   204       * @param origin The window in which the command was typed
   205       * @param line The line to be parsed
   206       */
   207      public final void parseCommand(final InputWindow origin,
   208              final String line) {
                 /* 
    P/P           *  Method: void parseCommand(InputWindow, String)
                  * 
                  *  Preconditions:
                  *    line != null
                  *    (soft) init'ed(com/dmdirc/commandparser/CommandManager.commandChar)
                  *    (soft) init'ed(com/dmdirc/commandparser/CommandManager.silenceChar)
                  *    (soft) this.commands != null
                  *    (soft) this.history != null
                  */
   209          parseCommand(origin, line, true);
   210      }
   211  
   212      /**
   213       * Handles the specified string as a non-command.
   214       *
   215       * @param origin The window in which the command was typed
   216       * @param line The line to be parsed
   217       */
   218      public final void parseCommandCtrl(final InputWindow origin, final String line) {
                 /* 
    P/P           *  Method: void parseCommandCtrl(InputWindow, String)
                  */
   219          handleNonCommand(origin, line);
   220      }
   221  
   222      /**
   223       * Executes the specified command with the given arguments.
   224       *
   225       * @param origin The window in which the command was typed
   226       * @param isSilent Whether the command is being silenced or not
   227       * @param command The command to be executed
   228       * @param args The arguments to the command
   229       * @since 0.6.3m1
   230       */
   231      protected abstract void executeCommand(final InputWindow origin,
   232              final boolean isSilent, final Command command, final CommandArguments args);
   233  
   234      /**
   235       * Called when the user attempted to issue a command (i.e., used the command
   236       * character) that wasn't found. It could be that the command has a different
   237       * arity, or that it plain doesn't exist.
   238       *
   239       * @param origin The window in which the command was typed
   240       * @param args The arguments passed to the command
   241       * @since 0.6.3m1
   242       */
   243      protected void handleInvalidCommand(final InputWindow origin,
   244              final CommandArguments args) {
                 /* 
    P/P           *  Method: void handleInvalidCommand(InputWindow, CommandArguments)
                  * 
                  *  Preconditions:
                  *    args != null
                  *    args.line != null
                  *    init'ed(args.words)
                  *    (soft) init'ed(com/dmdirc/commandparser/CommandManager.commandChar)
                  *    (soft) init'ed(com/dmdirc/commandparser/CommandManager.silenceChar)
                  * 
                  *  Presumptions:
                  *    init'ed(com.dmdirc.actions.CoreActionType.UNKNOWN_COMMAND)
                  * 
                  *  Postconditions:
                  *    args.words != null
                  *    init'ed(java.lang.String:split(...)._tainted)
                  *    java.lang.String:split(...)._tainted == 0
                  *    init'ed(java.lang.String:split(...).length)
                  *    init'ed(java.lang.String:split(...)[0])
                  *    java.lang.String:split(...)[0]._tainted == 0
                  * 
                  *  Test Vectors:
                  *    origin: Inverse{null}, Addr_Set{null}
                  */
   245          if (origin == null) {
   246              ActionManager.processEvent(CoreActionType.UNKNOWN_COMMAND, null,
   247                      null, args.getCommandName(), args.getArguments());
   248          } else {
   249              final StringBuffer buff = new StringBuffer("unknownCommand");
   250  
   251              ActionManager.processEvent(CoreActionType.UNKNOWN_COMMAND, buff,
   252                      origin.getContainer(), args.getCommandName(), args.getArguments());
   253  
   254              origin.addLine(buff, args.getCommandName());
   255          }
   256      }
   257  
   258      /**
   259       * Called when the input was a line of text that was not a command. This normally
   260       * means it is sent to the server/channel/user as-is, with no further processing.
   261       *
   262       * @param origin The window in which the command was typed
   263       * @param line The line input by the user
   264       */
   265      protected abstract void handleNonCommand(final InputWindow origin,
   266              final String line);
   267  
   268      /**
   269       * Determines if the specified command has defined any command options.
   270       *
   271       * @param command The command to investigate
   272       * @return True if the command defines options, false otherwise
   273       */
   274      protected boolean hasCommandOptions(final Command command) {
                 /* 
    P/P           *  Method: bool hasCommandOptions(Command)
                  * 
                  *  Preconditions:
                  *    command != null
                  * 
                  *  Presumptions:
                  *    java.lang.Object:getClass(...)@275 != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   275          return command.getClass().isAnnotationPresent(CommandOptions.class);
   276      }
   277  
   278      /**
   279       * Retrieves the command options for the specified command. If the command
   280       * does not define options, this method will return null.
   281       *
   282       * @param command The command whose options should be retrieved
   283       * @return The command's options, or null if not available
   284       */
   285      protected CommandOptions getCommandOptions(final Command command) {
                 /* 
    P/P           *  Method: CommandOptions getCommandOptions(Command)
                  * 
                  *  Preconditions:
                  *    command != null
                  * 
                  *  Presumptions:
                  *    java.lang.Object:getClass(...)@286 != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   286          return command.getClass().getAnnotation(CommandOptions.class);
   287      }
   288  }








SofCheck Inspector Build Version : 2.17854
CommandParser.java 2009-Jun-25 01:54:24
CommandParser.class 2009-Sep-02 17:04:12