mstover1    2002/07/12 20:17:49

  Modified:    docs     running.html
               docs/usermanual glossary.html index.html
               src_1/org/apache/jmeter/protocol/all/modifier
                        CompoundFunction.java Function.java
                        RegexFunction.java
               src_1/org/apache/jmeter/threads TestCompiler.java
               xdocs/usermanual glossary.xml index.xml
  Added:       docs/usermanual functions.html
               src_1/org/apache/jmeter/protocol/all/modifier
                        AbstractFunction.java
               xdocs/usermanual functions.xml
  Log:
  New Function implementations plus a quick draft of documentation for functions
  
  Revision  Changes    Path
  1.46      +0 -0      jakarta-jmeter/docs/running.html
  
  Index: running.html
  ===================================================================
  RCS file: /home/cvs/jakarta-jmeter/docs/running.html,v
  retrieving revision 1.45
  retrieving revision 1.46
  diff -u -r1.45 -r1.46
  
  
  
  1.11      +1 -1      jakarta-jmeter/docs/usermanual/glossary.html
  
  Index: glossary.html
  ===================================================================
  RCS file: /home/cvs/jakarta-jmeter/docs/usermanual/glossary.html,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- glossary.html     7 Mar 2002 23:03:12 -0000       1.10
  +++ glossary.html     13 Jul 2002 03:17:48 -0000      1.11
  @@ -68,7 +68,7 @@
                                                                                       
                                                                                  
<table border="0" cellspacing="0" cellpadding="2" width="100%">
                <tr><td bgcolor="#525D76">
                  <font color="#ffffff" face="arial,helvetica,sanserif">
  -                      <a name="glossary"><strong>14. Glossary</strong></a>
  +                      <a name="glossary"><strong>15. Glossary</strong></a>
                  </font>
                </td></tr>
                <tr><td>
  
  
  
  1.24      +8 -1      jakarta-jmeter/docs/usermanual/index.html
  
  Index: index.html
  ===================================================================
  RCS file: /home/cvs/jakarta-jmeter/docs/usermanual/index.html,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- index.html        26 Jun 2002 00:59:49 -0000      1.23
  +++ index.html        13 Jul 2002 03:17:48 -0000      1.24
  @@ -645,8 +645,15 @@
                                                                        
     
                                                                                       
         <li     >
  +                                                                                    
         <a       href="functions.html">
  +                                                             14. Functions
  +                                             </a>
  +                                                     </li>
  +                                                                     
  +  
  +                                                                                    
         <li     >
                                                                                       
         <a       href="glossary.html">
  -                                                             14. Glossary
  +                                                             15. Glossary
                                                </a>
                                                        </li>
                                                                        
  
  
  
  1.1                  jakarta-jmeter/docs/usermanual/functions.html
  
  Index: functions.html
  ===================================================================
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd";>
  
  <!-- Content Stylesheet for Site -->
  
         
  <!-- start the processing -->
         <!-- ====================================================================== 
-->
         <!-- Main Page Section -->
         <!-- ====================================================================== 
-->
         <html>
                  <head>
                                <meta http-equiv="Content-Type" content="text/html; 
charset=iso-8859-1"/>
  
                                                                
                                <title>JMeter - User's Manual: Introduction</title>
                  </head>
  
                  <body bgcolor="#ffffff" text="#000000" link="#525D76">
                                <table border="0" cellspacing="0">
                                         <!-- TOP IMAGE -->
                                         <tr>
                                                  <td colspan="2">
  <a href="http://jakarta.apache.org";><img 
src="http://jakarta.apache.org/images/jakarta-logo.gif"; align="left" border="0"/></a>
  </td>
                                         </tr>
                                </table>
                                <table border="0" width="100%" cellspacing="4">
                                         <tr><td colspan="2">
                                                  <hr noshade="" size="1"/>
                                         </td></tr>
  
                                         <tr>
                                                  <!-- LEFT SIDE NAVIGATION -->
                                                  <td width="20%" valign="top" 
nowrap="true">
                                                                          
<p><strong>About</strong></p>
                  <ul>
                                                <li>     <a 
href="../index.html">Overview</a>
  </li>
                                                <li>     <a 
href="http://jakarta.apache.org/builds/jakarta-jmeter/";>Download</a>
  </li>
                                                <li>     <a 
href="../changes.html">Changes</a>
  </li>
                                                <li>     <a 
