mstover1 2003/03/18 05:41:14
Modified: src/components/org/apache/jmeter/assertions
ResponseAssertion.java
src/components/org/apache/jmeter/assertions/gui
AssertionGui.java
src/core/org/apache/jmeter/gui/tree JMeterTreeModel.java
src/core/org/apache/jmeter/testelement WorkBench.java
src/protocol/java/org/apache/jmeter/protocol/java/config/gui
JavaConfigGui.java
src/protocol/java/org/apache/jmeter/protocol/java/sampler
JavaSampler.java JavaSamplerClient.java
src/protocol/java/org/apache/jmeter/protocol/java/test
SleepTest.java
xdocs/stylesheets project.xml
Added: src/protocol/java/org/apache/jmeter/protocol/java/sampler
AbstractJavaSamplerClient.java
JavaSamplerContext.java
Log:
WorkBench doesn't need to extend TestPlan (which was confusing too)
patch from Jeremy Arnold changing interface for JavaSampler
Fixing ResponseAssertion's GUI
Revision Changes Path
1.7 +9 -2
jakarta-jmeter/src/components/org/apache/jmeter/assertions/ResponseAssertion.java
Index: ResponseAssertion.java
===================================================================
RCS file:
/home/cvs/jakarta-jmeter/src/components/org/apache/jmeter/assertions/ResponseAssertion.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- ResponseAssertion.java 17 Mar 2003 09:24:48 -0000 1.6
+++ ResponseAssertion.java 18 Mar 2003 13:41:12 -0000 1.7
@@ -118,6 +118,13 @@
setTestType(type);
getTestStrings().add(string);
}
+
+ public void clear()
+ {
+ super.clear();
+ setProperty(TEST_STRINGS, new ArrayList());
+ }
+
/************************************************************
* !ToDo (Method description)
*
1.5 +8 -7
jakarta-jmeter/src/components/org/apache/jmeter/assertions/gui/AssertionGui.java
Index: AssertionGui.java
===================================================================
RCS file:
/home/cvs/jakarta-jmeter/src/components/org/apache/jmeter/assertions/gui/AssertionGui.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- AssertionGui.java 28 Feb 2003 14:21:44 -0000 1.4
+++ AssertionGui.java 18 Mar 2003 13:41:12 -0000 1.5
@@ -136,6 +136,7 @@
if (el instanceof ResponseAssertion)
{
ResponseAssertion ra = (ResponseAssertion) el;
+ ra.clearTestStrings();
String[] testStrings = tableModel.getData().getColumn(COL_NAME);
for (int i = 0; i < testStrings.length; i++)
{
1.10 +6 -6
jakarta-jmeter/src/core/org/apache/jmeter/gui/tree/JMeterTreeModel.java
Index: JMeterTreeModel.java
===================================================================
RCS file:
/home/cvs/jakarta-jmeter/src/core/org/apache/jmeter/gui/tree/JMeterTreeModel.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- JMeterTreeModel.java 28 Feb 2003 14:21:47 -0000 1.9
+++ JMeterTreeModel.java 18 Mar 2003 13:41:13 -0000 1.10
@@ -90,11 +90,11 @@
}
/****************************************
- * !ToDoo (Method description)
- *
- [EMAIL PROTECTED] type !ToDo (Parameter description)
- [EMAIL PROTECTED] !ToDo (Return description)
- ***************************************/
+ * Returns a list of tree nodes that
+ * hold objects of the given class
+ * type. If none are found, an empty
+ * list is returned
+ *************************************/
public List getNodesOfType(Class type)
{
List nodeList = new LinkedList();
1.3 +1 -1
jakarta-jmeter/src/core/org/apache/jmeter/testelement/WorkBench.java
Index: WorkBench.java
===================================================================
RCS file:
/home/cvs/jakarta-jmeter/src/core/org/apache/jmeter/testelement/WorkBench.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- WorkBench.java 5 Feb 2003 05:12:09 -0000 1.2
+++ WorkBench.java 18 Mar 2003 13:41:13 -0000 1.3
@@ -10,7 +10,7 @@
[EMAIL PROTECTED] 1.0
***************************************/
-public class WorkBench extends TestPlan implements Serializable
+public class WorkBench extends AbstractTestElement implements Serializable
{
private static List itemsCanAdd = null;
private boolean isRootNode;
1.7 +59 -8
jakarta-jmeter/src/protocol/java/org/apache/jmeter/protocol/java/config/gui/JavaConfigGui.java
Index: JavaConfigGui.java
===================================================================
RCS file:
/home/cvs/jakarta-jmeter/src/protocol/java/org/apache/jmeter/protocol/java/config/gui/JavaConfigGui.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- JavaConfigGui.java 28 Feb 2003 14:21:51 -0000 1.6
+++ JavaConfigGui.java 18 Mar 2003 13:41:13 -0000 1.7
@@ -2,7 +2,7 @@
* ====================================================================
* The Apache Software License, Version 1.1
*
- * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * Copyright (c) 2002,2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,7 +55,11 @@
package org.apache.jmeter.protocol.java.config.gui;
import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.JComboBox;
@@ -64,6 +68,7 @@
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
+import org.apache.jmeter.config.Argument;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.config.gui.AbstractConfigGui;
import org.apache.jmeter.config.gui.ArgumentsPanel;
@@ -72,10 +77,10 @@
import org.apache.jmeter.protocol.java.sampler.JavaSamplerClient;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.util.JMeterUtils;
-import org.apache.log.Hierarchy;
-import org.apache.log.Logger;
import org.apache.jorphan.gui.layout.VerticalLayout;
import org.apache.jorphan.reflect.ClassFinder;
+import org.apache.log.Hierarchy;
+import org.apache.log.Logger;
/**
@@ -85,9 +90,9 @@
* @version $Revision$
*/
-public class JavaConfigGui extends AbstractConfigGui
-{
- transient private static Logger log =
Hierarchy.getDefaultHierarchy().getLoggerFor("jmeter.protocol.java");
+public class JavaConfigGui extends AbstractConfigGui implements ActionListener {
+ transient private static Logger log =
+ Hierarchy.getDefaultHierarchy().getLoggerFor("jmeter.protocol.java");
private static String CLASSNAMECOMBO = "classnamecombo";
private JComboBox classnameCombo;
@@ -169,13 +174,14 @@
// Remove the JavaConfig class from the list since it only
implements the interface for
// error conditions.
-
possibleClasses.remove("org.apache.jmeter.protocol.java.sampler.JavaSampler");
+
possibleClasses.remove("org.apache.jmeter.protocol.java.sampler.JavaSampler$ErrorSamplerClient");
} catch (Exception e) {
log.debug("Exception getting interfaces.",e);
}
classnameCombo = new JComboBox(possibleClasses.toArray());
+ classnameCombo.addActionListener(this);
classnameCombo.setName(CLASSNAMECOMBO);
classnameCombo.setEditable(false);
panel.add(classnameCombo);
@@ -183,6 +189,51 @@
return panel;
}
+
+ public void actionPerformed(ActionEvent evt) {
+ if (evt.getSource() == classnameCombo) {
+ String className = (String)classnameCombo.getSelectedItem();
+ try {
+ JavaSamplerClient client = (JavaSamplerClient)Class.forName(
+ className.trim(),
+ true,
+ Thread.currentThread().getContextClassLoader()
+ ).newInstance();
+
+ Arguments currArgs = new Arguments();
+ argsPanel.modifyTestElement(currArgs);
+ Map currArgsMap = currArgs.getArgumentsAsMap();
+
+ Arguments newArgs = new Arguments();
+ Arguments testParams = client.getDefaultParameters();
+ if (testParams != null) {
+ Iterator i = testParams.getArguments().iterator();
+ while (i.hasNext()) {
+ Argument arg = (Argument)i.next();
+ String name = arg.getName();
+ Object value = arg.getValue();
+
+ // If a user has set parameters in one test, and then
+ // selects a different test which supports the same
+ // parameters, those parameters should have the same
+ // values that they did in the original test.
+ if (currArgsMap.containsKey(name)) {
+ Object newVal = currArgsMap.get(name);
+ if (newVal != null &&
+ newVal.toString().length() > 0) {
+ value = newVal;
+ }
+ }
+ newArgs.addArgument(name, value);
+ }
+ }
+
+ argsPanel.configure(newArgs);
+ } catch (Exception e) {
+ log.error("Error getting argument list for " + className, e);
+ }
+ }
+ }
protected JPanel getParameterPanel()
{
1.7 +66 -89
jakarta-jmeter/src/protocol/java/org/apache/jmeter/protocol/java/sampler/JavaSampler.java
Index: JavaSampler.java
===================================================================
RCS file:
/home/cvs/jakarta-jmeter/src/protocol/java/org/apache/jmeter/protocol/java/sampler/JavaSampler.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- JavaSampler.java 15 Mar 2003 14:44:52 -0000 1.6
+++ JavaSampler.java 18 Mar 2003 13:41:13 -0000 1.7
@@ -55,12 +55,10 @@
package org.apache.jmeter.protocol.java.sampler;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
-import org.apache.jmeter.config.Argument;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.config.JavaConfig;
import org.apache.jmeter.samplers.AbstractSampler;
@@ -72,17 +70,19 @@
import org.apache.log.Hierarchy;
import org.apache.log.Logger;
-public class JavaSampler extends AbstractSampler implements JavaSamplerClient,
PerThreadClonable, TestListener
-{
- /**
- * Property key representing the classname of the JavaSamplerClient to use.
- */
- public final static String CLASSNAME = "classname";
+public class JavaSampler extends AbstractSampler
+ implements PerThreadClonable, TestListener {
/**
- * Property key representing the arguments for the JavaSamplerClient.
- */
+ * Property key representing the classname of the JavaSamplerClient to
+ * user.
+ */
+ public final static String CLASSNAME = "classname";
+
+ /**
+ * Property key representing the arguments for the JavaSamplerClient.
+ */
public final static String ARGUMENTS = "arguments";
/**
@@ -90,11 +90,19 @@
* the sample.
*/
transient private JavaSamplerClient javaClient = null;
+
+ /**
+ * The JavaSamplerContext instance used by this sampler to hold
+ * information related to the test run, such as the parameters
+ * specified for the sampler client.
+ */
+ transient private JavaSamplerContext context = null;
/**
* Logging
*/
- transient private static Logger log =
Hierarchy.getDefaultHierarchy().getLoggerFor("jmeter.protocol.java");
+ transient private static Logger log =
+ Hierarchy.getDefaultHierarchy().getLoggerFor("jmeter.protocol.java");
/**
* Set used to register all active JavaSamplers. This is used so that the
@@ -147,19 +155,19 @@
/**
* Releases Java Client.
*/
- public void releaseJavaClient()
- {
+ private void releaseJavaClient () {
if (javaClient != null)
{
- javaClient.teardownTest(createArgumentsHashMap(getArguments()));
+ javaClient.teardownTest(context);
}
javaClient = null;
+ context = null;
}
/**
- * Sets the Classname attribute of the JavaConfig object
+ * Sets the Classname attribute of the JavaConfig object
*
- [EMAIL PROTECTED] classname The new Classname value
+ * @param classname the new Classname value
*/
public void setClassname(String classname)
{
@@ -167,9 +175,9 @@
}
/**
- * Gets the Classname attribute of the JavaConfig object
+ * Gets the Classname attribute of the JavaConfig object
*
- [EMAIL PROTECTED] The Classname value
+ * @return the Classname value
*/
public String getClassname()
{
@@ -181,8 +189,9 @@
*
* The <code>sample()</code> method retrieves the reference to the
* Java client and calls its <code>runTest()</code> method.
- * @see Sampler#sample()
- * @see JavaSamplerClient#runTest()
+ *
+ * @see Sampler#sample(org.apache.jmeter.samplers.Entry)
+ * @see JavaSamplerClient#runTest(JavaSamplerContext)
*
* @return test SampleResult
*/
@@ -192,32 +201,10 @@
{
log.debug(whoAmI() + "Creating Java Client");
createJavaClient();
- javaClient.setupTest(createArgumentsHashMap(getArguments()));
+ javaClient.setupTest(context);
}
- return javaClient.runTest(createArgumentsHashMap(getArguments()));
- }
- /**
- * Convert the arguments parameter into a HashMap which can be passed
- * to the JavaSamplerClient. The "name" of each Argument
- * in args is added to the HashMap as a key, and the "value"
- * is the value associated with that key. The original Arguments are
- * not modified.
- *
- * @param args the Arguments to convert to a HashMap
- * @return a HashMap representation of the Arguments
- */
- public HashMap createArgumentsHashMap(Arguments args)
- {
- HashMap newArgs = new HashMap();
- Iterator iter = args.iterator();
- while (iter.hasNext())
- {
- Argument item = (Argument) iter.next();
- newArgs.put(item.getName(), item.getValue());
- }
-
- return newArgs;
+ return createJavaClient().runTest(context);
}
/**
@@ -230,24 +217,27 @@
*
* @return JavaSamplerClient reference.
*/
- public JavaSamplerClient createJavaClient()
- {
+ private JavaSamplerClient createJavaClient() {
if (javaClient == null)
{
try
{
- Class javaClass = Class.forName(getClassname().trim(), false,
Thread.currentThread().getContextClassLoader());
+ Class javaClass = Class.forName(getClassname().trim(),
+ false,
+ Thread.currentThread().getContextClassLoader());
javaClient = (JavaSamplerClient) javaClass.newInstance();
+ context = new JavaSamplerContext(getArguments());
- if (log.isDebugEnabled())
- {
- log.debug(whoAmI() + "\tCreated:\t" + getClassname() + "@" +
Integer.toHexString(javaClient.hashCode()));
+ if (log.isDebugEnabled()) {
+ log.debug(whoAmI() + "\tCreated:\t" + getClassname() +
+ "@" + Integer.toHexString(javaClient.hashCode()));
}
}
catch (Exception e)
{
- log.error(whoAmI() + "\tException creating: " + getClassname(), e);
- javaClient = this;
+ log.error(whoAmI() + "\tException creating: " +
+ getClassname(), e);
+ javaClient = new ErrorSamplerClient();
}
}
return javaClient;
@@ -261,46 +251,16 @@
*
* @return reference to JavaSamplerClient
*/
- public JavaSamplerClient retrieveJavaClient()
- {
+ private JavaSamplerClient retrieveJavaClient() {
return javaClient;
}
/**
- * Provide default setupTest() implementation for error conditions.
- * @see JavaSamplerClient#setupTest()
- */
- public void setupTest(HashMap arguments)
- {
- log.debug(whoAmI() + "\tsetupTest");
- }
-
- /**
- * Provide default teardownTest() implementation for error conditions.
- * @see JavaSamplerClient#teardownTest()
- */
- public void teardownTest(HashMap arguments)
- {
- log.debug(whoAmI() + "\tteardownTest");
- javaClient = null;
- }
-
- /**
- * Return SampleResult with data on error.
- * @see JavaSamplerClient#runTest()
+ * Generate a String identifier of this instance for debugging
+ * purposes.
+ *
+ * @return a String identifier for this sampler instance
*/
- public SampleResult runTest(HashMap arguments)
- {
- log.debug(whoAmI() + "\trunTest");
- Thread.yield();
- SampleResult results = new SampleResult();
- results.setTime(0);
- results.setSuccessful(false);
- results.setResponseData(new String("Class not found: " +
getClassname()).getBytes());
- results.setSampleLabel("ERROR: " + getClassname());
- return results;
- }
-
private String whoAmI()
{
StringBuffer sb = new StringBuffer();
@@ -323,8 +283,8 @@
}
/**
- * Method called at the end of the test. This is called only on one
- * instance of JavaSampler. This method will loop throuh all of the
+ * Method called at the end of the test. This is called only on one
+ * instance of JavaSampler. This method will loop through all of the
* other JavaSamplers which have been registered (automatically in the
* constructor) and notify them that the test has ended, allowing the
* JavaSamplerClients to cleanup.
@@ -349,4 +309,21 @@
testEnded();
}
+ class ErrorSamplerClient extends AbstractJavaSamplerClient {
+ /**
+ * Return SampleResult with data on error.
+ * @see JavaSamplerClient#runTest()
+ */
+ public SampleResult runTest(JavaSamplerContext context) {
+ log.debug(whoAmI() + "\trunTest");
+ Thread.yield();
+ SampleResult results = new SampleResult();
+ results.setTime(0);
+ results.setSuccessful(false);
+ results.setResponseData(new String("Class not found: " +
+ getClassname()).getBytes());
+ results.setSampleLabel("ERROR: " + getClassname());
+ return results;
+ }
+ }
}
1.2 +100 -30
jakarta-jmeter/src/protocol/java/org/apache/jmeter/protocol/java/sampler/JavaSamplerClient.java
Index: JavaSamplerClient.java
===================================================================
RCS file:
/home/cvs/jakarta-jmeter/src/protocol/java/org/apache/jmeter/protocol/java/sampler/JavaSamplerClient.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- JavaSamplerClient.java 11 Aug 2002 19:24:53 -0000 1.1
+++ JavaSamplerClient.java 18 Mar 2003 13:41:13 -0000 1.2
@@ -2,7 +2,7 @@
* ====================================================================
* The Apache Software License, Version 1.1
*
- * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * Copyright (c) 2002,2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,41 +54,111 @@
*/
package org.apache.jmeter.protocol.java.sampler;
-import java.util.HashMap;
-
+import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.samplers.SampleResult;
+
/**
- *<code>JavaSamplerClient</code> provides a standard
- * interface to execute external Java programs within JMeter.
+ * This interface defines the interactions between the JavaSampler
+ * and external Java programs which can be executed by JMeter. Any
+ * Java class which wants to be executed as a JMeter test must
+ * implement this interface (either directly or indirectly through
+ * AbstractJavaSamplerClient).
+ * <p>
+ * JMeter will create one instance of a JavaSamplerClient implementation
+ * for each user/thread in the test. Additional instances may be
+ * created for internal use by JMeter (for example, to find out
+ * what parameters are supported by the client).
+ * <p>
+ * When the test is started, setupTest() will be called on each
+ * thread's JavaSamplerClient instance to initialize the client.
+ * Then runTest() will be called for each iteration of the test.
+ * Finally, teardownTest() will be called to allow the client
+ * to do any necessary clean-up.
+ * <p>
+ * The JMeter JavaSampler GUI allows a list of parameters to be
+ * defined for the test. These are passed to the various test
+ * methods through the JavaSamplerContext. A list of default
+ * parameters can be defined through the getDefaultParameters()
+ * method. These parameters and any default values associated
+ * with them will be shown in the GUI. Users can add other
+ * parameters as well.
+ * <p>
+ * While it may be necessary to make changes to the JavaSamplerClient
+ * interface from time to time (therefore requiring changes to any
+ * implementations of this interface), we intend to make this abstract
+ * class provide reasonable implementations of any new methods so that
+ * subclasses do not necessarily need to be updated for new versions.
+ * Therefore, when creating a new JavaSamplerClient implementation,
+ * developers are encouraged to subclass this abstract class rather
+ * than implementing the JavaSamplerClient interface directly.
+ * Implementing JavaSamplerClient directly will continue to be
+ * supported for cases where extending this class is not possible
+ * (for example, when the client class is already a subclass of some
+ * other class).
+ *
+ * @see JavaSamplerContext
*
* @author Brad Kiewel
+ * @author Jeremy Arnold
* @version $Revision$
*/
public interface JavaSamplerClient {
-
- /**
- * Setup any resources need for each test run.
- */
-
- public void setupTest(HashMap arguments);
-
- /**
- * Perform any clean up at the end of a test run.
- */
-
- public void teardownTest(HashMap arguments);
-
- /**
- * Performs test for each iteration.
- *
- * The <code>runTest()</code> method performs one test interation
- * each time it is called. The method returns a SampleResult object.
- * The method should, has a minimum, place the response time in
- * the SampleResult object.
- *
- * @return SampleResult object with results of the test run.
- */
- public SampleResult runTest(HashMap arguments);
-}
\ No newline at end of file
+ /**
+ * Do any initialization required by this client. It is
+ * generally recommended to do any initialization such as
+ * getting parameter values in the setupTest method rather
+ * than the runTest method in order to add as little overhead
+ * as possible to the test.
+ *
+ * @param context the context to run with. This provides access
+ * to initialization parameters.
+ */
+ public void setupTest(JavaSamplerContext context);
+
+ /**
+ * Perform a single sample for each iteration. This method
+ * returns a <code>SampleResult</code> object.
+ * <code>SampleResult</code> has many fields which can be
+ * used. At a minimum, the test should use
+ * <code>SampleResult.setTime</code> to set the time that
+ * the test required to execute. It is also a good idea to
+ * set the sampleLabel and the successful flag.
+ *
+ * @see org.apache.jmeter.samplers.SampleResult.setTime(long)
+ * @see org.apache.jmeter.samplers.SampleResult.setSuccessful(boolean)
+ * @see org.apache.jmeter.samplers.SampleResult.setSampleLabel(java.lang.String)
+ *
+ * @param context the context to run with. This provides access
+ * to initialization parameters.
+ *
+ * @return a SampleResult giving the results of this
+ * sample.
+ */
+ public SampleResult runTest(JavaSamplerContext context);
+
+ /**
+ * Do any clean-up required by this test at the end of a test run.
+ *
+ * @param context the context to run with. This provides access
+ * to initialization parameters.
+ */
+ public void teardownTest(JavaSamplerContext context);
+
+ /**
+ * Provide a list of parameters which this test supports. Any
+ * parameter names and associated values returned by this method
+ * will appear in the GUI by default so the user doesn't have
+ * to remember the exact names. The user can add other parameters
+ * which are not listed here. If this method returns null then
+ * no parameters will be listed. If the value for some parameter
+ * is null then that parameter will be listed in the GUI with
+ * an empty value.
+ *
+ * @return a specification of the parameters used by this
+ * test which should be listed in the GUI, or null
+ * if no parameters should be listed.
+ */
+ public Arguments getDefaultParameters();
+}
1.1
jakarta-jmeter/src/protocol/java/org/apache/jmeter/protocol/java/sampler/AbstractJavaSamplerClient.java
Index: AbstractJavaSamplerClient.java
===================================================================
/*
* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache JMeter" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* "Apache JMeter", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.jmeter.protocol.java.sampler;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.log.Hierarchy;
import org.apache.log.Logger;
/**
* An abstract implementation of the JavaSamplerClient interface.
* This implementation provides default implementations of most
* of the methods in the interface, as well as some convenience
* methods, in order to simplify development of JavaSamplerClient
* implementations.
* <p>
* While it may be necessary to make changes to the JavaSamplerClient
* interface from time to time (therefore requiring changes to any
* implementations of this interface), we intend to make this abstract
* class provide reasonable implementations of any new methods so that
* subclasses do not necessarily need to be updated for new versions.
* Therefore, when creating a new JavaSamplerClient implementation,
* developers are encouraged to subclass this abstract class rather
* than implementing the JavaSamplerClient interface directly.
* Implementing JavaSamplerClient directly will continue to be
* supported for cases where extending this class is not possible
* (for example, when the client class is already a subclass of some
* other class).
* <p>
* The runTest() method of JavaSamplerClient does not have a default
* implementation here, so subclasses must define at least this method.
* It may be useful to override other methods as well.
*
* @see JavaSamplerClient#runTest(JavaSamplerContext)
*
* @author Jeremy Arnold
* @version $Revision: 1.1 $
*/
public abstract class AbstractJavaSamplerClient implements JavaSamplerClient {
/**
* The Logger to be used by the Java protocol. This can be used
* by subclasses through the getLogger() method.
*
* @see #getLogger()
*/
transient private static Logger log =
Hierarchy.getDefaultHierarchy().getLoggerFor("jmeter.protocol.java");
public void setupTest(JavaSamplerContext context) {
log.debug(getClass().getName() + ": setupTest");
}
public void teardownTest(JavaSamplerContext context) {
log.debug(getClass().getName() + ": teardownTest");
}
public Arguments getDefaultParameters() {
return null;
}
/**
* Get a Logger instance which can be used by subclasses to log
* information. This is the same Logger which is used by the base
* JavaSampler classes (jmeter.protocol.java).
*
* @return a Logger instance which can be used for logging
*/
protected Logger getLogger() {
return log;
}
}
1.1
jakarta-jmeter/src/protocol/java/org/apache/jmeter/protocol/java/sampler/JavaSamplerContext.java
Index: JavaSamplerContext.java
===================================================================
/*
* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache JMeter" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* "Apache JMeter", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.jmeter.protocol.java.sampler;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.jmeter.config.Argument;
import org.apache.jmeter.config.Arguments;
import org.apache.log.Hierarchy;
import org.apache.log.Logger;
/**
* JavaSamplerContext is used to provide context information to a
* JavaSamplerClient implementation. This currently consists of
* the initialization parameters which were specified in the GUI.
* Additional data may be accessible through JavaSamplerContext
* in the future.
*
* @author Jeremy Arnold
* @version $Revision: 1.1 $
*/
public class JavaSamplerContext {
/*
* Implementation notes:
*
* All of the methods in this class are currently read-only.
* If update methods are included in the future, they should
* be defined so that a single instance of JavaSamplerContext
* can be associated with each thread. Therefore, no
* synchronization should be needed. The same instance should
* be used for the call to setupTest, all calls to runTest,
* and the call to teardownTest.
*/
/**
* Logging.
*/
transient private static Logger log =
Hierarchy.getDefaultHierarchy().getLoggerFor("jmeter.protocol.java");
/**
* Map containing the initialization parameters for the
* JavaSamplerClient.
*/
private Map params = null;
/**
* Create a new JavaSampler with the specified initialization
* parameters.
*
* @param params the initialization parameters.
*/
public JavaSamplerContext (Arguments args) {
this.params = args.getArgumentsAsMap();
}
/**
* Determine whether or not a value has been specified for the
* parameter with this name.
*
* @param name the name of the parameter to test
* @return true if the parameter value has been specified,
* false otherwise.
*/
public boolean containsParameter (String name) {
return params.containsKey(name);
}
/**
* Get an iterator of the parameter names. Each entry in the
* Iterator is a String.
*
* @return an Iterator of Strings listing the names of the
* parameters which have been specified for this
* test.
*/
public Iterator getParameterNamesIterator() {
return params.keySet().iterator();
}
/**
* Get the value of a specific parameter as a String, or null
* if the value was not specified.
*
* @param name the name of the parameter whose value should
* be retrieved
* @return the value of the parameter, or null if the
* value was not specified
*/
public String getParameter (String name) {
return getParameter (name, null);
}
/**
* Get the value of a specified parameter as a String, or return
* the specified default value if the value was not specified.
*
* @param name the name of the parameter whose value
* should be retrieved
* @param defaultValue the default value to return if the
* value of this parameter was not
* specified
* @return the value of the parameter, or the
* default value if the parameter was
* not specified
*/
public String getParameter (String name, String defaultValue) {
if (params == null || !params.containsKey(name)) {
return defaultValue;
}
return (String)params.get(name);
}
/**
* Get the value of a specified parameter as an integer. An
* exception will be thrown if the parameter is not specified
* or if it is not an integer. The value may be specified in
* decimal, hexadecimal, or octal, as defined by
* Integer.decode().
*
* @param name the name of the parameter whose value
* should be retrieved
* @return the value of the parameter
*
* @throws NumberFormatException if the parameter is not
* specified or is not an integer
*
* @see java.lang.Integer#decode(java.lang.String)
*/
public int getIntParameter (String name) throws NumberFormatException {
if (params == null || !params.containsKey(name)) {
throw new NumberFormatException ("No value for parameter named
'" + name + "'.");
}
return Integer.decode((String)params.get(name)).intValue();
}
/**
* Get the value of a specified parameter as an integer, or
* return the specified default value if the value was not
* specified or is not an integer. A warning will be
* logged if the value is not an integer. The value may
* be specified in decimal, hexadecimal, or octal, as defined
* by Integer.decode().
*
* @param name the name of the parameter whose value
* should be retrieved
* @param defaultValue the default value to return if the
* value of this parameter was not
* specified
* @return the value of the parameter, or the
* default value if the parameter was
* not specified
*
* @see java.lang.Integer#decode(java.lang.String)
*/
public int getIntParameter (String name, int defaultValue) {
if (params == null || !params.containsKey(name)) {
return defaultValue;
}
try {
return Integer.decode((String)params.get(name)).intValue();
} catch (NumberFormatException e) {
log.warn ("Value for parameter '" + name + "' not an integer:
'" +
params.get(name) + "'. Using default: '" +
defaultValue + "'.", e);
return defaultValue;
}
}
/**
* Get the value of a specified parameter as a long. An
* exception will be thrown if the parameter is not specified
* or if it is not a long. The value may be specified in
* decimal, hexadecimal, or octal, as defined by
* Long.decode().
*
* @param name the name of the parameter whose value
* should be retrieved
* @return the value of the parameter
*
* @throws NumberFormatException if the parameter is not
* specified or is not a long
*
* @see java.lang.Long#decode(java.lang.String)
*/
public long getLongParameter (String name) throws NumberFormatException {
if (params == null || !params.containsKey(name)) {
throw new NumberFormatException ("No value for parameter named
'" + name + "'.");
}
return Long.decode((String)params.get(name)).longValue();
}
/**
* Get the value of a specified parameter as along, or
* return the specified default value if the value was not
* specified or is not a long. A warning will be
* logged if the value is not a long. The value may
* be specified in decimal, hexadecimal, or octal, as defined
* by Long.decode().
*
* @param name the name of the parameter whose value
* should be retrieved
* @param defaultValue the default value to return if the
* value of this parameter was not
* specified
* @return the value of the parameter, or the
* default value if the parameter was
* not specified
*
* @see java.lang.Long#decode(java.lang.String)
*/
public long getLongParameter (String name, long defaultValue) {
if (params == null || !params.containsKey(name)) {
return defaultValue;
}
try {
return Long.decode((String)params.get(name)).longValue();
} catch (NumberFormatException e) {
log.warn ("Value for parameter '" + name + "' not a long: '" +
params.get(name) + "'. Using default: '" +
defaultValue + "'.", e);
return defaultValue;
}
}
}
1.5 +176 -106
jakarta-jmeter/src/protocol/java/org/apache/jmeter/protocol/java/test/SleepTest.java
Index: SleepTest.java
===================================================================
RCS file:
/home/cvs/jakarta-jmeter/src/protocol/java/org/apache/jmeter/protocol/java/test/SleepTest.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- SleepTest.java 30 Aug 2002 14:43:21 -0000 1.4
+++ SleepTest.java 18 Mar 2003 13:41:13 -0000 1.5
@@ -2,7 +2,7 @@
* ====================================================================
* The Apache Software License, Version 1.1
*
- * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * Copyright (c) 2001,2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -56,123 +56,192 @@
package org.apache.jmeter.protocol.java.test;
import java.io.Serializable;
-import java.util.HashMap;
import java.util.Iterator;
-import java.util.Map.Entry;
-import org.apache.jmeter.protocol.java.sampler.JavaSamplerClient;
+import org.apache.jmeter.config.Arguments;
+import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
+import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;
-import org.apache.log.Hierarchy;
-import org.apache.log.Logger;
/**
* The <code>SleepTest</code> class is a simple example class for a
* JMeter Java protocol client. The class implements the
* <code>JavaSamplerClient</code> interface.
+ * <p>
+ * During each sample, this client will sleep for some amount of
+ * time. The amount of time to sleep is determined from the
+ * two parameters SleepTime and SleepMask using the formula:
+ * <pre>
+ * totalSleepTime = SleepTime + (System.currentTimeMillis() % SleepMask)
+ * </pre>
+ * Thus, the SleepMask provides a way to add a random component
+ * to the sleep time.
*/
-
-public class SleepTest implements JavaSamplerClient,Serializable {
- /** Define category for logging */
- transient private static Logger log =
Hierarchy.getDefaultHierarchy().getLoggerFor("jmeter.protocol.java");
- /** */
- private long sleepTime = 1000;
- /** */
- private long sleepMask = 0x3ff;
- /**
- * Default constructor for <code>SleepTest</code>.
- *
- * [EMAIL PROTECTED] org.apache.jmeter.protocol.java.config.JavaConfig
JavaConfig}
- * uses the default constructor to instantiate an instance of
- * the client class.
- */
+public class SleepTest extends AbstractJavaSamplerClient
+ implements Serializable {
+ /**
+ * The default value of the SleepTime parameter, in milliseconds.
+ */
+ public static final long DEFAULT_SLEEP_TIME = 1000;
+
+ /**
+ * The default value of the SleepMask parameter.
+ */
+ public static final long DEFAULT_SLEEP_MASK = 0x3ff;
+
+ /**
+ * The base number of milliseconds to sleep during each sample.
+ */
+ private long sleepTime;
+
+ /**
+ * A mask to be applied to the current time in order to add a
+ * random component to the sleep time.
+ */
+ private long sleepMask;
+
+ /**
+ * Default constructor for <code>SleepTest</code>.
+ *
+ * The Java Sampler uses the default constructor to instantiate
+ * an instance of the client class.
+ */
public SleepTest() {
- log.debug(whoAmI() + "\tConstruct");
+ getLogger().debug(whoAmI() + "\tConstruct");
}
- /**
- * @see JavaSamplerClient#setupTest()
- *
- * setupTest() provides a way to do any initialization that may be required.
- */
- public void setupTest(HashMap arguments) {
- log.debug(whoAmI() + "\tsetupTest()");
- Iterator argsIt = arguments.entrySet().iterator();
- while (argsIt.hasNext()) {
- Entry entry = (Entry)argsIt.next();
- log.debug(entry.getKey().toString() + "=" +
entry.getValue().toString());
- }
-
- if (arguments.containsKey("SleepTime")) {
- setSleepTime(arguments.get("SleepTime"));
- }
-
- if (arguments.containsKey("SleepMask")) {
- setSleepMask(arguments.get("SleepMask"));
- }
- }
-
- /**
- * @see JavaSamplerClient#teardownTest()
- *
- * teardownTest() provides a way to do any clean-up that may be required.
- */
- public void teardownTest(HashMap arguments) {
- log.debug(whoAmI() + "\tteardownTest()");
- Iterator argsIt = arguments.entrySet().iterator();
- while (argsIt.hasNext()) {
- Entry entry = (Entry)argsIt.next();
- log.debug(entry.getKey().toString() + "=" +
entry.getValue().toString());
- }
- }
-
- /**
- * @see JavaSamplerClient#runTest()
- *
- * runTest() is called for each sample. The method returns a
- * <code>SampleResult</code> object. The method must calculate
- * how long the sample took to execute.
- */
- public SampleResult runTest(HashMap arguments) {
-
+ /**
+ * Do any initialization required by this client. In this case,
+ * initialization consists of getting the values of the SleepTime
+ * and SleepMask parameters. It is generally recommended to do
+ * any initialization such as getting parameter values in the
+ * setupTest method rather than the runTest method in order to
+ * add as little overhead as possible to the test.
+ *
+ * @param context the context to run with. This provides access
+ * to initialization parameters.
+ */
+ public void setupTest(JavaSamplerContext context) {
+ getLogger().debug(whoAmI() + "\tsetupTest()");
+ listParameters(context);
+
+ sleepTime = context.getLongParameter("SleepTime", 1000);
+ sleepMask = context.getLongParameter("SleepMask", 0x3ff);
+ }
+
+ /**
+ * Perform a single sample. In this case, this method will
+ * simply sleep for some amount of time.
+ * <p>
+ * This method returns a <code>SampleResult</code> object.
+ * <code>SampleResult</code> has many fields which can be
+ * used. At a minimum, the test should use
+ * <code>SampleResult.setTime</code> to set the time that
+ * the test required to execute. It is also a good idea to
+ * set the sampleLabel and the successful flag.
+ *
+ * @see org.apache.jmeter.samplers.SampleResult.setTime(long)
+ * @see org.apache.jmeter.samplers.SampleResult.setSuccessful(boolean)
+ * @see org.apache.jmeter.samplers.SampleResult.setSampleLabel(java.lang.String)
+ *
+ * @param context the context to run with. This provides access
+ * to initialization parameters.
+ *
+ * @return a SampleResult giving the results of this
+ * sample.
+ */
+ public SampleResult runTest(JavaSamplerContext context) {
SampleResult results = new SampleResult();
+
try {
- //
- // Generate a random value using the current time.
- //
- long ct = System.currentTimeMillis();
- ct %= getSleepMask();
- //
// Record sample start time.
- //
long start = System.currentTimeMillis();
- //
+
+ // Generate a random value using the current time.
+ long ct = start % getSleepMask();
+
// Execute the sample. In this case sleep for the
// specified time.
- //
Thread.sleep(getSleepTime() + ct);
- //
+
// Record end time and populate the results.
- //
long end = System.currentTimeMillis();
+
results.setTime(end - start);
results.setSuccessful(true);
- results.setSampleLabel("Sleep Test: time = "+getSleepTime() +
ct);
+ results.setSampleLabel("Sleep Test: time = " +
+ (getSleepTime() + ct));
} catch (Exception e) {
+ getLogger().error("SleepTest: error during sample", e);
+ results.setSuccessful(false);
}
- if (log.isDebugEnabled()) {
- log.debug(whoAmI() + "\trunTest()" + "\tTime:\t" +
results.getTime());
- Iterator argsIt = arguments.entrySet().iterator();
- while (argsIt.hasNext()) {
- Entry entry = (Entry)argsIt.next();
- log.debug(entry.getKey().toString() + "=" +
entry.getValue().toString());
- }
- }
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug(whoAmI() + "\trunTest()" + "\tTime:\t" +
results.getTime());
+ listParameters(context);
+ }
return results;
+ }
+ /**
+ * Do any clean-up required by this test. In this case no
+ * clean-up is necessary, but some messages are logged for
+ * debugging purposes.
+ *
+ * @param context the context to run with. This provides access
+ * to initialization parameters.
+ */
+ public void teardownTest(JavaSamplerContext context) {
+ getLogger().debug(whoAmI() + "\tteardownTest()");
+ listParameters(context);
}
+ /**
+ * Provide a list of parameters which this test supports. Any
+ * parameter names and associated values returned by this method
+ * will appear in the GUI by default so the user doesn't have
+ * to remember the exact names. The user can add other parameters
+ * which are not listed here. If this method returns null then
+ * no parameters will be listed. If the value for some parameter
+ * is null then that parameter will be listed in the GUI with
+ * an empty value.
+ *
+ * @return a specification of the parameters used by this
+ * test which should be listed in the GUI, or null
+ * if no parameters should be listed.
+ */
+ public Arguments getDefaultParameters() {
+ Arguments params = new Arguments();
+ params.addArgument("SleepTime", String.valueOf(DEFAULT_SLEEP_TIME));
+ params.addArgument("SleepMask", "0x" +
+ (Long.toHexString(DEFAULT_SLEEP_MASK)).toUpperCase());
+ return params;
+ }
+
+ /**
+ * Dump a list of the parameters in this context to the debug
+ * log.
+ *
+ * @param context the context which contains the initialization
+ * parameters.
+ */
+ private void listParameters(JavaSamplerContext context) {
+ if (getLogger().isDebugEnabled()) {
+ Iterator argsIt = context.getParameterNamesIterator();
+ while (argsIt.hasNext()) {
+ String name = (String)argsIt.next();
+ getLogger().debug(name + "=" + context.getParameter(name));
+ }
+ }
+ }
+
+ /**
+ * Generate a String identifier of this test for debugging
+ * purposes.
+ *
+ * @return a String identifier for this test instance
+ */
private String whoAmI() {
StringBuffer sb = new StringBuffer();
sb.append(Thread.currentThread().toString());
@@ -181,22 +250,23 @@
return sb.toString();
}
- private long getSleepTime() {return sleepTime;}
- private long getSleepMask() {return sleepMask;}
- private void setSleepTime(Object arg) {
- try {
- sleepTime = Long.parseLong((String)arg);
- } catch (Exception e) {
- log.debug("Exception getting sleepTime:\t",e);
- sleepTime = 1000l;
- }
- }
- private void setSleepMask(Object arg) {
- try {
- sleepMask = Long.parseLong((String)arg);
- } catch (Exception e) {
- log.debug("Exception getting sleepMask:\t",e);
- sleepMask = 0x3ff;
- }
- }
-}
\ No newline at end of file
+ /**
+ * Get the value of the sleepTime field.
+ *
+ * @return the base number of milliseconds to sleep during
+ * each sample.
+ */
+ private long getSleepTime() {
+ return sleepTime;
+ }
+
+ /**
+ * Get the value of the sleepMask field.
+ *
+ * @return a mask to be applied to the current time in order
+ * to add a random component to the sleep time.
+ */
+ private long getSleepMask() {
+ return sleepMask;
+ }
+}
1.12 +3 -1 jakarta-jmeter/xdocs/stylesheets/project.xml
Index: project.xml
===================================================================
RCS file: /home/cvs/jakarta-jmeter/xdocs/stylesheets/project.xml,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- project.xml 1 Feb 2003 16:12:07 -0000 1.11
+++ project.xml 18 Mar 2003 13:41:14 -0000 1.12
@@ -14,13 +14,15 @@
<item name="Changes" href="/changes.html"/>
<item name="Known Bugs"
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"/>
<item name="License" href="/license.html"/>
- <item name="TODO" href="/todo.html"/>
<item name="Contributors"
href="/contributing.html"/>
</menu>
<menu name="Documentation">
<item name="User Manual" href="/usermanual/index.html"/>
<item name="Developer Manual" href="/extending/index.html"/>
<item name="JMeter Wiki"
href="http://nagoya.apache.org/wiki/apachewiki.cgi?JMeterProjectPages"/>
+ </menu>
+ <menu name="JMeter Resources">
+ <item name="JMeter Articles"
href="http://nagoya.apache.org/wiki/apachewiki.cgi?JMeterLinks"/>
</menu>
<menu name="Community">
<item name="Get Involved" href="/site/getinvolved.html"/>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]