File Source: ActionSubstitutor.java

         /* 
    P/P   *  Method: com.dmdirc.actions.ActionSubstitutor__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.actions;
    24  
    25  import com.dmdirc.actions.interfaces.ActionType;
    26  import com.dmdirc.actions.interfaces.ActionComponent;
    27  import com.dmdirc.FrameContainer;
    28  import com.dmdirc.Server;
    29  import com.dmdirc.ServerState;
    30  import com.dmdirc.config.IdentityManager;
    31  
    32  import java.util.HashMap;
    33  import java.util.Map;
    34  import java.util.Set;
    35  
    36  /**
    37   * Handles the substitution of variables into action targets and responses.
    38   *
    39   * @author Chris
    40   */
    41  public class ActionSubstitutor {
    42      
    43      /** The action type this substitutor is for. */
    44      private final ActionType type;
    45      
    46      /**
    47       * Creates a new substitutor for the specified action type.
    48       *
    49       * @param type The action type this substitutor is for
    50       */
             /* 
    P/P       *  Method: void com.dmdirc.actions.ActionSubstitutor(ActionType)
              * 
              *  Postconditions:
              *    this.type == type
              *    init'ed(this.type)
              */
    51      public ActionSubstitutor(final ActionType type) {
    52          this.type = type;
    53      }
    54      
    55      /**
    56       * Retrieves a list of global config variables that will be substituted.
    57       * Note: does not include initial $.
    58       *
    59       * @return A list of global variable names that will be substituted
    60       */
    61      public Set<String> getConfigSubstitutions() {
                 /* 
    P/P           *  Method: Set getConfigSubstitutions()
                  * 
                  *  Presumptions:
                  *    com.dmdirc.config.ConfigManager:getOptions(...)@62 != null
                  *    com.dmdirc.config.IdentityManager:getGlobalConfig(...)@62 != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
    62          return IdentityManager.getGlobalConfig().getOptions("actions").keySet();
    63      }
    64      
    65      /**
    66       * Substitutes in config variables into the specified target.
    67       *
    68       * @param target The StringBuilder to modify
    69       */
    70      private void doConfigSubstitutions(final StringBuilder target) {
    71          for (Map.Entry<String, String> option 
                         /* 
    P/P                   *  Method: void doConfigSubstitutions(StringBuilder)
                          * 
                          *  Preconditions:
                          *    (soft) target != null
                          * 
                          *  Presumptions:
                          *    com.dmdirc.config.ConfigManager:getOptions(...)@72 != null
                          *    com.dmdirc.config.IdentityManager:getGlobalConfig(...)@72 != null
                          *    java.util.Iterator:next(...)@72 != null
                          *    java.util.Map:entrySet(...)@72 != null
                          * 
                          *  Test Vectors:
                          *    java.util.Iterator:hasNext(...)@72: {0}, {1}
                          */
    72                  : IdentityManager.getGlobalConfig().getOptions("actions").entrySet()) {
    73              doReplacement(target, "$" + option.getKey(), option.getValue());
    74          }
    75      }
    76      
    77      /**
    78       * Retrieves a list of substitutions derived from argument and component
    79       * combinations, along with a corresponding friendly name for them.
    80       * Note: does not include initial $.
    81       *
    82       * @return A map of component substitution names and their descriptions
    83       */
    84      public Map<String, String> getComponentSubstitutions() {
                 /* 
    P/P           *  Method: Map getComponentSubstitutions()
                  * 
                  *  Preconditions:
                  *    this.type != null
                  *    (soft) this.type.type != null
                  * 
                  *  Presumptions:
                  *    arr$.length@88 <= 232-1
                  *    getArgNames(...).length@91 >= 1
                  *    arr$.length@88 <= getArgNames(...).length@91
                  *    getArgNames(...)@91 != null
                  *    getArgTypes(...)@88 != null
                  *    ...
                  * 
                  *  Postconditions:
                  *    return_value == &amp;new HashMap(getComponentSubstitutions#1)
                  *    new HashMap(getComponentSubstitutions#1) num objects == 1
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@89: {0}, {1}
                  */
    85          final Map<String, String> res = new HashMap<String, String>();
    86          
    87          int i = 0;
    88          for (Class myClass : type.getType().getArgTypes()) {
    89              for (ActionComponent comp : ActionManager.getCompatibleComponents(myClass)) {
    90                  final String key = "{" + i + "." + comp.toString() + "}";
    91                  final String desc = type.getType().getArgNames()[i] + "'s " + comp.getName();
    92                  
    93                  res.put(key, desc);
    94              }
    95              
    96              i++;
    97          }
    98          
    99          return res;
   100      }
   101      
   102      /**
   103       * Substitutes in component-style substitutions.
   104       *
   105       * @param target The stringbuilder to be changed
   106       * @param args The arguments passed for this action type
   107       */
   108      private void doComponentSubstitutions(final StringBuilder target, final Object ... args) {
                 /* 
    P/P           *  Method: void doComponentSubstitutions(StringBuilder, Object[])
                  * 
                  *  Preconditions:
                  *    this.type != null
                  *    (soft) args != null
                  *    (soft) init'ed(args[...])
                  *    (soft) target != null
                  *    (soft) this.type.type != null
                  * 
                  *  Presumptions:
                  *    arr$.length@110 <= 232-1
                  *    arr$.length@110 <= args.length
                  *    getArgTypes(...)@110 != null
                  *    java.util.Iterator:next(...)@112 != null
                  * 
                  *  Test Vectors:
                  *    args[...]: Addr_Set{null}, Inverse{null}
                  *    get(...)@114: Addr_Set{null}, Inverse{null}
                  *    java.util.Iterator:hasNext(...)@112: {0}, {1}
                  */
   109          int i = 0;
   110          for (Class myClass : type.getType().getArgTypes()) {
   111              if (args[i] != null) {
   112                  for (ActionComponent comp : ActionManager.getCompatibleComponents(myClass)) {
   113                      final String needle = "${" + i + "." + comp.toString() + "}";
   114                      final Object replacement = comp.get(args[i]);
   115  
   116                      if (replacement != null) {
   117                          doReplacement(target, needle, replacement.toString());
   118                      }
   119                  }
   120              }
   121              
   122              i++;
   123          }
   124      }
   125      
   126      /**
   127       * Retrieves a list of server substitutions, if this action type supports
   128       * them.
   129       * Note: does not include initial $.
   130       *
   131       * @return A map of server substitution names and their descriptions.
   132       */
   133      public Map<String, String> getServerSubstitutions() {
                 /* 
    P/P           *  Method: Map getServerSubstitutions()
                  * 
                  *  Preconditions:
                  *    this.type != null
                  *    (soft) this.type.type != null
                  * 
                  *  Presumptions:
                  *    getCompatibleComponents(...)@137 init'ed
                  *    java.util.Iterator:next(...)@137 != null
                  * 
                  *  Postconditions:
                  *    return_value == &amp;new HashMap(getServerSubstitutions#1)
                  *    new HashMap(getServerSubstitutions#1) num objects == 1
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@137: {0}, {1}
                  */
   134          final Map<String, String> res = new HashMap<String, String>();
   135          
   136          if (hasFrameContainer()) {
   137              for (ActionComponent comp : ActionManager.getCompatibleComponents(Server.class)) {
   138                  final String key = "{" + comp.toString() + "}";
   139                  final String desc = "The connection's " + comp.getName();
   140                  
   141                  res.put(key, desc);
   142              }
   143          }
   144          
   145          return res;
   146      }
   147      
   148      /**
   149       * Substitutes in server substitutions.
   150       *
   151       * @param target The stringbuilder to be changed
   152       * @param args The arguments passed for this action type
   153       */
   154      private void doServerSubstitutions(final StringBuilder target, final Object ... args) {
                 /* 
    P/P           *  Method: void doServerSubstitutions(StringBuilder, Object[])
                  * 
                  *  Preconditions:
                  *    args != null
                  *    (soft) init'ed(args[0])
                  *    (soft) target != null
                  * 
                  *  Presumptions:
                  *    getCompatibleComponents(...)@164 init'ed
                  *    java.util.Iterator:next(...)@164 != null
                  *    server.myState.state@156 != null
                  *    server.myState@156 != null
                  * 
                  *  Test Vectors:
                  *    args.length: {0}, {1..+Inf}
                  *    args[0]: Addr_Set{null}, Inverse{null}
                  *    com.dmdirc.ServerState:equals(...)@160: {1}, {0}
                  *    get(...)@166: Addr_Set{null}, Inverse{null}
                  *    getServer(...)@156: Addr_Set{null}, Inverse{null}
                  */
   155          if (args.length > 0 && args[0] instanceof FrameContainer) {
   156              final Server server = ((FrameContainer) args[0]).getServer();
   157          
   158              if (server != null) {
   159                  synchronized (server.getState()) {
   160                      if (!server.getState().equals(ServerState.CONNECTED)) {
   161                          return;
   162                      }
   163                      
   164                      for (ActionComponent comp : ActionManager.getCompatibleComponents(Server.class)) {
   165                          final String key = "${" + comp.toString() + "}";
   166                          final Object res = comp.get(((FrameContainer) args[0]).getServer());
   167  
   168                          if (res != null) {
   169                              doReplacement(target, key, res.toString());
   170                          }
   171                      }
   172                  }
   173              }
   174          }
   175      }
   176      
   177      /**
   178       * Returns true if this action type's first argument is a frame container,
   179       * or descendent of one.
   180       *
   181       * @return True if this action type's first arg extends or is a FrameContainer
   182       */
   183      private boolean hasFrameContainer() {
                 /* 
    P/P           *  Method: bool hasFrameContainer()
                  * 
                  *  Preconditions:
                  *    this.type != null
                  *    (soft) this.type.type != null
                  * 
                  *  Presumptions:
                  *    getArgTypes(...).length@187 >= 1
                  *    getArgTypes(...)@186 != null
                  *    getArgTypes(...)@187 != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  * 
                  *  Test Vectors:
                  *    getArgTypes(...).length@186: {0}, {1..+Inf}
                  */
   184          Class target = null;
   185          
   186          if (type.getType().getArgTypes().length > 0) {
   187              target = type.getType().getArgTypes()[0];
   188              
   189              while (target != null && target != FrameContainer.class) {
   190                  target = target.getSuperclass();
   191              }
   192          }
   193          
   194          return target == FrameContainer.class;
   195      }
   196      
   197      /**
   198       * Determines whether or not word substitutions will work for this action
   199       * type. Word substitutions take the form $1, $1-5, $6-, etc.
   200       *
   201       * @return True if word substitutions are supported, false otherwise.
   202       */
   203      public boolean usesWordSubstitutions() {
                 /* 
    P/P           *  Method: bool usesWordSubstitutions()
                  * 
                  *  Preconditions:
                  *    this.type != null
                  *    (soft) this.type.type != null
                  * 
                  *  Presumptions:
                  *    getArgTypes(...).length@204 >= 3
                  *    getArgTypes(...)@204 != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   204          return type.getType().getArgTypes().length > 2 && type.getType().getArgTypes()[2] == String[].class;
   205      }
   206      
   207      /**
   208       * Substitutes in word substitutions.
   209       *
   210       * @param target The stringbuilder to be changed
   211       * @param args The arguments passed for this action type
   212       */
   213      private void doWordSubstitutions(final StringBuilder target, final Object ... args) {
                 /* 
    P/P           *  Method: void doWordSubstitutions(StringBuilder, Object[])
                  * 
                  *  Preconditions:
                  *    args != null
                  *    (soft) init'ed(args[1])
                  *    (soft) args[1].length in {1..232-1}
                  *    (soft) init'ed(args[2])
                  *    (soft) args[2].length in {1..232-1}
                  *    (soft) target != null
                  * 
                  *  Test Vectors:
                  *    args.length: {0,1}, {2}, {3..+Inf}
                  *    java.lang.StringBuffer:length(...)@231: {-231..0}, {1..232-1}
                  */
   214          if (args.length > 1) {
   215              String[] words = null;
   216              
   217              if (args.length > 2 && args[2] instanceof String[]) {
   218                  words = (String[]) args[2];
   219              } else if (args.length > 2 && args[2] instanceof String) {
   220                  words = ((String) args[2]).split(" ");
   221              } else if (args[1] instanceof String[]) {
   222                  words = (String[]) args[1];
   223              } else if (args[1] instanceof String) {
   224                  words = ((String) args[1]).split(" ");
   225              } else {
   226                  return;
   227              }
   228              
   229              final StringBuffer compound = new StringBuffer();
   230              for (int i = words.length - 1; i >= 0; i--) {
   231                  if (compound.length() > 0) {
   232                      compound.insert(0, ' ');
   233                  }
   234                  compound.insert(0, words[i]);
   235                  
   236                  doReplacement(target, "$" + (i + 1) + "-", compound.toString());
   237                  doReplacement(target, "$" + (i + 1), words[i]);
   238              }
   239          }
   240      }
   241      
   242      /**
   243       * Performs all applicable substitutions on the specified string, with the
   244       * specified arguments.
   245       *
   246       * @param target The string to be altered
   247       * @param args The arguments for the action type
   248       * @return The substituted string
   249       */
   250      public String doSubstitution(final String target, final Object ... args) {
                 /* 
    P/P           *  Method: String doSubstitution(String, Object[])
                  * 
                  *  Preconditions:
                  *    args != null
                  *    this.type != null
                  *    (soft) init'ed(args[0])
                  *    (soft) init'ed(args[1])
                  *    (soft) args[1].length in {1..232-1}
                  *    (soft) init'ed(args[2])
                  *    (soft) args[2].length in {1..232-1}
                  *    (soft) init'ed(args[...])
                  *    (soft) this.type.type != null
                  * 
                  *  Postconditions:
                  *    java.lang.StringBuilder:toString(...)._tainted == target._tainted
                  *    init'ed(java.lang.StringBuilder:toString(...)._tainted)
                  *    return_value == &amp;java.lang.StringBuilder:toString(...)
                  */
   251          final StringBuilder res = new StringBuilder(target);
   252          
   253          doConfigSubstitutions(res);
   254          doServerSubstitutions(res, args);
   255          doComponentSubstitutions(res, args);
   256          doWordSubstitutions(res, args);
   257          
   258          return res.toString();
   259      }
   260      
   261      /**
   262       * Replaces all occurances of needle in haystack with replacement.
   263       *
   264       * @param haystack The stringbuilder that is to be modified
   265       * @param needle The search string
   266       * @param replacement The string to be substituted in
   267       */
   268      private void doReplacement(final StringBuilder haystack, final String needle,
   269              final String replacement) {
                 /* 
    P/P           *  Method: void doReplacement(StringBuilder, String, String)
                  * 
                  *  Preconditions:
                  *    haystack != null
                  *    (soft) needle != null
                  * 
                  *  Presumptions:
                  *    java.lang.StringBuilder:indexOf(...)@273 + java.lang.String:length(...)@276 in {-231..232-1}
                  * 
                  *  Test Vectors:
                  *    java.lang.StringBuilder:indexOf(...)@273: {-1}, {-231..-2, 0..232-1}
                  */
   270          int i = -1;
   271          
   272          do {
   273              i = haystack.indexOf(needle);
   274              
   275              if (i != -1) {
   276                  haystack.replace(i, i + needle.length(), replacement);
   277              }
   278          } while (i != -1);
   279      }
   280      
   281  }








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