href="http://nagoya.apache.org/bugzilla/buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&email1=&emailtype1=substring&emailassigned_to1=1&email2=&emailtype2=substring&emailreporter2=1&bugidtype=include&bug_id=&changedin=&votes=&chfieldfrom=&chfieldto=Now&chfieldvalue=&product=JMeter&short_desc=&short_desc_type=substring&long_desc=&long_desc_type=substring&bug_file_loc=&bug_file_loc_type=substring&keywords=&keywords_type=anywords&field0-0-0=noop&type0-0-0=noop&value0-0-0=&cmdtype=doit&order=Reuse+same+sort+as+last+time";>Known
 Bugs</a>
  </li>
                                                <li>     <a 
href="../license.html">License</a>
  </li>
                                                <li>     <a 
href="../todo.html">TODO</a>
  </li>
                                  </ul>
                          <p><strong>Documentation</strong></p>
                  <ul>
                                                <li>     <a 
href="../usermanual/index.html">User Manual</a>
  </li>
                                                <li>     <a 
href="../extending/index.html">Developer Manual</a>
  </li>
                                  </ul>
                          <p><strong>Community</strong></p>
                  <ul>
                                                <li>     <a 
href="http://jakarta.apache.org/site/getinvolved.html";>Get Involved</a>
  </li>
                                                <li>     <a 
href="http://jakarta.apache.org/site/mail.html";>Mailing Lists</a>
  </li>
                                                <li>     <a 
href="http://jakarta.apache.org/site/cvsindex.html";>CVS Repositories</a>
  </li>
                                  </ul>
                                                          </td>
                                                  <td width="80%" align="left" 
valign="top">
                                                                                       
                                                                                  
<table border="0" cellspacing="0" cellpadding="2" width="100%">
                <tr><td bgcolor="#525D76">
                  <font color="#ffffff" face="arial,helvetica,sanserif">
                         <a name="functions"><strong>14. Functions</strong></a>
                  </font>
                </td></tr>
                <tr><td>
                  <blockquote>
                                                                                       
                                 <p      >
                                                                
  JMeter functions are special values that can populate fields of any Sampler or other 
configuration
  element in a test tree.  A function looks like this:
                                                </p>
                                                                                       
                                                                         <p      >
                                                                                       
         <code   >
                                                                
${__functionName(var1,var2,var3)}
                                                </code>
                                                        </p>
                                                                                       
                                                                         <p      >
                                                                Where "__functionName" 
matches the name of an existing built-in or user-defined function.
                                                                                       
         <br     >
                                                </br>
                                                                        
  Parentheses surround the parameters sent to the function.  The actual parameters 
vary from function 
  to function.  Functions that require no parameters can leave off the parentheses.  
The function itself
  is wrapped in ${}.
                                                </p>
                                                                                       
                                                                          <table 
border="0" cellspacing="0" cellpadding="2" width="100%">
                <tr><td bgcolor="#828DA6">
                  <font color="#ffffff" face="arial,helvetica,sanserif">
                         <a name="what_can_do"><strong>14.1 What can functions 
do</strong></a>
                  </font>
                </td></tr>
                <tr><td>
                  <blockquote>
                                                                                       
                                 <p      >
                                                                There are two kinds of 
functions: user-defined static values, and built-in functions.
                                                                                       
         <br     >
                                                </br>
                                                                        
  User-defined static values allows the user to define variables to be replaced with 
their static value when
  a test tree is compiled and submitted to be run.  This replacement happens once at 
the beginning of the test
  run.  This could be used to replace the DOMAIN field of all HTTP requests, for 
example - making it a simple 
  matter to change a test to target a different server with the same test.
  
                                                </p>
                                                                                       
                                                                         <p      >
                                                                This type of 
replacement is possible without functions, but was less convenient and less intuitive.
  It required users to create default config elements that would fill in blank values 
of Samplers.  User-defined
  functions allows one to replace only part of any given value, not just filling in 
blank values.
                                                </p>
                                                                                       
                                                                         <p      >
                                                                
  With built-in functions users can compute new values at run-time based on previous 
response data, which
  thread the function is in, the time, and many other sources.  These values are 
generated fresh for every
  request throughout the course of the test. 
                                                </p>
                                                                          </blockquote>
                </td></tr>
                <tr><td><br/></td></tr>
         </table>
                                                                                       
                                                                          <table 
