From e1b8b0d8a080991befc174db259f485273de98e7 Mon Sep 17 00:00:00 2001
From: No Author
Date: Fri, 19 Aug 2005 20:24:19 +0000
Subject: [PATCH] This commit was manufactured by cvs2svn to create tag
'rel-2_1'.
git-svn-id: https://svn.apache.org/repos/asf/jakarta/jmeter/tags/rel-2_1@325652 13f79535-47bb-0310-9956-ffa450edef68
---
KEYS.txt | 17 +++
build.xml | 2 +-
eclipse.classpath | 2 +-
.../org/apache/jmeter/config/CSVDataSet.java | 2 +-
.../org/apache/jmeter/config/Argument.java | 3 +
.../org/apache/jmeter/config/Arguments.java | 3 +
.../org/apache/jmeter/engine/PreCompiler.java | 20 +--
.../jmeter/engine/StandardJMeterEngine.java | 23 ++--
.../org/apache/jmeter/gui/GuiPackage.java | 6 +
.../org/apache/jmeter/junit/JMeterTest.java | 15 +-
.../org/apache/jmeter/save/SaveService.java | 22 +--
.../apache/jmeter/services/FileServer.java | 6 +-
.../apache/jmeter/testelement/TestPlan.java | 5 +
.../jmeter/testelement/ThreadListener.java | 43 ++++++
.../property/FunctionProperty.java | 4 +-
.../org/apache/jmeter/util/JMeterVersion.java | 2 +-
.../org/apache/jorphan/util/JOrphanUtils.java | 74 +++-------
.../http/control/gui/HttpTestSampleGui2.java | 7 +-
.../control/gui/WebServiceSamplerGui.java | 9 +-
.../http/parser/HtmlParserHTMLParser.java | 9 +-
.../protocol/http/parser/JTidyHTMLParser.java | 2 +-
.../http/sampler/AccessLogSampler.java | 23 +++-
.../protocol/http/sampler/HTTPSampler2.java | 4 +-
.../protocol/http/util/accesslog/Filter.java | 4 +-
.../http/util/accesslog/LogFilter.java | 13 +-
.../accesslog/OrderPreservingLogParser.java | 27 ++++
.../http/util/accesslog/SessionFilter.java | 130 +++++++++++++-----
.../util/accesslog/SharedTCLogParser.java | 93 +++++++++++++
.../http/util/accesslog/TCLogParser.java | 2 +-
.../protocol/jdbc/sampler/JDBCSampler.java | 18 +--
.../jdbc/sampler/JDBCSamplerBeanInfo.java | 8 +-
.../sampler/JDBCSamplerResources.properties | 4 +-
.../JDBCSamplerResources_es.properties | 4 +-
.../protocol/tcp/sampler/TCPSampler.java | 119 +++++-----------
.../apache/jmeter/save/TestSaveService.java | 14 +-
.../apache/jorphan/util/TestJorphanUtils.java | 81 +++++++++++
xdocs/changes.xml | 4 +
xdocs/usermanual/component_reference.xml | 14 +-
...meter_distributed_testing_step_by_step.pdf | Bin 123784 -> 133695 bytes
...meter_distributed_testing_step_by_step.sxw | Bin 39165 -> 49185 bytes
40 files changed, 577 insertions(+), 261 deletions(-)
create mode 100644 src/core/org/apache/jmeter/testelement/ThreadListener.java
create mode 100644 src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/OrderPreservingLogParser.java
create mode 100644 src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/SharedTCLogParser.java
create mode 100644 test/src/org/apache/jorphan/util/TestJorphanUtils.java
diff --git a/KEYS.txt b/KEYS.txt
index a2d7bead7d6..f188ea33e8f 100644
--- a/KEYS.txt
+++ b/KEYS.txt
@@ -113,3 +113,20 @@ LY8FCQXcYNsACgkQP+DBYbypc6yBbwCeOvnv0jFl9vF0s8xhSAoL//sVh+AAni2E
MqhkiC8tJZdEK9EAd9T0HkeT
=Y6NQ
-----END PGP PUBLIC KEY BLOCK-----
+
+key for: Peter Lin
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.2 (MingW32)
+
+mIsEQvwEgAEEALtlIFI5TYGenY7iQhhoU26lca2z7PTIGlCZ3eAPxjQNek/oCEPR
+nl39NtNKjEo4V2eJPrZz4nlA2pUxwkzVWGe9yULQT73mB0pkQxr40iH2vIdpkW3y
+CV3NymyH77XrvELhQrnLpK1pbzMdPTnpr04Wq4BCysEcGzJJT7mlIDiBAAYptDtQ
+ZXRlciBMaW4gKFBldGVyIExpbiBKTWV0ZXIgY29tbWl0dGVyKSA8d29vbGZlbEBh
+cGFjaGUub3JnPoi8BBMBAgAmBQJC/ASAAhsDBQkDwmcABgsJCAcDAgQVAggDBBYC
+AwECHgECF4AACgkQlell0l24rA970wP/WhOKLRrpF8IrjgpZsJ4X7CpdOhRQRfXd
+8u7TxhdxTRom6XFW14LyUH9i7teRB3RC8F809jFwfmR2oa4fhNhv36QkXQI9npmS
+gebbL9RMq3mjdXwtpDYbcA4r2pbz+Wf2m+BV38Gz8k+WOm5X8QW3sRbZ1QnxUjTu
+NGHyeqz14hs=
+=rMW+
+-----END PGP PUBLIC KEY BLOCK-----
\ No newline at end of file
diff --git a/build.xml b/build.xml
index 97d82951977..c899389f43c 100644
--- a/build.xml
+++ b/build.xml
@@ -298,7 +298,7 @@
-
+
diff --git a/eclipse.classpath b/eclipse.classpath
index d5e31a04375..7a7b4d7d110 100644
--- a/eclipse.classpath
+++ b/eclipse.classpath
@@ -35,7 +35,7 @@
-
+
diff --git a/src/components/org/apache/jmeter/config/CSVDataSet.java b/src/components/org/apache/jmeter/config/CSVDataSet.java
index aad80920113..0895f9c9d81 100644
--- a/src/components/org/apache/jmeter/config/CSVDataSet.java
+++ b/src/components/org/apache/jmeter/config/CSVDataSet.java
@@ -62,7 +62,7 @@ public void iterationStart(LoopIterationEvent iterEvent) {
String delim = getDelimiter();
if (delim.equals("\\t"))
delim = "\t";// Make it easier to enter a Tab
- String[] lineValues = JOrphanUtils.split(server.readLine(getFilename()), delim);
+ String[] lineValues = JOrphanUtils.split(server.readLine(getFilename()), delim,false);
for (int a = 0; a < vars.length && a < lineValues.length; a++) {
this.getThreadContext().getVariables().put(vars[a], lineValues[a]);
}
diff --git a/src/core/org/apache/jmeter/config/Argument.java b/src/core/org/apache/jmeter/config/Argument.java
index d45706a8a3b..02190d2d3a2 100644
--- a/src/core/org/apache/jmeter/config/Argument.java
+++ b/src/core/org/apache/jmeter/config/Argument.java
@@ -22,6 +22,8 @@
import org.apache.jmeter.testelement.AbstractTestElement;
import org.apache.jmeter.testelement.property.StringProperty;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
// Mark Walsh, 2002-08-03, add metadata attribute
// add constructor Argument(String name, Object value, Object metadata)
@@ -36,6 +38,7 @@
* @version $Revision$
*/
public class Argument extends AbstractTestElement implements Serializable {
+ private static Logger log = LoggingManager.getLoggerForClass();
/** Name used to store the argument's name. */
public static final String ARG_NAME = "Argument.name";
diff --git a/src/core/org/apache/jmeter/config/Arguments.java b/src/core/org/apache/jmeter/config/Arguments.java
index 94044d813e9..fac807eba38 100644
--- a/src/core/org/apache/jmeter/config/Arguments.java
+++ b/src/core/org/apache/jmeter/config/Arguments.java
@@ -27,6 +27,8 @@
import org.apache.jmeter.testelement.property.CollectionProperty;
import org.apache.jmeter.testelement.property.PropertyIterator;
import org.apache.jmeter.testelement.property.TestElementProperty;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
// Mark Walsh, 2002-08-03 add method:
// addArgument(String name, Object value, Object metadata)
@@ -41,6 +43,7 @@
* @version $Revision$
*/
public class Arguments extends ConfigTestElement implements Serializable {
+ private static Logger log = LoggingManager.getLoggerForClass();
/** The name of the property used to store the arguments. */
public static final String ARGUMENTS = "Arguments.arguments";
diff --git a/src/core/org/apache/jmeter/engine/PreCompiler.java b/src/core/org/apache/jmeter/engine/PreCompiler.java
index a7af74218e0..7eba7eb7457 100644
--- a/src/core/org/apache/jmeter/engine/PreCompiler.java
+++ b/src/core/org/apache/jmeter/engine/PreCompiler.java
@@ -52,21 +52,25 @@ public PreCompiler() {
* @see HashTreeTraverser#addNode(Object, HashTree)
*/
public void addNode(Object node, HashTree subTree) {
+ if(node instanceof TestElement)
+ {
+ try {
+ replacer.replaceValues((TestElement) node);
+ } catch (InvalidVariableException e) {
+ log.error("invalid variables", e);
+ }
+ }
if (node instanceof TestPlan) {
- Map args = ((TestPlan) node).getUserDefinedVariables();
+ ((TestPlan)node).prepareForPreCompile(); //A hack to make user-defined variables in the testplan element more dynamic
+ Map args = ((TestPlan) node).getUserDefinedVariables();
replacer.setUserDefinedVariables(args);
JMeterVariables vars = new JMeterVariables();
vars.putAll(args);
JMeterContextService.getContext().setVariables(vars);
- } else if (node instanceof TestElement) {
- try {
- replacer.replaceValues((TestElement) node);
- } catch (InvalidVariableException e) {
- log.error("invalid variables", e);
- }
- }
+ }
if (node instanceof Arguments) {
+ ((Arguments)node).setRunningVersion(true);
Map args = ((Arguments) node).getArgumentsAsMap();
replacer.addVariables(args);
JMeterContextService.getContext().getVariables().putAll(args);
diff --git a/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java b/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java
index 9b61f5fb415..929a93eb15d 100644
--- a/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java
+++ b/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java
@@ -204,6 +204,7 @@ protected void notifyTestListenersOfStart() {
}
protected void notifyTestListenersOfEnd() {
+ log.info("Notifying test listeners of end of test");
Iterator iter = testListeners.getSearchResults().iterator();
while (iter.hasNext()) {
TestListener tl = (TestListener) iter.next();
@@ -231,12 +232,16 @@ public void reset() {
}
public synchronized void threadFinished(JMeterThread thread) {
- allThreads.remove(thread);
- log.info("Ending thread " + thread.getThreadNum());
- if (!serialized && allThreads.size() == 0 && !schcdule_run) {
- log.info("Stopping test");
- stopTest();
- }
+ try {
+ allThreads.remove(thread);
+ log.info("Ending thread " + thread.getThreadNum());
+ if (!serialized && allThreads.size() == 0 && !schcdule_run) {
+ log.info("Stopping test");
+ stopTest();
+ }
+ } catch (Throwable e) {
+ log.fatalError("Call to threadFinished should never throw an exception - this can deadlock JMeter",e);
+ }
}
public synchronized void stopTest() {
@@ -296,7 +301,7 @@ public void run() {
if (((TestPlan) plan[0]).isSerialized()) {
serialized = true;
}
- JMeterContextService.startTest();
+ JMeterContextService.startTest();
compileTree();
/**
* Notification of test listeners needs to happen after function
@@ -354,9 +359,9 @@ public void run() {
log.info("Continue on error");
}
+ ListedHashTree threadGroupTree = (ListedHashTree) searcher.getSubTree(group);
+ threadGroupTree.add(group, testLevelElements);
for (int i = 0; running && i < threads.length; i++) {
- ListedHashTree threadGroupTree = (ListedHashTree) searcher.getSubTree(group);
- threadGroupTree.add(group, testLevelElements);
threads[i] = new JMeterThread(cloneTree(threadGroupTree), this, notifier);
threads[i].setThreadNum(i);
threads[i].setThreadGroup(group);
diff --git a/src/core/org/apache/jmeter/gui/GuiPackage.java b/src/core/org/apache/jmeter/gui/GuiPackage.java
index cc2a5ae21a2..6abe3456bc2 100644
--- a/src/core/org/apache/jmeter/gui/GuiPackage.java
+++ b/src/core/org/apache/jmeter/gui/GuiPackage.java
@@ -25,6 +25,7 @@
import java.util.HashMap;
import java.util.Map;
+import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import org.apache.jmeter.engine.util.ValueReplacer;
@@ -306,6 +307,11 @@ public TestElement createTestElement(String objClass) {
return node;
} catch (NoClassDefFoundError e) {
log.error("Problem retrieving gui for " + objClass, e);
+ String msg="Cannot find class: "+e.getMessage();
+ JOptionPane.showMessageDialog(null,
+ msg,
+ "Missing jar? See log file." ,
+ JOptionPane.ERROR_MESSAGE);
throw new RuntimeException(e.toString()); // Probably a missing
// jar
} catch (ClassNotFoundException e) {
diff --git a/src/core/org/apache/jmeter/junit/JMeterTest.java b/src/core/org/apache/jmeter/junit/JMeterTest.java
index ff042f1dd17..3e0b1ec75ee 100644
--- a/src/core/org/apache/jmeter/junit/JMeterTest.java
+++ b/src/core/org/apache/jmeter/junit/JMeterTest.java
@@ -173,11 +173,14 @@ public void createTitleSet() throws Exception {
List components = ((Element) sections.get(i)).getChildren("component");
for (int j = 0; j < components.size(); j++) {
Element comp = (Element) components.get(j);
- guiTitles.put(comp.getAttributeValue("name"), Boolean.FALSE);
+ String nm=comp.getAttributeValue("name");
+ if (!nm.equals("SSL Manager")){// Not a true GUI component
+ guiTitles.put(nm.replace(' ','_'), Boolean.FALSE);
+ }
}
}
// Add titles that don't need to be documented
- guiTitles.put("Root", Boolean.FALSE);
+ //guiTitles.put("Root", Boolean.FALSE);
guiTitles.put("Example Sampler", Boolean.FALSE);
}
@@ -235,10 +238,6 @@ private int scanprintMap(Map m, String t) {
while (i.hasNext()) {
Object key = i.next();
if (!m.get(key).equals(Boolean.TRUE)) {
- if (key.equals("SSL Manager"))// Not a true GUI component
- {
- continue;
- }
if (unseen == 0)// first time
{
System.out.println("\nNames remaining in " + t + " Map:");
@@ -332,13 +331,13 @@ private static Test suiteBeanComponents() throws Exception {
*/
public void runGUITitle() throws Exception {
if (guiTitles.size() > 0) {
- String title = guiItem.getStaticLabel();
+ String title = guiItem.getDocAnchor();
boolean ct = guiTitles.containsKey(title);
if (ct)
guiTitles.put(title, Boolean.TRUE);// So we can detect extra
// entries
if (// Is this a work in progress or an internal GUI component?
- (title.length() > 0) // Will be "" for internal components
+ (title != null && title.length() > 0) // Will be "" for internal components
&& (title.toUpperCase().indexOf("(ALPHA") == -1) && (title.toUpperCase().indexOf("(BETA") == -1)
&& (!title.equals("Example1")) // Skip the example samplers
// ...
diff --git a/src/core/org/apache/jmeter/save/SaveService.java b/src/core/org/apache/jmeter/save/SaveService.java
index fb3cbb23b57..0caf7ea5275 100644
--- a/src/core/org/apache/jmeter/save/SaveService.java
+++ b/src/core/org/apache/jmeter/save/SaveService.java
@@ -220,23 +220,23 @@ private static void checkVersion(Class clazz, String expected) {
private static void checkVersions() {
versionsOK = true;
- checkVersion(BooleanPropertyConverter.class, "1.4");
- checkVersion(HashTreeConverter.class, "1.2");
- checkVersion(IntegerPropertyConverter.class, "1.3");
- checkVersion(LongPropertyConverter.class, "1.3");
- checkVersion(MultiPropertyConverter.class, "1.3");
- checkVersion(SampleResultConverter.class, "1.8");
+ checkVersion(BooleanPropertyConverter.class, "1.5");
+ checkVersion(HashTreeConverter.class, "1.3");
+ checkVersion(IntegerPropertyConverter.class, "1.4");
+ checkVersion(LongPropertyConverter.class, "1.4");
+ checkVersion(MultiPropertyConverter.class, "1.4");
+ checkVersion(SampleResultConverter.class, "1.9");
/*
* Should check this, but tricky to do, because not built until later.
*
* checkVersion(HTTPResultConverter.class, "1.6");
*
*/
- checkVersion(StringPropertyConverter.class, "1.6");
- checkVersion(TestElementConverter.class, "1.3");
- checkVersion(TestElementPropertyConverter.class, "1.6");
- checkVersion(ScriptWrapperConverter.class, "1.5");
- checkVersion(TestResultWrapperConverter.class, "1.4");
+ checkVersion(StringPropertyConverter.class, "1.7");
+ checkVersion(TestElementConverter.class, "1.4");
+ checkVersion(TestElementPropertyConverter.class, "1.7");
+ checkVersion(ScriptWrapperConverter.class, "1.6");
+ checkVersion(TestResultWrapperConverter.class, "1.5");
if (!PROPVERSION.equalsIgnoreCase(propertiesVersion)) {
log.warn("Property file - expected " + PROPVERSION + ", found " + propertiesVersion);
}
diff --git a/src/core/org/apache/jmeter/services/FileServer.java b/src/core/org/apache/jmeter/services/FileServer.java
index a18d0d576a1..a8e6a0663ae 100644
--- a/src/core/org/apache/jmeter/services/FileServer.java
+++ b/src/core/org/apache/jmeter/services/FileServer.java
@@ -72,7 +72,6 @@ public static FileServer getFileServer() {
}
public void setBasedir(String basedir) throws IOException {
- log.info("Setting basedir to: " + basedir);
if (filesOpen()) {
throw new IOException("Files are still open, cannot change base directory");
}
@@ -90,7 +89,6 @@ public String getBaseDir() {
}
public synchronized void reserveFile(String filename) {
- log.info("filename = " + filename + " base = " + base);
if (!files.containsKey(filename)) {
Object[] file = new Object[] { new File(base, filename), null };
files.put(filename, file);
@@ -151,7 +149,7 @@ public void closeFiles() throws IOException {
*/
public synchronized void closeFile(String name) throws IOException {
Object[] file = (Object[]) files.get(name);
- if (file[1] != null) {
+ if (file != null && file.length == 2 && file[1] != null) {
((Reader) file[1]).close();
file[1] = null;
}
@@ -171,6 +169,8 @@ protected boolean filesOpen() {
/**
* Method will get a random file in a base directory
+ * TODO hey, not sure this method belongs here. FileServer is for threadsafe
+ * File access relative to current test's base directory.
*
* @param basedir
* @return
diff --git a/src/core/org/apache/jmeter/testelement/TestPlan.java b/src/core/org/apache/jmeter/testelement/TestPlan.java
index 5bf023d9ba9..1a769e79cd9 100644
--- a/src/core/org/apache/jmeter/testelement/TestPlan.java
+++ b/src/core/org/apache/jmeter/testelement/TestPlan.java
@@ -88,6 +88,11 @@ public TestPlan(String name) {
// setSerialized(false);
setProperty(new CollectionProperty(THREAD_GROUPS, threadGroups));
}
+
+ public void prepareForPreCompile()
+ {
+ getVariables().setRunningVersion(true);
+ }
/**
* Fetches the functional mode property
diff --git a/src/core/org/apache/jmeter/testelement/ThreadListener.java b/src/core/org/apache/jmeter/testelement/ThreadListener.java
new file mode 100644
index 00000000000..69655897f18
--- /dev/null
+++ b/src/core/org/apache/jmeter/testelement/ThreadListener.java
@@ -0,0 +1,43 @@
+// $Header$
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.jmeter.testelement;
+
+/**
+ * Allow threads to perform startup and closedown if necessary
+ *
+ * @version $Revision$ on $Date$
+ */
+public interface ThreadListener {
+ /**
+ * Called just before the start of the thread
+ *
+ * @see org.apache.jmeter.threads.JMeterThread#threadStarted()
+ *
+ */
+ public void threadStarted();
+
+ /**
+ * Called once for each thread at the end of a test
+ *
+ * @see org.apache.jmeter.threads.JMeterThread#threadFinished()
+ *
+ */
+ public void threadFinished();
+
+}
\ No newline at end of file
diff --git a/src/core/org/apache/jmeter/testelement/property/FunctionProperty.java b/src/core/org/apache/jmeter/testelement/property/FunctionProperty.java
index 2b567e7fe18..42a5d869804 100644
--- a/src/core/org/apache/jmeter/testelement/property/FunctionProperty.java
+++ b/src/core/org/apache/jmeter/testelement/property/FunctionProperty.java
@@ -70,12 +70,12 @@ public String getStringValue() {
JMeterContext ctx = JMeterContextService.getContext();// Expensive, so
// do
// once
- if (!isRunningVersion() || !ctx.isSamplingStarted()) {
+ if (!isRunningVersion() /*|| !ctx.isSamplingStarted()*/) {
log.debug("Not running version, return raw function string");
return function.getRawParameters();
} else {
log.debug("Running version, executing function");
- int iter = ctx.getVariables().getIteration();
+ int iter = ctx.getVariables() != null ? ctx.getVariables().getIteration() : -1;
if (iter < testIteration) {
testIteration = -1;
}
diff --git a/src/core/org/apache/jmeter/util/JMeterVersion.java b/src/core/org/apache/jmeter/util/JMeterVersion.java
index 9319062b7bc..841d3c6209c 100644
--- a/src/core/org/apache/jmeter/util/JMeterVersion.java
+++ b/src/core/org/apache/jmeter/util/JMeterVersion.java
@@ -41,7 +41,7 @@ public class JMeterVersion {
* JMeterUtils This ensures that JMeterUtils always gets the correct
* version, even if it is not re-compiled during the build.
*/
- private static final String VERSION = "2.1.20050630";
+ private static final String VERSION = "2.1";
static final String COPYRIGHT = "Copyright (c) 1998-2005 The Apache Software Foundation";
diff --git a/src/jorphan/org/apache/jorphan/util/JOrphanUtils.java b/src/jorphan/org/apache/jorphan/util/JOrphanUtils.java
index 68e6d53fac4..3759d5311a3 100644
--- a/src/jorphan/org/apache/jorphan/util/JOrphanUtils.java
+++ b/src/jorphan/org/apache/jorphan/util/JOrphanUtils.java
@@ -61,15 +61,18 @@ private JOrphanUtils() {
* Character to split the string on
* @return Array of all the tokens.
*/
- public static String[] split(String splittee, String splitChar) {
+ public static String[] split(String splittee, String splitChar,boolean truncate) {
if (splittee == null || splitChar == null) {
return new String[0];
}
int spot;
- while ((spot = splittee.indexOf(splitChar + splitChar)) != -1) {
- splittee = splittee.substring(0, spot + splitChar.length())
- + splittee.substring(spot + 2 * splitChar.length(), splittee.length());
- }
+ if(truncate) {
+ while ((spot = splittee.indexOf(splitChar + splitChar)) != -1) {
+ splittee = splittee.substring(0, spot + splitChar.length())
+ + splittee.substring(spot + 2 * splitChar.length(), splittee.length());
+ }
+ if(splittee.startsWith(splitChar)) splittee = splittee.substring(splitChar.length());
+ }
Vector returns = new Vector();
int start = 0;
int length = splittee.length();
@@ -78,6 +81,10 @@ public static String[] split(String splittee, String splitChar) {
if (spot > 0) {
returns.addElement(splittee.substring(start, spot));
}
+ else
+ {
+ returns.addElement("");
+ }
start = spot + splitChar.length();
}
if (start < length) {
@@ -87,6 +94,11 @@ public static String[] split(String splittee, String splitChar) {
returns.copyInto(values);
return values;
}
+
+ public static String[] split(String splittee,String splitChar)
+ {
+ return split(splittee,splitChar,true);
+ }
private static final String SPACES = " ";
@@ -280,56 +292,4 @@ public static byte[] getByteArraySlice(byte[] array, int begin, int end) {
return slice;
}
-
- public static class Test extends TestCase {
- public void testReplace1() {
- assertEquals("xyzdef", replaceFirst("abcdef", "abc", "xyz"));
- }
-
- public void testReplace2() {
- assertEquals("axyzdef", replaceFirst("abcdef", "bc", "xyz"));
- }
-
- public void testReplace3() {
- assertEquals("abcxyz", replaceFirst("abcdef", "def", "xyz"));
- }
-
- public void testReplace4() {
- assertEquals("abcdef", replaceFirst("abcdef", "bce", "xyz"));
- }
-
- public void testReplace5() {
- assertEquals("abcdef", replaceFirst("abcdef", "alt=\"\" ", ""));
- }
-
- public void testReplace6() {
- assertEquals("abcdef", replaceFirst("abcdef", "alt=\"\" ", ""));
- }
-
- public void testReplace7() {
- assertEquals("alt=\"\"", replaceFirst("alt=\"\"", "alt=\"\" ", ""));
- }
-
- public void testReplace8() {
- assertEquals("img src=xyz ", replaceFirst("img src=xyz alt=\"\" ", "alt=\"\" ", ""));
- }
-
- public void testSplit1() {
- String in = "a,bc,,"; // Test ignore trailing split characters
- String out[] = split(in, ",");
- assertEquals(2, out.length);
- assertEquals("a", out[0]);
- assertEquals("bc", out[1]);
- }
-
- public void testSplit2() {
- String in = ",,a,bc"; // Test leading split characters
- String out[] = split(in, ",");
- assertEquals("Should detect the leading split chars; ", 2, out.length - 2);
- assertEquals("", out[0]);
- assertEquals("", out[1]);
- assertEquals("a", out[2]);
- assertEquals("bc", out[3]);
- }
- }
}
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/HttpTestSampleGui2.java b/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/HttpTestSampleGui2.java
index 7e9ddea9fe0..078a1ceb731 100644
--- a/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/HttpTestSampleGui2.java
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/HttpTestSampleGui2.java
@@ -38,6 +38,11 @@ public TestElement createTestElement() {
}
public String getStaticLabel() {
- return super.getStaticLabel() + " HTTPCLient (ALPHA)";
+ return super.getStaticLabel() + " HTTPClient";
}
+
+ public String getDocAnchor() {
+ return super.getStaticLabel().replace(' ', '_');
+ }
+
}
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/WebServiceSamplerGui.java b/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/WebServiceSamplerGui.java
index 3e5c42ccb15..5bc6ebd6538 100644
--- a/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/WebServiceSamplerGui.java
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/control/gui/WebServiceSamplerGui.java
@@ -170,7 +170,7 @@ public void modifyTestElement(TestElement s) {
WebServiceSampler sampler = (WebServiceSampler) s;
this.configureTestElement(sampler);
sampler.setDomain(domain.getText());
- sampler.setPort(80);
+ sampler.setProperty(HTTPSamplerBase.PORT,port.getText());
sampler.setPath(path.getText());
sampler.setWsdlURL(wsdlField.getText());
sampler.setMethod(HTTPSamplerBase.POST);
@@ -280,12 +280,7 @@ public void configure(TestElement el) {
WebServiceSampler sampler = (WebServiceSampler) el;
wsdlField.setText(sampler.getWsdlURL());
domain.setText(sampler.getDomain());
- String portstring = sampler.getPropertyAsString(HTTPSamplerBase.PORT);
- if (portstring.equals("" + HTTPSamplerBase.UNSPECIFIED_PORT)) {
- port.setText("");
- } else {
- port.setText(portstring);
- }
+ port.setText(sampler.getPropertyAsString(HTTPSamplerBase.PORT));
path.setText(sampler.getPath());
soapAction.setText(sampler.getSoapAction());
soapXml.setText(sampler.getXmlData());
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/parser/HtmlParserHTMLParser.java b/src/protocol/http/org/apache/jmeter/protocol/http/parser/HtmlParserHTMLParser.java
index 07585d22803..86f3ce424f6 100644
--- a/src/protocol/http/org/apache/jmeter/protocol/http/parser/HtmlParserHTMLParser.java
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/parser/HtmlParserHTMLParser.java
@@ -48,6 +48,7 @@
import org.htmlparser.tags.LinkTag;
import org.htmlparser.tags.LinkTagTag;
import org.htmlparser.tags.ScriptTag;
+import org.htmlparser.tags.Tag;
import org.htmlparser.util.DefaultParserFeedback;
import org.htmlparser.util.NodeIterator;
import org.htmlparser.util.ParserException;
@@ -165,7 +166,13 @@ public Iterator getEmbeddedResourceURLs(byte[] html, URL baseUrl, URLCollection
} else if (node instanceof BgSoundTag) {
BgSoundTag script = (BgSoundTag) node;
binUrlStr = script.getAttribute("src");
- }
+ } else if (node instanceof Tag) {
+ Tag tag = (Tag) node;
+ String tagname=tag.getTagName();
+ if (tagname.equalsIgnoreCase("EMBED")){
+ binUrlStr = tag.getAttribute("src");
+ }
+ }
if (binUrlStr == null) {
continue;
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/parser/JTidyHTMLParser.java b/src/protocol/http/org/apache/jmeter/protocol/http/parser/JTidyHTMLParser.java
index bcfe943b31e..cb8937a965a 100644
--- a/src/protocol/http/org/apache/jmeter/protocol/http/parser/JTidyHTMLParser.java
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/parser/JTidyHTMLParser.java
@@ -111,7 +111,7 @@ private URL scanNodes(Node node, URLCollection urls, URL baseUrl) throws HTMLPar
break;
}
- if (name.equalsIgnoreCase("img")) {
+ if (name.equalsIgnoreCase("img") || name.equalsIgnoreCase("embed")) {
urls.addURL(getValue(attrs, "src"), baseUrl);
break;
}
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/sampler/AccessLogSampler.java b/src/protocol/http/org/apache/jmeter/protocol/http/sampler/AccessLogSampler.java
index d842293a6c4..87da4e7bf60 100644
--- a/src/protocol/http/org/apache/jmeter/protocol/http/sampler/AccessLogSampler.java
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/sampler/AccessLogSampler.java
@@ -25,6 +25,7 @@
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testbeans.TestBean;
import org.apache.jmeter.testelement.TestCloneable;
+import org.apache.jmeter.testelement.ThreadListener;
import org.apache.jmeter.threads.JMeterContextService;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.jorphan.util.JMeterException;
@@ -65,7 +66,7 @@
* @author Peter Lin
* @version $Revision$ last updated $Date$
*/
-public class AccessLogSampler extends HTTPSampler implements TestBean {
+public class AccessLogSampler extends HTTPSampler implements TestBean,ThreadListener {
private static Logger log = LoggingManager.getLoggerForClass();
public static final String DEFAULT_CLASS = "org.apache.jmeter.protocol.http.util.accesslog.TCLogParser";
@@ -296,6 +297,15 @@ public Object clone() {
initFilter();
s.filter = (Filter) ((TestCloneable) filter).clone();
}
+ if(TestCloneable.class.isAssignableFrom(Class.forName(parserClassName)))
+ {
+ instantiateParser();
+ s.PARSER = (LogParser)((TestCloneable)PARSER).clone();
+ if(filter != null)
+ {
+ s.PARSER.setFilter(s.filter);
+ }
+ }
} catch (Exception e) {
log.warn("Could not clone cloneable filter", e);
}
@@ -313,6 +323,7 @@ public void testEnded() {
if (PARSER != null) {
PARSER.close();
}
+ filter = null;
started = false;
super.testEnded();
}
@@ -326,4 +337,14 @@ public void testStarted() {
started = true;
super.testStarted();
}
+
+ /* (non-Javadoc)
+ * @see org.apache.jmeter.testelement.AbstractTestElement#threadFinished()
+ */
+ public void threadFinished() {
+ if(PARSER instanceof ThreadListener)
+ ((ThreadListener)PARSER).threadFinished();
+ if(filter instanceof ThreadListener)
+ ((ThreadListener)filter).threadFinished();
+ }
}
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler2.java b/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler2.java
index e460c5e6f8b..07daee11a72 100644
--- a/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler2.java
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSampler2.java
@@ -536,11 +536,11 @@ private void saveConnectionCookies(HttpState state, CookieManager cookieManager)
}
public void threadStarted() {
- log.info("Thread Started");
+ log.debug("Thread Started");
}
public void threadFinished() {
- log.info("Thread Finished");
+ log.debug("Thread Finished");
if (httpConn != null)
httpConn.close();
}
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/Filter.java b/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/Filter.java
index 6659e3b0804..985b6fa3ebe 100644
--- a/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/Filter.java
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/Filter.java
@@ -18,6 +18,8 @@
package org.apache.jmeter.protocol.http.util.accesslog;
+import org.apache.jmeter.testelement.TestElement;
+
/**
* Description:
*
@@ -82,7 +84,7 @@ public interface Filter {
* @param path
* @return boolean
*/
- public boolean isFiltered(String path);
+ public boolean isFiltered(String path,TestElement sampler);
/**
* In case the user wants to replace the file extension, log parsers should
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/LogFilter.java b/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/LogFilter.java
index e0430cdaa62..1a86f52afd9 100644
--- a/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/LogFilter.java
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/LogFilter.java
@@ -22,6 +22,7 @@
import java.util.ArrayList;
import org.apache.jmeter.junit.JMeterTestCase;
+import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.Perl5Compiler;
@@ -207,7 +208,7 @@ public void excludePattern(String[] regexp) {
* @param path
* @return boolean
*/
- public boolean isFiltered(String path) {
+ public boolean isFiltered(String path,TestElement el) {
// we do a quick check to see if any
// filters are set. If not we just
// return false to be efficient.
@@ -474,7 +475,7 @@ public void setUp() {
public void testReplaceExtension() {
testf.setReplaceExtension("html", "jsp");
- testf.isFiltered(TESTSTR);// set the required variables
+ testf.isFiltered(TESTSTR,null);// set the required variables
assertEquals(TESTSTROUT, testf.filter(TESTSTR));
}
@@ -485,7 +486,7 @@ public void testExcludeFiles() {
String theFile = td.file;
boolean expect = td.exclfile;
- testf.isFiltered(theFile);
+ testf.isFiltered(theFile,null);
String line = testf.filter(theFile);
if (line != null) {
assertTrue("Expect to accept " + theFile, expect);
@@ -502,7 +503,7 @@ public void testIncludeFiles() {
String theFile = td.file;
boolean expect = td.inclfile;
- testf.isFiltered(theFile);
+ testf.isFiltered(theFile,null);
String line = testf.filter(theFile);
if (line != null) {
assertTrue("Expect to accept " + theFile, expect);
@@ -520,7 +521,7 @@ public void testExcludePattern() {
String theFile = td.file;
boolean expect = td.exclpatt;
- assertEquals(!expect, testf.isFiltered(theFile));
+ assertEquals(!expect, testf.isFiltered(theFile,null));
String line = testf.filter(theFile);
if (line != null) {
assertTrue("Expect to accept " + theFile, expect);
@@ -537,7 +538,7 @@ public void testIncludePattern() {
String theFile = td.file;
boolean expect = td.inclpatt;
- assertEquals(!expect, testf.isFiltered(theFile));
+ assertEquals(!expect, testf.isFiltered(theFile,null));
String line = testf.filter(theFile);
if (line != null) {
assertTrue("Expect to accept " + theFile, expect);
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/OrderPreservingLogParser.java b/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/OrderPreservingLogParser.java
new file mode 100644
index 00000000000..4095fbfb527
--- /dev/null
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/OrderPreservingLogParser.java
@@ -0,0 +1,27 @@
+package org.apache.jmeter.protocol.http.util.accesslog;
+
+import org.apache.jmeter.testelement.TestElement;
+
+public class OrderPreservingLogParser extends SharedTCLogParser {
+
+ public OrderPreservingLogParser() {
+ super();
+ }
+
+ public OrderPreservingLogParser(String source) {
+ super(source);
+ }
+
+ /**
+ * parse a set number of lines from the access log. Keep in mind the number
+ * of lines parsed will depend the filter and number of lines in the log.
+ * The method returns the actual lines parsed.
+ *
+ * @param count
+ * @return lines parsed
+ */
+ public synchronized int parseAndConfigure(int count, TestElement el) {
+ return this.parse(el, count);
+ }
+
+}
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/SessionFilter.java b/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/SessionFilter.java
index 7d298fc9e39..932ec133f70 100644
--- a/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/SessionFilter.java
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/SessionFilter.java
@@ -21,11 +21,17 @@
package org.apache.jmeter.protocol.http.util.accesslog;
import java.io.Serializable;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.jmeter.protocol.http.control.CookieManager;
+import org.apache.jmeter.protocol.http.sampler.HTTPSampler;
import org.apache.jmeter.testelement.TestCloneable;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.testelement.ThreadListener;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
@@ -37,37 +43,26 @@
* @author mstover
*
*/
-public class SessionFilter implements Filter, Serializable, TestCloneable {
+public class SessionFilter implements Filter, Serializable, TestCloneable,ThreadListener {
+ private static final long serialVersionUID = 1;
static Logger log = LoggingManager.getLoggerForClass();
/**
- * This object is static across multiple threads in a test, via clone()
+ * These objects are static across multiple threads in a test, via clone()
* method.
*/
- protected List excludedIps;
-
- String ipAddress;
+ protected Map cookieManagers;
+ protected Set managersInUse;
+
+ protected CookieManager lastUsed;
- /*
+ /*
* (non-Javadoc)
*
* @see org.apache.jmeter.protocol.http.util.accesslog.LogFilter#excPattern(java.lang.String)
*/
protected boolean hasExcPattern(String text) {
- synchronized (excludedIps) {
- boolean exclude = false;
- for (Iterator x = excludedIps.iterator(); x.hasNext();) {
- if (text.indexOf((String) x.next()) > -1) {
- exclude = true;
- break;
- }
- }
- if (!exclude) {
- ipAddress = getIpAddress(text);
- excludedIps.add(ipAddress);
- }
- return exclude;
- }
+ return false;
}
protected String getIpAddress(String logLine) {
@@ -84,12 +79,21 @@ protected String getIpAddress(String logLine) {
* @see org.apache.jmeter.protocol.http.util.accesslog.Filter#reset()
*/
public void reset() {
- ipAddress = null;
+ cookieManagers.clear();
}
public Object clone() {
+ if(cookieManagers == null)
+ {
+ cookieManagers = Collections.synchronizedMap(new HashMap());
+ }
+ if(managersInUse == null)
+ {
+ managersInUse = Collections.synchronizedSet(new HashSet());
+ }
SessionFilter f = new SessionFilter();
- f.excludedIps = excludedIps;
+ f.cookieManagers = cookieManagers;
+ f.managersInUse = managersInUse;
return f;
}
@@ -97,7 +101,6 @@ public Object clone() {
*
*/
public SessionFilter() {
- excludedIps = new LinkedList();
}
/*
@@ -146,13 +149,55 @@ public void includePattern(String[] regexp) {
*
* @see org.apache.jmeter.protocol.http.util.accesslog.Filter#isFiltered(java.lang.String)
*/
- public boolean isFiltered(String path) {
- if (ipAddress != null) {
- log.debug("looking for ip address: " + ipAddress + " in line: " + path);
- return !(path.indexOf(ipAddress) > -1);
- } else
- return hasExcPattern(path);
+ public boolean isFiltered(String path,TestElement sampler) {
+ String ipAddr = getIpAddress(path);
+ CookieManager cm = getCookieManager(ipAddr);
+ ((HTTPSampler)sampler).setCookieManager(cm);
+ return false;
}
+
+ protected CookieManager getCookieManager(String ipAddr)
+ {
+ CookieManager cm = null;
+ // First have to release the cookie we were using so other
+ // threads stuck in wait can move on
+ synchronized(managersInUse)
+ {
+ if(lastUsed != null)
+ {
+ managersInUse.remove(lastUsed);
+ managersInUse.notify();
+ }
+ }
+ // let notified threads move on and get lock on managersInUse
+ if(lastUsed != null)
+ {
+ Thread.yield();
+ }
+ // here is the core routine to find appropriate cookie manager and
+ // check it's not being used. If used, wait until whoever's using it gives
+ // it up
+ synchronized(managersInUse)
+ {
+ cm = (CookieManager)cookieManagers.get(ipAddr);
+ if(cm == null)
+ {
+ cm = new CookieManager();
+ cookieManagers.put(ipAddr,cm);
+ }
+ while(managersInUse.contains(cm))
+ {
+ try {
+ managersInUse.wait();
+ } catch (InterruptedException e) {
+ log.info("SessionFilter wait interrupted");
+ }
+ }
+ managersInUse.add(cm);
+ lastUsed = cm;
+ }
+ return cm;
+ }
/*
* (non-Javadoc)
@@ -162,4 +207,23 @@ public boolean isFiltered(String path) {
*/
public void setReplaceExtension(String oldextension, String newextension) {
}
+
+ /* (non-Javadoc)
+ * @see org.apache.jmeter.testelement.ThreadListener#threadFinished()
+ */
+ public void threadFinished() {
+ synchronized(managersInUse)
+ {
+ managersInUse.remove(lastUsed);
+ managersInUse.notify();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.jmeter.testelement.ThreadListener#threadStarted()
+ */
+ public void threadStarted() {
+ // TODO Auto-generated method stub
+
+ }
}
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/SharedTCLogParser.java b/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/SharedTCLogParser.java
new file mode 100644
index 00000000000..6dc502bf266
--- /dev/null
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/SharedTCLogParser.java
@@ -0,0 +1,93 @@
+package org.apache.jmeter.protocol.http.util.accesslog;
+
+import java.io.IOException;
+
+import org.apache.jmeter.services.FileServer;
+import org.apache.jmeter.testelement.TestCloneable;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.testelement.ThreadListener;
+
+public class SharedTCLogParser extends TCLogParser implements TestCloneable {
+
+ public SharedTCLogParser() {
+ super();
+ }
+
+ public SharedTCLogParser(String source) {
+ super(source);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#clone()
+ */
+ public Object clone() {
+ SharedTCLogParser parser = new SharedTCLogParser();
+ parser.FILENAME = FILENAME;
+ parser.FILTER = FILTER;
+ return parser;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.jmeter.protocol.http.util.accesslog.TCLogParser#parse(org.apache.jmeter.testelement.TestElement, int)
+ */
+ public int parse(TestElement el, int parseCount) {
+ FileServer fileServer = FileServer.getFileServer();
+ fileServer.reserveFile(FILENAME);
+ try {
+ return parse(fileServer, el, parseCount);
+ } catch (Exception exception) {
+ log.error("Problem creating samples", exception);
+ }
+ return -1;// indicate that an error occured
+ }
+
+ /**
+ * The method is responsible for reading each line, and breaking out of the
+ * while loop if a set number of lines is given.
+ *
+ * @param breader
+ */
+ protected int parse(FileServer breader, TestElement el, int parseCount) {
+ int actualCount = 0;
+ String line = null;
+ try {
+ // read one line at a time using
+ // BufferedReader
+ line = breader.readLine(FILENAME);
+ while (line != null) {
+ if (line.length() > 0) {
+ actualCount += this.parseLine(line, el);
+ }
+ // we check the count to see if we have exceeded
+ // the number of lines to parse. There's no way
+ // to know where to stop in the file. Therefore
+ // we use break to escape the while loop when
+ // we've reached the count.
+ if (parseCount != -1 && actualCount >= parseCount) {
+ break;
+ }
+ line = breader.readLine(FILENAME);
+ }
+ if (line == null) {
+ breader.closeFile(FILENAME);
+ // this.READER = new BufferedReader(new
+ // FileReader(this.SOURCE));
+ // parse(this.READER,el);
+ }
+ } catch (IOException ioe) {
+ log.error("Error reading log file", ioe);
+ }
+ return actualCount;
+ }
+
+ public void close() {
+ try {
+ FileServer.getFileServer().closeFile(FILENAME);
+ } catch (IOException e) {
+ // do nothing
+ }
+ }
+
+
+
+}
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/TCLogParser.java b/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/TCLogParser.java
index 1a055e4c4ae..dab041e7b1b 100644
--- a/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/TCLogParser.java
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/TCLogParser.java
@@ -244,7 +244,7 @@ protected int parseLine(String line, TestElement el) {
el.setProperty(HTTPSamplerBase.METHOD, RMETHOD);
if (FILTER != null) {
log.debug("filter is not null");
- if (!FILTER.isFiltered(line)) {
+ if (!FILTER.isFiltered(line,el)) {
log.debug("line was not filtered");
// increment the current count
count++;
diff --git a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSampler.java b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSampler.java
index a7d89eeda79..057739a1af9 100644
--- a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSampler.java
+++ b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSampler.java
@@ -44,12 +44,13 @@ public class JDBCSampler extends AbstractSampler implements TestBean {
private static Logger log = LoggingManager.getLoggerForClass();
public static final String QUERY = "query";
+ public static final String SELECT = "Select Statement";
public String query = "";
public String dataSource = "";
- public boolean queryOnly = true;
+ public String queryType = SELECT;
/**
* Creates a JDBCSampler.
@@ -80,7 +81,7 @@ public SampleResult sample(Entry e) {
stmt = conn.createStatement();
// Based on query return value, get results
- if (isQueryOnly()) {
+ if (SELECT.equals(getQueryType())) {
ResultSet rs = null;
try {
rs = stmt.executeQuery(getQuery());
@@ -195,17 +196,16 @@ public void setDataSource(String dataSource) {
}
/**
- * @return Returns the queryOnly.
+ * @return Returns the queryType.
*/
- public boolean isQueryOnly() {
- return queryOnly;
+ public String getQueryType() {
+ return queryType;
}
/**
- * @param queryOnly
- * The queryOnly to set.
+ * @param queryType The queryType to set.
*/
- public void setQueryOnly(boolean queryOnly) {
- this.queryOnly = queryOnly;
+ public void setQueryType(String queryType) {
+ this.queryType = queryType;
}
}
diff --git a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerBeanInfo.java b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerBeanInfo.java
index c5400e67918..148f5e689f4 100644
--- a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerBeanInfo.java
+++ b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerBeanInfo.java
@@ -40,15 +40,17 @@ public JDBCSamplerBeanInfo() {
createPropertyGroup("varName", new String[] { "dataSource" });
- createPropertyGroup("sql", new String[] { "queryOnly", "query" });
+ createPropertyGroup("sql", new String[] { "queryType", "query" });
PropertyDescriptor p = property("dataSource");
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, "");
- p = property("queryOnly");
+ p = property("queryType");
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
- p.setValue(DEFAULT, new Boolean(true));
+ p.setValue(DEFAULT, JDBCSampler.SELECT);
+ p.setValue(NOT_OTHER,Boolean.TRUE);
+ p.setValue(TAGS,new String[]{JDBCSampler.SELECT,"Update Statement"});
p = property("query");
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
diff --git a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerResources.properties b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerResources.properties
index 1b90853a521..6ce82079548 100644
--- a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerResources.properties
+++ b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerResources.properties
@@ -3,7 +3,7 @@ varName.displayName=Variable Name Bound to Pool
sql.displayName=SQL Query
query.displayName=Query
query.shortDescription=SQL Query to send to database
-queryOnly.displayName=Query Only
-queryOnly.shortDescription=If true, will run as a query and not as an update/insert. Otherwise, run as update.
+queryType.displayName=Query Type
+queryType.shortDescription=Determines if the SQL statement should be run as a select statement or an update statement.
dataSource.displayName=Variable Name
dataSource.shortDescription=Name of the JMeter variable that the connection pool is bound to.
\ No newline at end of file
diff --git a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerResources_es.properties b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerResources_es.properties
index 80d12658274..f9522694520 100644
--- a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerResources_es.properties
+++ b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerResources_es.properties
@@ -4,7 +4,7 @@ dataSource.shortDescription=Nombre de la variable JMeter a la cual est\u00E1 lig
displayName=Petici\u00F3n JDBC
query.displayName=Query
query.shortDescription=Query SQL a enviar a la base de datos
-queryOnly.displayName=Solo Query
-queryOnly.shortDescription=is true, se lanzar\u00E1 como una query y no como un update/inser. Si no, se lanza como update.
+queryType.displayName=Solo Query
+queryType.shortDescription=is true, se lanzar\u00E1 como una query y no como un update/inser. Si no, se lanza como update.
sql.displayName=Query SQL
varName.displayName=Nombre de Variable Ligada al Pool
diff --git a/src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/TCPSampler.java b/src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/TCPSampler.java
index bf2fa933312..df4c0a2cfd1 100644
--- a/src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/TCPSampler.java
+++ b/src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/TCPSampler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2004 The Apache Software Foundation.
+ * Copyright 2003-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,19 +26,15 @@
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
-import java.util.Set;
import org.apache.jmeter.config.ConfigTestElement;
import org.apache.jmeter.util.JMeterUtils;
-import org.apache.jmeter.engine.event.LoopIterationEvent;
import org.apache.jmeter.samplers.AbstractSampler;
import org.apache.jmeter.samplers.Entry;
import org.apache.jmeter.samplers.SampleResult;
-import org.apache.jmeter.testelement.TestListener;
+import org.apache.jmeter.testelement.ThreadListener;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
@@ -46,7 +42,7 @@
* A sampler which understands Tcp requests.
*
*/
-public class TCPSampler extends AbstractSampler implements TestListener {
+public class TCPSampler extends AbstractSampler implements ThreadListener {
private static final Logger log = LoggingManager.getLoggerForClass();
public final static String SERVER = "TCPSampler.server"; //$NON-NLS-1$
@@ -67,9 +63,6 @@ public class TCPSampler extends AbstractSampler implements TestListener {
private final static String ERRKEY = "ERR"; //$NON-NLS-1$ key for HashMap
- private static Set allSockets = new HashSet();// Keep track of connections
- // to allow close
-
// If set, this is the regex that is used to extract the status from the
// response
// NOT implemented yet private final static String STATUS_REGEX =
@@ -142,7 +135,6 @@ private Socket getSocket() {
log.debug(this + " Timeout " + getTimeout() + " NoDelay " + getNoDelay()); //$NON-NLS-1$
log.debug("Created new connection " + con); //$NON-NLS-1$
cp.put(TCPKEY, con);
- allSockets.add(con);// Save so can be closed
} catch (UnknownHostException e) {
log.warn("Unknown host for " + getLabel(), e);//$NON-NLS-1$
cp.put(ERRKEY, e.toString());
@@ -302,22 +294,23 @@ public SampleResult sample(Entry e)// Entry tends to be ignored ...
}
}
}
- } catch (Exception ex) {
+ } catch (IOException ex) {
log.debug("", ex);
res.setResponseCode("500");
res.setResponseMessage(ex.toString());
- }
-
- // Calculate response time
- res.sampleEnd();
-
- // Set if we were successful or not
- res.setSuccessful(isSuccessful);
+ closeSocket();
+ } finally {
+ // Calculate response time
+ res.sampleEnd();
+
+ // Set if we were successful or not
+ res.setSuccessful(isSuccessful);
+ }
return res;
}
- /**
+ /**
* @param rc
* response code
* @return whether this represents success or not
@@ -332,69 +325,25 @@ private boolean checkResponseCode(String rc) {
return true;
}
- private void disconnectAll() {
- synchronized (allSockets) {
- Iterator i = allSockets.iterator();
- while (i.hasNext()) {
- Socket socket = (Socket) i.next();
- try {
- socket.close();
- } catch (IOException e) {
- log.warn("Error closing socket ", e);
- } finally {
- i.remove();
- }
- }
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jmeter.testelement.TestListener#testStarted()
- */
- public void testStarted() // Only called once per class?
- {
- log.debug(this + " test started");
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jmeter.testelement.TestListener#testEnded()
- */
- public void testEnded() // Only called once per class?
- {
- log.debug(this + " test ended");
- disconnectAll();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jmeter.testelement.TestListener#testStarted(java.lang.String)
- */
- public void testStarted(String host) {
- log.debug(this + " test started on " + host);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jmeter.testelement.TestListener#testEnded(java.lang.String)
- */
- public void testEnded(String host) {
- log.debug(this + " test ended on " + host);
- disconnectAll();
-
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jmeter.testelement.TestListener#testIterationStart(org.apache.jmeter.engine.event.LoopIterationEvent)
- */
- public void testIterationStart(LoopIterationEvent event) {
- log.debug(this + " test iteration start on " + event.getIteration());
- }
+ public void threadStarted() {
+ log.debug("Thread Started");
+ }
+
+ private void closeSocket() {
+ Map cp = (Map) tp.get();
+ Socket con = (Socket) cp.remove(TCPKEY);
+ if (con != null) {
+ log.debug(this + " Closing connection " + con); //$NON-NLS-1$
+ try {
+ con.close();
+ } catch (IOException e) {
+ log.warn("Error closing socket "+e);
+ }
+ }
+ }
+
+ public void threadFinished() {
+ log.debug("Thread Finished");
+ closeSocket();
+ }
}
diff --git a/test/src/org/apache/jmeter/save/TestSaveService.java b/test/src/org/apache/jmeter/save/TestSaveService.java
index d237617f931..8719343e43a 100644
--- a/test/src/org/apache/jmeter/save/TestSaveService.java
+++ b/test/src/org/apache/jmeter/save/TestSaveService.java
@@ -67,11 +67,21 @@ public void testLoadAndSave() throws Exception {
// fail, because the order of the properties within each
// test element may change. Comparing the lengths should be
// enough to detect most problem cases...
- if (len != out.size()) {
+ int outsz=out.size();
+ // Allow for input in CRLF and output in LF only
+ int lines=0;
+ byte ba[]=out.toByteArray();
+ for(int j=0;jHow-to for JMS samplers
Bug 35525 - Added Spanish localisation
Bug 30379 - allow server.rmi.port to be overridden
+enhanced the monitor listener to save the calculated stats
+Functions and variables now work at top level of test plan
Bug fixes:
@@ -81,6 +83,8 @@
- Fixed webservice sampler so it works with user defined variables
- Fixed screen borders for LDAP config GUI elements
- Bug 31184 - make sure encoding is specified in JDBC sampler
+- TCP sampler - only share sockets with same host:port details; correct the manual
+- Extract src attribute for embed tags in JTidy and Html Parsers
Version 2.0.3
diff --git a/xdocs/usermanual/component_reference.xml b/xdocs/usermanual/component_reference.xml
index 9f699c46941..df2d6aedfa8 100644
--- a/xdocs/usermanual/component_reference.xml
+++ b/xdocs/usermanual/component_reference.xml
@@ -80,6 +80,9 @@ JMeter assumes the FTP server is listening on the default port.
them. This can save you time if you have a lot of HTTP requests or requests with many
parameters.
+ There are two versions of the sampler
+ - one uses the default Java HTTP implementation, the other uses Commons HttpClient
+
If the request requires a login authorization, you will also have to add an
Configuration Element. And, if the request uses cookies, then you will also need an
@@ -614,8 +617,15 @@ TBC
The TCP Sampler opens a TCP/IP connection to the specified server.
It then sends the text, and waits for a response.
- Once established, the same connection is re-used by the Sampler that created it.
- Connections are not shared between Samplers, even in the same thread.
+
+ Connections are shared between Samplers in the same thread, provided that the exact
+ same host name string and port are used.
+ To force a different socket to be used, change the hostname by changing the case
+ of one of the letters, e.g. www.apache.org and wWw.apache.org will use different
+ sockets.
+
+ If an error is detected, the socket is closed.
+ Another socket will be reopened on the next sample.
The following properties can be used to control its operation:
diff --git a/xdocs/usermanual/jmeter_distributed_testing_step_by_step.pdf b/xdocs/usermanual/jmeter_distributed_testing_step_by_step.pdf
index 73505b2864c8d500471407c7c2126f1f2b349daa..e338dd92a5240033882b5f47931450854a6115e9 100644
GIT binary patch
delta 19853
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
delta 10746
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
P4q#(2Gs|lzU}O9rww&Gd
diff --git a/xdocs/usermanual/jmeter_distributed_testing_step_by_step.sxw b/xdocs/usermanual/jmeter_distributed_testing_step_by_step.sxw
index 40a3840893871237a29f4e3f5659b38f431331c9..755c61c11bfc544cb4c5a5edab9757ab3ab090a9 100644
GIT binary patch
delta 16508
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