Save This Page
Home » jakarta-jmeter-2.3.4_src » org.apache.jmeter.engine.util » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *   http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    *
   17    */
   18   
   19   /*
   20    * Created on Jul 25, 2003
   21    */
   22   package org.apache.jmeter.engine.util;
   23   
   24   import java.io.IOException;
   25   import java.io.StringReader;
   26   import java.util.LinkedList;
   27   
   28   import org.apache.jmeter.engine.StandardJMeterEngine;
   29   import org.apache.jmeter.functions.Function;
   30   import org.apache.jmeter.functions.InvalidVariableException;
   31   import org.apache.jmeter.testelement.TestListener;
   32   import org.apache.jorphan.logging.LoggingManager;
   33   import org.apache.log.Logger;
   34   
   35   /**
   36    * Parses function / variable references of the form
   37    * ${functionName[([var[,var...]])]}
   38    * and
   39    * ${variableName}
   40    */
   41   class FunctionParser {
   42       private static final Logger log = LoggingManager.getLoggerForClass();
   43   
   44       /**
   45        * Compile a general string into a list of elements for a CompoundVariable.
   46        *
   47        * Calls {@link #makeFunction(StringReader)} if it detects an unescaped "${".
   48        *
   49        * Removes escapes from '$', ',' and '\'.
   50        * 
   51        * @param value string containing the function / variable references (if any)
   52        *
   53        * @return list of strings or Objects representing functions
   54        */
   55       LinkedList compileString(String value) throws InvalidVariableException {
   56           StringReader reader = new StringReader(value);
   57           LinkedList result = new LinkedList();
   58           StringBuffer buffer = new StringBuffer();
   59           char previous = ' '; // TODO - why use space?
   60           char[] current = new char[1];
   61           try {
   62               while (reader.read(current) == 1) {
   63                   if (current[0] == '\\') { // Handle escapes
   64                       previous = current[0];
   65                       if (reader.read(current) == 0) {
   66                           break;
   67                       }
   68                       // Keep the '\' unless it is one of the escapable chars '$' ',' or '\'
   69                       // N.B. This method is used to parse function parameters, so must treat ',' as special
   70                       if (current[0] != '$' && current[0] != ',' && current[0] != '\\') {
   71                           buffer.append(previous); // i.e. '\\'
   72                       }
   73                       previous = ' ';
   74                       buffer.append(current[0]);
   75                       continue;
   76                   } else if (current[0] == '{' && previous == '$') {// found "${"
   77                       buffer.deleteCharAt(buffer.length() - 1);
   78                       if (buffer.length() > 0) {// save leading text
   79                           result.add(buffer.toString());
   80                           buffer.setLength(0);
   81                       }
   82                       result.add(makeFunction(reader));
   83                       previous = ' ';
   84                   } else {
   85                       buffer.append(current[0]);
   86                       previous = current[0];
   87                   }
   88               }
   89               if (buffer.length() > 0) {
   90                   result.add(buffer.toString());
   91               }
   92           } catch (IOException e) {
   93               log.error("Error parsing function: " + value, e);
   94               result.clear();
   95               result.add(value);
   96           }
   97           if (result.size() == 0) {
   98               result.add("");
   99           }
  100           return result;
  101       }
  102   
  103       /**
  104        * Compile a string into a function or SimpleVariable.
  105        *
  106        * Called by {@link #compileString(String)} when that has detected "${".
  107        *
  108        * Calls {@link CompoundVariable#getNamedFunction(String)} if it detects:
  109        * '(' - start of parameter list
  110        * '}' - end of function call
  111        *
  112        * @param reader points to input after the "${"
  113        * @return the function or variable object (or a String)
  114        */
  115       Object makeFunction(StringReader reader) throws InvalidVariableException {
  116           char[] current = new char[1];
  117           char previous = ' '; // TODO - why use space?
  118           StringBuffer buffer = new StringBuffer();
  119           Object function;
  120           try {
  121               while (reader.read(current) == 1) {
  122                   if (current[0] == '\\') {
  123                       if (reader.read(current) == 0) {
  124                           break;
  125                       }
  126                       previous = ' ';
  127                       buffer.append(current[0]);
  128                       continue;
  129                   } else if (current[0] == '(' && previous != ' ') {
  130                       String funcName = buffer.toString();
  131                       function = CompoundVariable.getNamedFunction(funcName);
  132                       if (function instanceof Function) {
  133                           ((Function) function).setParameters(parseParams(reader));
  134                           if (reader.read(current) == 0 || current[0] != '}') {
  135                               reader.reset();// set to start of string
  136                               char []cb = new char[100];
  137                               reader.read(cb);// return deliberately ignored
  138                               throw new InvalidVariableException
  139                               ("Expected } after "+funcName+" function call in "+new String(cb));
  140                           }
  141                           if (function instanceof TestListener) {
  142                               StandardJMeterEngine.register((TestListener) function);
  143                           }
  144                           return function;
  145                       } else { // Function does not exist, so treat as per missing variable
  146                           buffer.append(current[0]);
  147                       }
  148                       continue;
  149                   } else if (current[0] == '}') {// variable, or function with no parameter list
  150                       function = CompoundVariable.getNamedFunction(buffer.toString());
  151                       if (function instanceof Function){// ensure that setParameters() is called.
  152                           ((Function) function).setParameters(new LinkedList());
  153                       }
  154                       buffer.setLength(0);
  155                       return function;
  156                   } else {
  157                       buffer.append(current[0]);
  158                       previous = current[0];
  159                   }
  160               }
  161           } catch (IOException e) {
  162               log.error("Error parsing function: " + buffer.toString(), e);
  163               return null;
  164           }
  165           log.warn("Probably an invalid function string: " + buffer.toString());
  166           return buffer.toString();
  167       }
  168   
  169       /**
  170        * Compile a String into a list of parameters, each made into a
  171        * CompoundVariable.
  172        * 
  173        * Parses strings of the following form:
  174        * <ul>
  175        * <li>text)</li>
  176        * <li>text,text)</li>
  177        * <li></li>
  178        * </ul>
  179        * @param reader a StringReader pointing to the current input location, just after "("
  180        */
  181       LinkedList parseParams(StringReader reader) throws InvalidVariableException {
  182           LinkedList result = new LinkedList();
  183           StringBuffer buffer = new StringBuffer();
  184           char[] current = new char[1];
  185           char previous = ' ';
  186           int functionRecursion = 0;
  187           int parenRecursion = 0;
  188           try {
  189               while (reader.read(current) == 1) {
  190                   if (current[0] == '\\') { // Process escaped characters
  191                       buffer.append(current[0]); // Store the \
  192                       if (reader.read(current) == 0) {
  193                           break; // end of buffer
  194                       }
  195                       previous = ' ';
  196                       buffer.append(current[0]); // store the following character
  197                       continue;
  198                   } else if (current[0] == ',' && functionRecursion == 0) {
  199                       CompoundVariable param = new CompoundVariable();
  200                       param.setParameters(buffer.toString());
  201                       buffer.setLength(0);
  202                       result.add(param);
  203                   } else if (current[0] == ')' && functionRecursion == 0 && parenRecursion == 0) {
  204                       // Detect functionName() so this does not generate empty string as the parameter
  205                       if (buffer.length() == 0 && result.isEmpty()){
  206                           return result;
  207                       }
  208                       // Normal exit occurs here
  209                       CompoundVariable param = new CompoundVariable();
  210                       param.setParameters(buffer.toString());
  211                       buffer.setLength(0);
  212                       result.add(param);
  213                       return result;
  214                   } else if (current[0] == '{' && previous == '$') {
  215                       buffer.append(current[0]);
  216                       previous = current[0];
  217                       functionRecursion++;
  218                   } else if (current[0] == '}' && functionRecursion > 0) {
  219                       buffer.append(current[0]);
  220                       previous = current[0];
  221                       functionRecursion--;
  222                   } else if (current[0] == ')' && functionRecursion == 0 && parenRecursion > 0) {
  223                       buffer.append(current[0]);
  224                       previous = current[0];
  225                       parenRecursion--;
  226                   } else if (current[0] == '(' && functionRecursion == 0) {
  227                       buffer.append(current[0]);
  228                       previous = current[0];
  229                       parenRecursion++;
  230                   } else {
  231                       buffer.append(current[0]);
  232                       previous = current[0];
  233                   }
  234               }
  235           } catch (IOException e) {// Should not happen with StringReader
  236               log.error("Error parsing function: " + buffer.toString(), e);
  237           }
  238           // Dropped out, i.e. did not find closing ')'
  239           log.warn("Probably an invalid function string: " + buffer.toString());
  240           CompoundVariable var = new CompoundVariable();
  241           var.setParameters(buffer.toString());
  242           result.add(var);
  243           return result;
  244       }
  245   }

Save This Page
Home » jakarta-jmeter-2.3.4_src » org.apache.jmeter.engine.util » [javadoc | source]