border="0" cellspacing="0" cellpadding="2" width="100%">
                <tr><td bgcolor="#828DA6">
                  <font color="#ffffff" face="arial,helvetica,sanserif">
                         <a name="where"><strong>14.2 Where can functions be 
used?</strong></a>
                  </font>
                </td></tr>
                <tr><td>
                  <blockquote>
                                                                                       
                                 <p      >
                                                                A user-defined 
function can be written into any field of any test component.  Some fields do not 
allow random strings 
  because they are expecting numbers, and thus will not accept a function.  However, 
most fields will allow
  functions.
                                                </p>
                                                                                       
                                                                         <p      >
                                                                Built-in functions can 
be written into any field of non-controller test components. This includes
  Samplers, Timers, Listeners, Modifiers, Assertions, and Config Elements.
                                                </p>
                                                                          </blockquote>
                </td></tr>
                <tr><td><br/></td></tr>
         </table>
                                                                                       
                                                                          <table 
border="0" cellspacing="0" cellpadding="2" width="100%">
                <tr><td bgcolor="#828DA6">
                  <font color="#ffffff" face="arial,helvetica,sanserif">
                         <a name="how"><strong>14.3 Writing the function 
string</strong></a>
                  </font>
                </td></tr>
                <tr><td>
                  <blockquote>
                                                                                       
                                 <p      >
                                                                User-defined functions 
take the form: 
                                                                                       
         <code   >
                                                                ${varName}
                                                </code>
                                                                        .  In the 
TestPlan tree element, a two-column table
  of user-defined values is kept, matching up variable names with static values.  
Referencing the
  variable in a test element is done by bracketing the variable name with '${' and '}'.
                                                </p>
                                                                                       
                                                                         <p      >
                                                                Built-in functions are 
written in the same manner, but by convention, the names of built-in
  parameters begin with "__" to avoid conflict with user value names
                                                                                       
         <sup    >
                                                                *
                                                </sup>
                                                                        .  Some 
functions take arguments to
  configure them, and these go in parentheses, comma-delimited.  If the function takes 
no arguments, the parentheses can
  be left out.  A further complication for argument values that themselves contain 
commas is that the value
  should be encoded the way HTTP parameters are encoded.  JMeter provides a tool to 
help you construct
  function calls for various built-in functions, which you can then copy-paste.  If 
your argument values
  do not contain commas, encoding is not required.
                                                </p>
                                                                                       
                                                                         <p><table 
border="1" bgcolor="#bbbb00" width="50%" cellspacing="0" cellpadding="2">
                <tr><td>                                                               
                 <sup    >
                                                                *
                                                </sup>
                                                                        If you define 
a user-defined static variable with the same name as a built-in function, your static
  variable will override the built-in function.
                        </td></tr>
        </table></p>
                                                                          </blockquote>
                </td></tr>
                <tr><td><br/></td></tr>
         </table>
                                                                          </blockquote>
                  </p>
                </td></tr>
                <tr><td><br/></td></tr>
         </table>
                                                                                       
           </td>
                                         </tr>
  
                                         <!-- FOOTER -->
                                         <tr><td colspan="2">
                                                  <hr noshade="" size="1"/>
                                         </td></tr>
                                         <tr><td colspan="2">
                                                  <div align="center"><font 
color="#525D76" size="-1"><em>
                                                  Copyright &#169; 1999-2001, Apache 
