File Source: ActionModel.java

     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.actions;
    24  
    25  import com.dmdirc.actions.interfaces.ActionType;
    26  import com.dmdirc.Main;
    27  import com.dmdirc.Precondition;
    28  import com.dmdirc.ServerManager;
    29  import com.dmdirc.WritableFrameContainer;
    30  import com.dmdirc.commandparser.parsers.CommandParser;
    31  import com.dmdirc.commandparser.parsers.GlobalCommandParser;
    32  import com.dmdirc.ui.interfaces.InputWindow;
    33  import com.dmdirc.ui.interfaces.Window;
    34  
    35  import java.util.ArrayList;
    36  import java.util.Arrays;
    37  import java.util.List;
    38  
    39  /**
    40   * Represents the basic model of an action, and its triggering mechanism.
    41   * Saving and loading are handled by the Action class.
    42   *
    43   * @author chris
    44   */
         /* 
    P/P   *  Method: com.dmdirc.actions.ActionModel__static_init
          */
    45  public class ActionModel {
    46  
    47      /** The group this action belongs to. */
    48      protected String group;
    49  
    50      /** The name of this action. */
    51      protected String name;
    52  
    53      /** The ActionTypes that trigger this action. */
    54      protected ActionType[] triggers;
    55  
    56      /** The commands to execute if this action is triggered. */
    57      protected String[] response;
    58  
    59      /** The change that should be made to the format string, if any. */
    60      protected String newFormat;
    61  
    62      /** The conditions for this action. */
    63      protected List<ActionCondition> conditions = new ArrayList<ActionCondition>();
    64      
    65      /** The condition tree used for evaluating conditions. */
    66      protected ConditionTree conditionTree;
    67      
    68      /** Whether this action has been modified or not. */
    69      protected boolean modified;
    70      
    71      /**
    72       * Creates a new instance of ActionModel with the specified properties.
    73       *
    74       * @param group The group the action belongs to
    75       * @param name The name of the action
    76       */
             /* 
    P/P       *  Method: void com.dmdirc.actions.ActionModel(String, String)
              * 
              *  Postconditions:
              *    this.conditions == &amp;new ArrayList(ActionModel#1)
              *    this.group == group
              *    init'ed(this.group)
              *    this.name == name
              *    init'ed(this.name)
              *    new ArrayList(ActionModel#1) num objects == 1
              */
    77      public ActionModel(final String group, final String name) {
    78          this.group = group;
    79          this.name = name;
    80      }    
    81      
    82      /**
    83       * Creates a new instance of ActionModel with the specified properties.
    84       *
    85       * @param group The group the action belongs to
    86       * @param name The name of the action
    87       * @param triggers The triggers to use
    88       * @param response The response to use
    89       * @param conditions The conditions to use
    90       * @param conditionTree The condition tree to use
    91       * @param newFormat The new formatter to use
    92       */
    93      public ActionModel(final String group, final String name,
    94              final ActionType[] triggers, final String[] response,
    95              final List<ActionCondition> conditions,
                     /* 
    P/P               *  Method: void com.dmdirc.actions.ActionModel(String, String, ActionType[], String[], List, ConditionTree, String)
                      * 
                      *  Preconditions:
                      *    response != null
                      *    triggers != null
                      *    (soft) init'ed(response[...])
                      *    (soft) init'ed(triggers[...])
                      * 
                      *  Postconditions:
                      *    this.conditionTree == conditionTree
                      *    init'ed(this.conditionTree)
                      *    this.conditions == conditions
                      *    init'ed(this.conditions)
                      *    this.group == group
                      *    init'ed(this.group)
                      *    this.modified == 1
                      *    new ActionType[](ActionModel#2) num objects == 1
                      *    new ArrayList(ActionModel#1) num objects == 1
                      *    new String[](ActionModel#3) num objects == 1
                      *    ...
                      */
    96              final ConditionTree conditionTree, final String newFormat) {
    97          this.group = group;
    98          this.name = name;
    99          this.triggers = triggers.clone();
   100          this.response = response.clone();
   101          this.conditions = conditions;
   102          this.conditionTree = conditionTree;
   103          this.newFormat = newFormat;
   104          this.modified = true;
   105      }
   106  
   107      /**
   108       * Triggers this action.
   109       *
   110       * @param format The format of the message that's going to be displayed.
   111       * @param arguments The arguments from the action that caused this trigger.
   112       */
   113      @Precondition({
   114          "This action has at least one trigger",
   115          "This action's primary trigger is non-null"
   116      })
   117      public void trigger(final StringBuffer format, final Object... arguments) {
                 /* 
    P/P           *  Method: void trigger(StringBuffer, Object[])
                  * 
                  *  Preconditions:
                  *    init'ed(this.conditionTree)
                  *    this.conditions != null
                  *    this.triggers != null
                  *    this.triggers.length >= 1
                  *    this.triggers[0] != null
                  *    (soft) arguments != null
                  *    (soft) init'ed(arguments[0])
                  *    (soft) init'ed(arguments[1])
                  *    (soft) arguments[1].length in {1..232-1}
                  *    (soft) init'ed(arguments[2])
                  *    ...
                  * 
                  *  Presumptions:
                  *    com.dmdirc.commandparser.parsers.GlobalCommandParser:getGlobalCommandParser(...)@140 != null
                  *    com.dmdirc.ui.interfaces.InputWindow:getCommandParser(...)@142 != null
                  *    getServerManager(...).servers != null
                  *    java.util.List:get(...)@136 != null
                  * 
                  *  Postconditions:
                  *    init'ed(com/dmdirc/ServerManager.me)
                  *    init'ed(format._tainted)
                  *    new ArrayList(ServerManager#1) num objects <= 1
                  *    new ArrayList(ServerManager#1) num objects == 0
                  *    new ServerManager(getServerManager#1) num objects <= 1
                  *    new ServerManager(getServerManager#1) num objects == 0
                  *    init'ed(new ServerManager(getServerManager#1).servers)
                  * 
                  *  Test Vectors:
                  *    arguments.length: {0}, {1..+Inf}
                  *    format: Addr_Set{null}, Inverse{null}
                  *    this.newFormat: Addr_Set{null}, Inverse{null}
                  *    java.util.List:size(...)@140: {-231..0}, {1..232-1}
                  */
   118          assert(triggers.length > 0);
   119          assert(triggers[0] != null);
   120          
   121          final ActionSubstitutor sub = new ActionSubstitutor(triggers[0]);
   122          
   123          if (!test(sub, arguments)) {
   124              return;
   125          }
   126  
   127          final Window active = Main.getUI().getActiveWindow();
   128          InputWindow cw = null;
   129          CommandParser cp = null;
   130  
   131          if (arguments.length > 0 && arguments[0] instanceof WritableFrameContainer) {
   132              cw = ((WritableFrameContainer) arguments[0]).getFrame();
   133          } else if (active instanceof InputWindow) {
   134              cw = (InputWindow) active;
   135          } else if (ServerManager.getServerManager().numServers() > 0) {
   136              cw = ServerManager.getServerManager().getServers().get(0).getFrame();
   137          }
   138  
   139          if (cw == null) {
   140              cp = GlobalCommandParser.getGlobalCommandParser();
   141          } else {
   142              cp = cw.getCommandParser();
   143          }
   144  
   145          for (String command : response) {
   146              cp.parseCommand(cw, sub.doSubstitution(command, arguments));
   147          }
   148  
   149          if (newFormat != null && format != null) {
   150              format.setLength(0);
   151              format.append(newFormat);
   152          }
   153      }
   154      
   155      /**
   156       * Tests to see if this action should be triggered or not.
   157       * 
   158       * @param sub The ActionsSubstitutor to use to substitute args
   159       * @param arguments The arguments for the action event
   160       * @return True if the action should be executed, false otherwise
   161       */
   162      public boolean test(final ActionSubstitutor sub, final Object ... arguments) {
                 /* 
    P/P           *  Method: bool test(ActionSubstitutor, Object[])
                  * 
                  *  Preconditions:
                  *    init'ed(this.conditionTree)
                  *    this.conditions != null
                  *    (soft) arguments != null
                  *    (soft) init'ed(arguments[0])
                  *    (soft) init'ed(arguments[1])
                  *    (soft) arguments[1].length in {1..232-1}
                  *    (soft) init'ed(arguments[2])
                  *    (soft) arguments[2].length in {1..232-1}
                  *    (soft) init'ed(arguments[...])
                  *    (soft) init'ed(com.dmdirc.actions.ConditionTree$1__static_init.new int[](ConditionTree$1__static_init#1)[...])
                  *    ...
                  * 
                  *  Presumptions:
                  *    condition.arg@166 >= -1
                  *    condition.arg@166 < arguments.length
                  *    condition.comparison@166 != null
                  *    condition.component@166 != null
                  *    getRealConditionTree(...)...argument@170 >= 0
                  *    ...
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@166: {0}, {1}
                  */
   163          final boolean[] results = new boolean[conditions.size()];
   164          
   165          int i = 0;
   166          for (ActionCondition condition : conditions) {
   167              results[i++] = condition.test(sub, arguments);
   168          }
   169          
   170          return getRealConditionTree().evaluate(results);
   171      }
   172  
   173      /**
   174       * Retrieves a list of this action's conditions.
   175       *
   176       * @return A list of this action's conditions
   177       */
   178      public List<ActionCondition> getConditions() {
                 /* 
    P/P           *  Method: List getConditions()
                  * 
                  *  Preconditions:
                  *    init'ed(this.conditions)
                  * 
                  *  Postconditions:
                  *    return_value == this.conditions
                  *    init'ed(return_value)
                  */
   179          return conditions;
   180      }
   181  
   182      /**
   183       * Sets this action's conditions.
   184       *
   185       * @param conditions A list of conditions to use
   186       */
   187      public void setConditions(final List<ActionCondition> conditions) {
                 /* 
    P/P           *  Method: void setConditions(List)
                  * 
                  *  Postconditions:
                  *    this.conditions == conditions
                  *    init'ed(this.conditions)
                  *    this.modified == 1
                  */
   188          this.conditions = conditions;
   189          this.modified = true;
   190      }
   191  
   192      /**
   193       * Retrieves this action's triggers.
   194       *
   195       * @return The triggers used by this action
   196       */
   197      public ActionType[] getTriggers() {
                 /* 
    P/P           *  Method: ActionType[] getTriggers()
                  * 
                  *  Preconditions:
                  *    init'ed(this.triggers)
                  *    (soft) init'ed(this.triggers[...])
                  * 
                  *  Postconditions:
                  *    return_value == One-of{this.triggers, &amp;new ActionType[](getTriggers#1)}
                  *    return_value in Addr_Set{null,&amp;new ActionType[](getTriggers#1)}
                  *    new ActionType[](getTriggers#1) num objects <= 1
                  *    new ActionType[](getTriggers#1).length == this.triggers.length
                  *    init'ed(new ActionType[](getTriggers#1).length)
                  *    new ActionType[](getTriggers#1)[...] == One-of{this.triggers[...], undefined}
                  */
   198          return triggers == null ? triggers : triggers.clone();
   199      }
   200  
   201      /**
   202       * Sets this action's triggers.
   203       *
   204       * @param triggers The new triggers to use
   205       */
   206      public void setTriggers(final ActionType[] triggers) {
                 /* 
    P/P           *  Method: void setTriggers(ActionType[])
                  * 
                  *  Preconditions:
                  *    triggers != null
                  *    (soft) init'ed(triggers[...])
                  * 
                  *  Postconditions:
                  *    this.modified == 1
                  *    new ActionType[](setTriggers#1) num objects == 1
                  *    this.triggers == &amp;new ActionType[](setTriggers#1)
                  *    this.triggers.length == triggers.length
                  *    init'ed(this.triggers.length)
                  *    possibly_updated(this.triggers[...])
                  */
   207          this.triggers = triggers.clone();
   208          this.modified = true;
   209      }
   210  
   211      /**
   212       * Retrieves this action's new format setting.
   213       *
   214       * @return The format that this action will use, or null if no change
   215       */
   216      public String getNewFormat() {
                 /* 
    P/P           *  Method: String getNewFormat()
                  * 
                  *  Preconditions:
                  *    init'ed(this.newFormat)
                  * 
                  *  Postconditions:
                  *    return_value == this.newFormat
                  *    init'ed(return_value)
                  */
   217          return newFormat;
   218      }
   219  
   220      /**
   221       * Sets this action's new format setting.
   222       *
   223       * @param newFormat The new 'new format' setting
   224       */
   225      public void setNewFormat(final String newFormat) {
                 /* 
    P/P           *  Method: void setNewFormat(String)
                  * 
                  *  Postconditions:
                  *    this.modified == 1
                  *    this.newFormat == newFormat
                  *    init'ed(this.newFormat)
                  */
   226          this.newFormat = newFormat;
   227          this.modified = true;
   228      }
   229  
   230      /**
   231       * Retrieves this action's response.
   232       *
   233       * @return The commands that will be executed if this action is triggered
   234       */
   235      public String[] getResponse() {
                 /* 
    P/P           *  Method: String[] getResponse()
                  * 
                  *  Preconditions:
                  *    init'ed(this.response)
                  *    (soft) init'ed(this.response[...])
                  * 
                  *  Postconditions:
                  *    return_value == One-of{this.response, &amp;new String[](getResponse#1)}
                  *    return_value in Addr_Set{null,&amp;new String[](getResponse#1)}
                  *    new String[](getResponse#1) num objects <= 1
                  *    new String[](getResponse#1).length == this.response.length
                  *    init'ed(new String[](getResponse#1).length)
                  *    new String[](getResponse#1)[...] == One-of{this.response[...], undefined}
                  */
   236          return response == null ? response : response.clone();
   237      }
   238  
   239      /**
   240       * Sets this action's response.
   241       *
   242       * @param response The new response to use
   243       */
   244      public void setResponse(final String[] response) {
                 /* 
    P/P           *  Method: void setResponse(String[])
                  * 
                  *  Preconditions:
                  *    response != null
                  *    (soft) init'ed(response[...])
                  * 
                  *  Postconditions:
                  *    this.modified == 1
                  *    new String[](setResponse#1) num objects == 1
                  *    this.response == &amp;new String[](setResponse#1)
                  *    this.response.length == response.length
                  *    init'ed(this.response.length)
                  *    possibly_updated(this.response[...])
                  */
   245          this.response = response.clone();
   246          this.modified = true;
   247      }
   248  
   249      /**
   250       * Retrieves this action's group name.
   251       *
   252       * @return This action's group name
   253       */
   254      public String getGroup() {
                 /* 
    P/P           *  Method: String getGroup()
                  * 
                  *  Preconditions:
                  *    init'ed(this.group)
                  * 
                  *  Postconditions:
                  *    return_value == this.group
                  *    init'ed(return_value)
                  */
   255          return group;
   256      }
   257      
   258      /**
   259       * Sets the group of this action.
   260       *
   261       * @param newGroup The new group for this action
   262       */
   263      public void setGroup(final String newGroup) {
                 /* 
    P/P           *  Method: void setGroup(String)
                  * 
                  *  Postconditions:
                  *    this.group == newGroup
                  *    init'ed(this.group)
                  *    this.modified == 1
                  */
   264          this.group = newGroup;
   265          this.modified = true;
   266      }
   267  
   268      /**
   269       * Retrieves this action's name.
   270       *
   271       * @return This action's name
   272       */
   273      public String getName() {
                 /* 
    P/P           *  Method: String getName()
                  * 
                  *  Preconditions:
                  *    init'ed(this.name)
                  * 
                  *  Postconditions:
                  *    return_value == this.name
                  *    init'ed(return_value)
                  */
   274          return name;
   275      }
   276      
   277      /**
   278       * Sets the name of this action.
   279       *
   280       * @param newName The new name for this action
   281       */
   282      public void setName(final String newName) {
                 /* 
    P/P           *  Method: void setName(String)
                  * 
                  *  Postconditions:
                  *    this.modified == 1
                  *    this.name == newName
                  *    init'ed(this.name)
                  */
   283          this.name = newName;
   284          this.modified = true;
   285      }
   286  
   287      /**
   288       * Retrieves the condition tree used for this action. Condition trees may
   289       * be null, in which case the arguments are conjoined together.
   290       * 
   291       * @return This action's condition tree
   292       */
   293      public ConditionTree getConditionTree() {
                 /* 
    P/P           *  Method: ConditionTree getConditionTree()
                  * 
                  *  Preconditions:
                  *    init'ed(this.conditionTree)
                  * 
                  *  Postconditions:
                  *    return_value == this.conditionTree
                  *    init'ed(return_value)
                  */
   294          return conditionTree;
   295      }
   296      
   297      /**
   298       * Retrieves a concrete condition tree used for this action. If there is
   299       * no condition tree defined for this action, returns a conjunction tree
   300       * for the arguments.
   301       * 
   302       * @since 0.6
   303       * @return A {@link ConditionTree} object for this action
   304       */
   305      public ConditionTree getRealConditionTree() {
                 /* 
    P/P           *  Method: ConditionTree getRealConditionTree()
                  * 
                  *  Preconditions:
                  *    init'ed(this.conditionTree)
                  *    (soft) this.conditions != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  *    new ConditionTree(parseStack#3) num objects <= 1
                  *    new ConditionTree(parseStack#3).argument == -1
                  *    new ConditionTree(parseStack#3).leftArg == null
                  *    new ConditionTree(parseStack#3).op == &amp;com.dmdirc.actions.ConditionTree$OPERATION__static_init.new ConditionTree$OPERATION(ConditionTree$OPERATION__static_init#5)
                  *    new ConditionTree(parseStack#3).rightArg == null
                  *    init'ed(new ConditionTree(readTerm#1) num objects)
                  *    new ConditionTree(readTerm#1).argument == 0, if init'ed
                  *    new ConditionTree(readTerm#1).leftArg == null
                  *    new ConditionTree(readTerm#1).op == null
                  *    ...
                  */
   306          return conditionTree == null
   307                  ? ConditionTree.createConjunction(conditions.size()) : conditionTree;
   308      }
   309  
   310      /**
   311       * Sets the condition tree used for this action.
   312       * 
   313       * @param conditionTree The new condition tree to be used
   314       */
   315      public void setConditionTree(final ConditionTree conditionTree) {
                 /* 
    P/P           *  Method: void setConditionTree(ConditionTree)
                  * 
                  *  Postconditions:
                  *    this.conditionTree == conditionTree
                  *    init'ed(this.conditionTree)
                  *    this.modified == 1
                  */
   316          this.conditionTree = conditionTree;
   317          this.modified = true;
   318      }    
   319      
   320      /**
   321       * Determine if this model has been modified since it was constructed or
   322       * its modified status was reset.
   323       * 
   324       * @return True if this model has been modified, false otherwise
   325       */
   326      public boolean isModified() {
                 /* 
    P/P           *  Method: bool isModified()
                  * 
                  *  Preconditions:
                  *    init'ed(this.modified)
                  * 
                  *  Postconditions:
                  *    return_value == this.modified
                  *    init'ed(return_value)
                  */
   327          return modified;
   328      }
   329      
   330      /**
   331       * Resets the modified status of this model. After a call to
   332       * resetModified(), this model will report that it has not been modified,
   333       * until one of the set* methods is used.
   334       */
   335      public void resetModified() {
                 /* 
    P/P           *  Method: void resetModified()
                  * 
                  *  Postconditions:
                  *    this.modified == 0
                  */
   336          this.modified = false;
   337      }
   338      
   339      /** {@inheritDoc} */
   340      @Override
   341      public String toString() {
                 /* 
    P/P           *  Method: String toString()
                  * 
                  *  Preconditions:
                  *    init'ed(this.conditions)
                  *    init'ed(this.group)
                  *    init'ed(this.name)
                  *    init'ed(this.newFormat)
                  *    init'ed(this.response)
                  *    init'ed(this.triggers)
                  * 
                  *  Postconditions:
                  *    java.lang.StringBuilder:toString(...)._tainted == this.conditions._tainted | this.group._tainted | this.name._tainted | One-of{this.conditions._tainted | this.group._tainted | this.name._tainted, this.newFormat._tainted}
                  *    init'ed(java.lang.StringBuilder:toString(...)._tainted)
                  *    return_value == &amp;java.lang.StringBuilder:toString(...)
                  */
   342          return "[name=" + group + "/" + name + ", triggers="
   343                  + Arrays.toString(triggers) + ", response="
   344                  + Arrays.toString(response) + ", "
   345                  + conditions + ", format='" + newFormat + "']";
   346      }    
   347  }








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