Software Foundation
                                                  </em></font></div>
                                         </td></tr>
                                </table>
                  </body>
         </html>
  <!-- end the processing -->
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  1.2       +32 -5     
jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/CompoundFunction.java
  
  Index: CompoundFunction.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/CompoundFunction.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- CompoundFunction.java     12 Jul 2002 02:00:46 -0000      1.1
  +++ CompoundFunction.java     13 Jul 2002 03:17:48 -0000      1.2
  @@ -1,5 +1,6 @@
   package org.apache.jmeter.protocol.all.modifier;
   
  +import java.net.URLEncoder;
   import java.util.HashMap;
   import java.util.Iterator;
   import java.util.LinkedList;
  @@ -11,11 +12,8 @@
   import org.apache.jmeter.samplers.Sampler;
   import org.apache.jmeter.util.ClassFinder;
   import org.apache.oro.text.perl.Perl5Util;
  -import org.apache.oro.text.regex.Pattern;
   import org.apache.oro.text.regex.PatternCompiler;
  -import org.apache.oro.text.regex.PatternMatcher;
   import org.apache.oro.text.regex.Perl5Compiler;
  -import org.apache.oro.text.regex.Perl5Matcher;
   
   /**
    * @author mstover
  @@ -66,7 +64,28 @@
         * @see Function#execute(SampleResult)
         */
        public String execute(SampleResult previousResult,Sampler currentSampler) {
  -             return null;
  +             if(compiledComponents == null || compiledComponents.size() == 0)
  +             {
  +                     return "";
  +             }
  +             StringBuffer results = new StringBuffer();
  +             Iterator iter = compiledComponents.iterator();
  +             while(iter.hasNext())
  +             {
  +                     Object item = iter.next();
  +                     if(item instanceof Function)
  +                     {
  +                             try {
  +                                     
results.append(((Function)item).execute(previousResult,currentSampler));
  +                             } catch(InvalidVariableException e) {
  +                             }
  +                     }
  +                     else
  +                     {
  +                             results.append(item);
  +                     }
  +             }
  +             return results.toString();
        }
        
        public CompoundFunction getFunction()
  @@ -249,17 +268,20 @@
                        assertTrue(function.hasFunction());
                        assertTrue(!function.hasStatics());
                        assertEquals("hello 
world",((Function)function.compiledComponents.getFirst()).execute(result,null));
  +                     assertEquals("hello world",function.execute(result,null));
                }
                
                public void testParseExample2() throws Exception
                {
  -                     function.setParameters("It should 
say:${${__regexFunction(<html>(.*)</html>,$1$)}}");
  +                     function.setParameters("It should 
say:${${__regexFunction("+URLEncoder.encode("<html>(.*)</html>")+",$1$)}}");
                        assertEquals(3,function.compiledComponents.size());
                        assertEquals("It should 
say:${",function.compiledComponents.getFirst().toString());
                        assertTrue(function.hasFunction());
                        assertTrue(!function.hasStatics());
                        assertEquals("hello 
world",((Function)function.compiledComponents.get(1)).execute(result,null));
                        
assertEquals("}",function.compiledComponents.get(2).toString());
  +                     assertEquals("It should say:${hello 
world}",function.execute(result,null));
  +                     assertEquals("It should 
say:${<html>(.*)</html>,$1$}",function.execute(null,null));
                }
                
                public void testParseExample3() throws Exception
  @@ -270,6 +292,9 @@
                        assertTrue(!function.hasStatics());
                        assertEquals("hello 
world",((Function)function.compiledComponents.get(0)).execute(result,null));
                        
assertEquals("hellorld",((Function)function.compiledComponents.get(1)).execute(result,null));
  +                     assertEquals("hello 
worldhellorld",function.execute(result,null));
  +                     
assertEquals("<html>(.*)</html>,$1$<html>(.*o)(.*o)(.*)</html>,$1$$3$",
  +                                     function.execute(null,null));
                }
                
                public void testParseExample4() throws Exception
  @@ -280,6 +305,8 @@
                        assertTrue(!function.hasStatics());
                        assertEquals("${non-existing function}",
                                        
function.compiledComponents.getFirst().toString());
  +                     assertEquals("${non-existing 
function}",function.execute(result,null));
  +                     assertEquals("${non-existing 
function}",function.execute(null,null));
                }
                
                public void testParseExample5() throws Exception
  
  
  
  1.2       +2 -1      
jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/Function.java
  
  Index: Function.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/Function.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Function.java     12 Jul 2002 02:00:46 -0000      1.1
  +++ Function.java     13 Jul 2002 03:17:48 -0000      1.2
  @@ -11,7 +11,8 @@
    */
   public interface Function {
        
  -     public String execute(SampleResult previousResult,Sampler currentSampler);
  +     public String execute(SampleResult previousResult,Sampler currentSampler)
  +                     throws InvalidVariableException;
        
        public void setParameters(String parameters) throws InvalidVariableException;
        
  
  
  
  1.2       +26 -38    
jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/RegexFunction.java
  
  Index: RegexFunction.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/RegexFunction.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- RegexFunction.java        12 Jul 2002 02:00:46 -0000      1.1
  +++ RegexFunction.java        13 Jul 2002 03:17:48 -0000      1.2
  @@ -3,6 +3,7 @@
   import java.net.URLDecoder;
   import java.net.URLEncoder;
   import java.util.ArrayList;
  +import java.util.Collection;
   import java.util.Iterator;
   import java.util.LinkedList;
   import java.util.List;
  @@ -28,13 +29,13 @@
    * To change this generated comment edit the template variable "typecomment":
    * Window>Preferences>Java>Templates.
    */
  -public class RegexFunction implements Function {
  +public class RegexFunction extends AbstractFunction {
        
        public static final String ALL = "ALL";
        public static final String RAND = "RAND";
        public static final String KEY = "__regexFunction";     
        
  -     Random rand = new Random();
  +     private static Random rand = new Random();
        Pattern searchPattern;
        Object[] template;
        String valueIndex,defaultValue,between;
  @@ -56,6 +57,10 @@
         */
        public String execute(SampleResult previousResult,Sampler currentSampler) 
        {
  +             if(previousResult == null || previousResult.getResponseData() == null)
  +             {
  +                     return defaultValue;
  +             }
                List collectAllMatches = new ArrayList();
                try {
                        PatternMatcher matcher = new Perl5Matcher();
  @@ -131,52 +136,35 @@
        
        public void setParameters(String params) throws InvalidVariableException
        {
  -             StringTokenizer tk = new StringTokenizer(params,",",true);
  -             valueIndex = "1";
  -             between = "";
  -             defaultValue = "";
  -             String temp = null;
  -             try {
  -                     searchPattern = 
compiler.compile(URLDecoder.decode(tk.nextToken()));
  -             } catch(MalformedPatternException e) {
  -                     throw new InvalidVariableException(e.getMessage());
  -             }
  -             tk.nextToken();
  -             generateTemplate(URLDecoder.decode(tk.nextToken()));
  -             if(tk.hasMoreTokens())
  +             try
                {
  -                     tk.nextToken();
  -                     temp = tk.nextToken();
  -                     if(!temp.equals(","))
  +                     Iterator tk = parseArguments(params).iterator();
  +                     valueIndex = "1";
  +                     between = "";
  +                     defaultValue = URLDecoder.decode(params);
  +                     searchPattern = compiler.compile((String)tk.next());           
         
  +                     generateTemplate((String)tk.next());
  +                     if(tk.hasNext())
                        {
  -                             valueIndex = temp;
  +                             valueIndex = (String)tk.next();
                        }
  -             }
  -             if(tk.hasMoreTokens())
  -             {
  -                     if(!temp.equals(","))
  +                     if(tk.hasNext())
                        {
  -                             tk.nextToken();
  +                             between = (String)tk.next();
                        }
  -                     temp = tk.nextToken();
  -                     if(!temp.equals(","))
  +                     if(tk.hasNext())
                        {
  -                             between = URLDecoder.decode(temp);
  +                             defaultValue = (String)tk.next();
                        }
  +             } catch(MalformedPatternException e) {
  +                             e.printStackTrace();
  +                             throw new InvalidVariableException("Bad regex 
pattern");
                }
  -             if(tk.hasMoreTokens())
  +             catch(Exception e)
                {
  -                     if(!temp.equals(","))
  -                     {
  -                             tk.nextToken();
  -                     }
  -                     temp = tk.nextToken();
  -                     if(!temp.equals(","))
  -                     {
  -                             defaultValue = URLDecoder.decode(temp);
  -                     }
  +                     throw new InvalidVariableException(e.getMessage());
                }
  -     }       
  +     }
        
        private void generateTemplate(String rawTemplate)
        {
  
  
  
  1.1                  
jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/AbstractFunction.java
  
  Index: AbstractFunction.java
  ===================================================================
  package org.apache.jmeter.protocol.all.modifier;
  
  import java.net.URLDecoder;
  import java.util.Collection;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.StringTokenizer;
  
  import org.apache.jmeter.samplers.SampleResult;
  import org.apache.jmeter.samplers.Sampler;
  
  /**
   * @author mstover
   *
   * To change this generated comment edit the template variable "typecomment":
   * Window>Preferences>Java>Templates.
   */
  public abstract class AbstractFunction implements Function {
  
        /**
         * @see Function#execute(SampleResult, Sampler)
         */
        abstract public String execute(SampleResult previousResult, Sampler 
currentSampler) 
                        throws InvalidVariableException;
  
        /**
         * @see Function#setParameters(String)
         */
        abstract public void setParameters(String parameters) throws 
InvalidVariableException;
  
        /**
         * @see Function#getReferenceKey()
         */
        abstract public String getReferenceKey();       
        
        /**
         * Provides a convenient way to parse the given argument string into a 
collection of
         * individual arguments.  Takes care of splitting the string based on commas, 
generates
         * blank strings for values between adjacent commas, and decodes the string 
using URLDecoder.
         */
        protected Collection parseArguments(String params)
        {
                StringTokenizer tk = new StringTokenizer(params,",",true);
                List arguments = new LinkedList();
                String previous = "";
                while(tk.hasMoreTokens())
                {
                        String arg = tk.nextToken();
                        if(arg.equals(",") && previous.equals(","))
                        {
                                arguments.add("");
                        }
                        else if(!arg.equals(","))
                        {
                                arguments.add(URLDecoder.decode(arg));
                        }
                        previous = arg;
                }
                return arguments;
        }
  
  }
  
  
  
  1.6       +165 -9    jakarta-jmeter/src_1/org/apache/jmeter/threads/TestCompiler.java
  
  Index: TestCompiler.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-jmeter/src_1/org/apache/jmeter/threads/TestCompiler.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- TestCompiler.java 21 May 2002 03:36:44 -0000      1.5
  +++ TestCompiler.java 13 Jul 2002 03:17:48 -0000      1.6
  @@ -1,12 +1,21 @@
   package org.apache.jmeter.threads;
  -import java.util.*;
  -import org.apache.jmeter.config.Arguments;
  +import java.util.Collection;
  +import java.util.HashMap;
  +import java.util.HashSet;
  +import java.util.Iterator;
  +import java.util.LinkedList;
  +import java.util.List;
  +import java.util.Map;
  +import java.util.Set;
  +
   import org.apache.jmeter.assertions.Assertion;
  -import org.apache.jmeter.timers.Timer;
  +import org.apache.jmeter.config.Arguments;
   import org.apache.jmeter.config.ConfigTestElement;
   import org.apache.jmeter.config.Modifier;
   import org.apache.jmeter.config.ResponseBasedModifier;
   import org.apache.jmeter.control.GenericController;
  +import org.apache.jmeter.protocol.all.modifier.Function;
  +import org.apache.jmeter.protocol.all.modifier.InvalidVariableException;
   import org.apache.jmeter.protocol.http.sampler.HTTPSampler;
   import org.apache.jmeter.samplers.SampleEvent;
   import org.apache.jmeter.samplers.SampleListener;
  @@ -14,6 +23,7 @@
   import org.apache.jmeter.samplers.Sampler;
   import org.apache.jmeter.testelement.PerSampleClonable;
   import org.apache.jmeter.testelement.TestElement;
  +import org.apache.jmeter.timers.Timer;
   import org.apache.jmeter.util.ListedHashTree;
   import org.apache.jmeter.util.ListedHashTreeVisitor;
   
  @@ -37,8 +47,10 @@
   {
        LinkedList stack = new LinkedList();
        Map samplerConfigs = new HashMap();
  +     Set objectsWithFunctions = new HashSet();
        ListedHashTree testTree;
        SampleResult previousResult;
  +     Sampler currentSampler;
        private static Set pairing = new HashSet();
   
        /****************************************
  @@ -91,12 +103,17 @@
         ***************************************/
        public SamplePackage configureSampler(Sampler sampler)
        {
  +             currentSampler = sampler;
                SamplePackage ret = new SamplePackage();
                Sampler clonedSampler = sampler;
                if(sampler instanceof PerSampleClonable)
                {
                        clonedSampler = (Sampler)((PerSampleClonable)sampler).clone();
                }
  +             if(objectsWithFunctions.contains(sampler))
  +             {
  +                     replaceValues(clonedSampler);
  +             }
                ret.setSampler(clonedSampler);
                ret.addSampleListener(this);
                Iterator iter = ((List)samplerConfigs.get(sampler)).iterator();
  @@ -154,9 +171,18 @@
                        Iterator iter = testTree.list(stack.subList(0, i)).iterator();
                        while(iter.hasNext())
                        {
  -                             configs.add(iter.next());
  +                             TestElement item = (TestElement)iter.next();
  +                             if(hasFunctions(item))
  +                             {
  +                                     objectsWithFunctions.add(item);
  +                             }
  +                             configs.add(item);
                        }
                }
  +             if(hasFunctions(sam))
  +             {
  +                     objectsWithFunctions.add(sam);
  +             }
                samplerConfigs.put(sam, configs);
        }
   
  @@ -259,6 +285,7 @@
   
        private void layerElement(SamplePackage ret,TestElement config, Sampler 
clonedSampler)
        {
  +             boolean replace = objectsWithFunctions.contains(config);
                if(config instanceof PerSampleClonable)
                {
                        config = (TestElement)((PerSampleClonable)config).clone();
  @@ -283,6 +310,135 @@
                {
                        ret.addTimer((Timer)config);
                }
  +             if(replace && config instanceof PerSampleClonable)
  +             {
  +                     replaceValues(config);
  +             }
  +             else if(replace)
  +             {
  +                     config = (TestElement)config.clone();
  +                     replaceValues(config);
  +             }
                clonedSampler.addTestElement(config);
        }
  +     
  +     private boolean hasFunctions(TestElement el)
  +     {
  +             Iterator iter = el.getPropertyNames().iterator();
  +             while(iter.hasNext())
  +             {
  +                     String propName = (String)iter.next();
  +                     Object propValue = el.getProperty(propName);
  +                     if(propValue instanceof Function)
  +                     {
  +                             return true;
  +                     }
  +                     else if(propValue instanceof TestElement)
  +                     {
  +                             if(hasFunctions((TestElement)propValue))
  +                             {
  +                                     return true;
  +                             }
  +                     }
  +                     else if(propValue instanceof Collection)
  +                     {
  +                             if(hasFunctions((Collection)propValue))
  +                             {
  +                                     return true;
  +                             }
  +                     }
  +             }
  +             return false;
  +     }
  +     
  +     private boolean hasFunctions(Collection values)
  +     {
  +             Iterator iter = values.iterator();
  +             while(iter.hasNext())
  +             {
  +                     Object val = iter.next();
  +                     if(val instanceof TestElement)
  +                     {
  +                             if(hasFunctions((TestElement)val))
  +                             {
  +                                     return true;
  +                             }
  +                     }
  +                     else if(val instanceof Function)
  +                     {
  +                             return true;
  +                     }
  +                     else if(val instanceof Collection)
  +                     {
  +                             if(hasFunctions((Collection)val))
  +                             {
  +                                     return true;
  +                             }
  +                     }
  +             }
  +             return false;
  +     }       
  +     
  +     private void replaceValues(TestElement el)
  +     {
  +             Iterator iter = el.getPropertyNames().iterator();
  +             while(iter.hasNext())
  +             {
  +                     String propName = (String)iter.next();
  +                     Object propValue = el.getProperty(propName);
  +                     if(propValue instanceof Function)
  +                     {
  +                             try
  +                             {
  +                                     
el.setProperty(propName,((Function)propValue).execute(previousResult,currentSampler));
  +                             }
  +                             catch(InvalidVariableException e)
  +                             {}
  +                     }
  +                     else if(propValue instanceof TestElement)
  +                     {
  +                             replaceValues((TestElement)propValue);
  +                     }
  +                     else if(propValue instanceof Collection)
  +                     {
  +                             
el.setProperty(propName,replaceValues((Collection)propValue));
  +                     }
  +             }
  +     }
  +     
  +     private Collection replaceValues(Collection values)
  +     {
  +             Collection newColl = null;
  +             try {
  +                     newColl = (Collection)values.getClass().newInstance();
  +             } catch(Exception e) {
  +                     e.printStackTrace();
  +                     return values;
  +             } 
  +             Iterator iter = values.iterator();
  +             while(iter.hasNext())
  +             {
  +                     Object val = iter.next();
  +                     if(val instanceof TestElement)
  +                     {
  +                             replaceValues((TestElement)val);
  +                     }
  +                     else if(val instanceof Function)
  +                     {
  +                             try
  +                             {
  +                                     val = 
((Function)val).execute(previousResult,currentSampler);
  +                             }
  +                             catch(InvalidVariableException e)
  +                             {}
  +                     }
  +                     else if(val instanceof Collection)
  +                     {
  +                             val = replaceValues((Collection)val);
  +                     }
  +                     newColl.add(val);
  +             }
  +             return newColl;
  +     }
  +
   }
  
  
  
  1.4       +1 -1      jakarta-jmeter/xdocs/usermanual/glossary.xml
  
  Index: glossary.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-jmeter/xdocs/usermanual/glossary.xml,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- glossary.xml      24 Feb 2002 18:17:18 -0000      1.3
  +++ glossary.xml      13 Jul 2002 03:17:49 -0000      1.4
  @@ -7,7 +7,7 @@
   
   <body>
   
  -<section name="14. Glossary" anchor="glossary">
  +<section name="15. Glossary" anchor="glossary">
   </section>
   
   </body>
  
  
  
  1.23      +2 -1      jakarta-jmeter/xdocs/usermanual/index.xml
  
  Index: index.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-jmeter/xdocs/usermanual/index.xml,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- index.xml 26 Jun 2002 00:59:49 -0000      1.22
  +++ index.xml 13 Jul 2002 03:17:49 -0000      1.23
  @@ -106,7 +106,8 @@
     <li><a href="boss.html">12. Help! My boss wants me to load test our web 
app!</a></li>
   
     <li><a href="component_reference.html">13. Component Reference</a></li>
  -  <li><a href="glossary.html">14. Glossary</a></li>
  +  <li><a href="functions.html">14. Functions</a></li>
  +  <li><a href="glossary.html">15. Glossary</a></li>
   </ul>
   
   </section>
  
  
  
  1.1                  jakarta-jmeter/xdocs/usermanual/functions.xml
  
  Index: functions.xml
  ===================================================================
  <?xml version="1.0"?>
  <document>
  
  <properties>
    <title>User's Manual: Introduction</title>
  </properties>
  
  <body>
  
  <section name="14. Functions" anchor="functions">
  <p>
  JMeter functions are special values that can populate fields of any Sampler or other 
configuration
  element in a test tree.  A function looks like this:</p>
  
  <p><code>${__functionName(var1,var2,var3)}</code></p>
  
  <p>Where "__functionName" matches the name of an existing built-in or user-defined 
function.<br/>
  Parentheses surround the parameters sent to the function.  The actual parameters 
vary from function 
  to function.  Functions that require no parameters can leave off the parentheses.  
The function itself
  is wrapped in ${}.</p>
  
  
  <subsection name="14.1 What can functions do" anchor="what_can_do">
  <p>There are two kinds of functions: user-defined static values, and built-in 
functions.<br/>
  User-defined static values allows the user to define variables to be replaced with 
their static value when
  a test tree is compiled and submitted to be run.  This replacement happens once at 
the beginning of the test
  run.  This could be used to replace the DOMAIN field of all HTTP requests, for 
example - making it a simple 
  matter to change a test to target a different server with the same test.
  </p>
  <p>This type of replacement is possible without functions, but was less convenient 
and less intuitive.
  It required users to create default config elements that would fill in blank values 
of Samplers.  User-defined
  functions allows one to replace only part of any given value, not just filling in 
blank values.</p>
  <p>
  With built-in functions users can compute new values at run-time based on previous 
response data, which
  thread the function is in, the time, and many other sources.  These values are 
generated fresh for every
  request throughout the course of the test. </p>
  </subsection>
  
  <subsection name="14.2 Where can functions be used?" anchor="where">
  <p>A user-defined function can be written into any field of any test component.  
Some fields do not allow random strings 
  because they are expecting numbers, and thus will not accept a function.  However, 
most fields will allow
  functions.</p>
  <p>Built-in functions can be written into any field of non-controller test 
components. This includes
  Samplers, Timers, Listeners, Modifiers, Assertions, and Config Elements.</p>
  </subsection>
  
  <subsection name="14.3 Writing the function string" anchor="how">
  <p>User-defined functions take the form: <code>${varName}</code>.  In the TestPlan 
tree element, a two-column table
  of user-defined values is kept, matching up variable names with static values.  
Referencing the
  variable in a test element is done by bracketing the variable name with '${' and 
'}'.</p>
  <p>Built-in functions are written in the same manner, but by convention, the names 
of built-in
  parameters begin with "__" to avoid conflict with user value names<sup>*</sup>.  
Some functions take arguments to
  configure them, and these go in parentheses, comma-delimited.  If the function takes 
no arguments, the parentheses can
  be left out.  A further complication for argument values that themselves contain 
commas is that the value
  should be encoded the way HTTP parameters are encoded.  JMeter provides a tool to 
help you construct
  function calls for various built-in functions, which you can then copy-paste.  If 
your argument values
  do not contain commas, encoding is not required.</p>
  <note><sup>*</sup>If you define a user-defined static variable with the same name as 
a built-in function, your static
  variable will override the built-in function.</note>
  </subsection>
  
  </section>
  
  </body>
  </document>
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to