diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..20ea5d9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+# binaries
+dependency-reduced-pom.xml
+target
+
+# eclipse
+.classpath
+.project
+.settings/
+
+# linux
+*~
+\#*#
diff --git a/LICENCE b/LICENCE
new file mode 100644
index 0000000..b4bd858
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team
+
+ 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.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..12a1e2c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,185 @@
+mqttws-jmeter
+===========
+
+Jmeter MQTT sampler with support for websockets
+
+Initially a fork of https://github.com/tuanhiep/mqtt-jmeter by
+Tuan Hiep, ERODS Team, LIG- Grenoble-France
+
+
+# Introduction
+
+The MQTTWS Plugin in Jmeter is used for the injection testing of MQTT brokers.
+It uses a paho based client that supports MQTT over tcp and websockets.
+
+
+# How to install MQTT plugin in Jmeter
+
+From the repository: https://github.com/winglet/mqtt-jmeter
+Get the source code, go to mqtt-jemeter folder and and use the command maven in terminal (Ubuntu):
+
+ mvn clean install package
+
+You also need to build (TODO)
+
+to obtain the file **mqtt-jmeter.jar** in **mqtt-jemeter/target**.
+Put the **mqtt-jemeter.jar** in the folder **lib/ext** of Jmeter
+(to be downloaded on http://jmeter.apache.org/download_jmeter.cgi ).
+
+Remind that, it's necessary to update the file **ApacheJMeter_core.jar** in the repository lib/ext of Jmeter.
+Update the file messages.properties in the folder :/org/apache/jmeter/resources/
+in **ApacheJMeter_core.jar** by new file messages.properties from
+https://github.com/tuanhiep/mqtt-jmeter/tree/master/ressource
+
+# How to use MQTT plugin in Jmeter
+
+## MQTT Publisher
+
+The interface graphic of Jmeter:
+
+![Alt text](images/Main_Interface_Jmeter.png)
+
+Right-click “Thread” and choose : Add → Sampler → MQTT Publisher
+
+![Alt text](images/MQTT_Publisher.png)
+
+In the principal interface of MQTT Publisher we have the fields:
+*Connection Info*
+
+**Name:** Name of the MQTT Publisher
+**Comments:** Your comments
+**Provider URL:** the address of MQTT server example: tcp://localhost:1883
+**Client Id:** Your Id in the session with MQTT server example: Noel De Palma
+**List Topic:** The list of topic's names you want to publish to
+The topic's names are separated by a comma ","
+For example: List Topic: GRENOBLE/LIG,GRENOBLE/UJF-LIG
+This means, you'll publish to 2 topics: GRENOBLE/LIG and GRENOBLE/UJF-LIG
+You can choose the option **One connection per topic** : It means that for each topic in the list above, the plugin will create one correspondant
+ connection. Note that, if the client Id is "Noel De Palma", for example, and you have 2 topics in the list, so the plugin will create 2 connections with 2 Client
+Id : "Noel De Palma 0" and "Noel De Palma 1"
+The plugin provide two strategies to publish:
+ **1: Round Robin** : You'll publish to the topics in equal portions and in circular order
+ **2: Random** : You'll publish to a random topic in the list above
+If the list of topic has only one topic, so regardless the strategies, you'll publish to the topic for sure.
+ **Use Authorization check box:** Necessary in the case the connection needs the username and
+password
+**User:** Your username
+**Password:** Your password
+**Number of samples to aggregate:** In other way, the number of messages you want to publish to
+the MQTT sever in this MQTT Publisher thread, with the value like the configuration below.
+**Message Type:** You can choose : Text, Generated Value, Fixed Value, Random Byte Array (more detail below)
+
+![Alt text](images/Publisher_Text.png)
+
+*Encoding*
+
+**Message Format** : The type of encoding that you'll encode your data before publish .You can choose Binary Codec, Base64, BinHex or Plain Text
+If you choose Plain Text, you can choose 6 types of charsets : UTF-8, UTF-16, US-ASCII,UTF-16LE, UTF-16BE, ISO-8859-1.
+Of course, you can choose to no encoding too.
+
+*Option*
+
+**Add TimeStamp check box:** Add the timestamps to the message. The timestamps is 8 bytes
+**Add Number Sequence check box:** Add the number sequence to the message. Example: if you
+publish 100 messages in your session, the message is numbered from 0 to 99. The number sequence
+field in the message is 4 bytes.
+**Retained check box:** You publish the messages as retained messages or not. The retain flag for an
+MQTT message is set to false by default. This means that a broker will not hold onto the message
+so that any subscribers arriving after the message was sent will not see the message. By setting
+the retain flag, the message is held onto by the broker, so when the late arrivers connect to the
+broker or clients create a new subscription they get all the relevant retained messages”
+**Quality of service:** Three levels:
+0 : At most once
+1 : At least once
+2 : Exactly once
+Each message in MQTT can have its quality of service and retain flag set. The quality of service
+advises the code if and how it should ensure the message arrives. There are three options, 0 (At Most Once),
+1 (At Least Once) and 2 (Exactly Once). By default, a new message instance is set to "At Least Once",a Quality
+of Service (QoS) of 1, which means the sender will deliver the message at least once and, if there's no acknowledgement
+ of it, it will keep sending it with a duplicate flag set until an acknowledgement turns up, at which point the
+client removes the message from its persisted set of messages.
+A QoS of 0, "At Most Once", is the fastest mode, where the client doesn't wait for an
+acknowledgement. This means, of course, that if there’s a disconnection or server failure, a message
+may be lost. At the other end of the scale is a QoS of 2, "Exactly Once", which uses two pairs of
+exchanges, first to transfer the message and then to ensure only one copy has been received and is
+being processed. This does make Exactly Once the slower but most reliable QoS setting.
+
+With MQTT Publisher in Jmeter, three type of messages can be sent (Message Type):
+**Text:** The text message, without flag header and the server MQTT can deliver it like a normal
+text if you choose *No Encoding* or *Plain Text*.
+
+![Alt text](images/Publisher_Text.png)
+
+![Alt text](images/Receive.png)
+
+1 byte “flag header” for the messages of type: Generated value, Fixed value
+
+![Alt text](images/Flag_Header.png)
+In the flag header, if one field is set to 1, it means, we use the header in the message.
+For example: With this flag header
+
+![Alt text](images/Flag_Header_Example.png)
+It means that, in the message, we have :
+![Alt text](images/Message.png)
+
+**Generated Value:**
+The generated value can be of type: Integer, Long, Float, Double within the range [Min,Max] .
+The type of random can be: Pseudo random or Secure random. In the two cases, we can set the Seed
+for the generator.
+
+![Alt text](images/Publisher_generated_value.png)
+
+**Fixed Value:**
+The fixed value can be of type: Integer, Long, Float, Double, String within the range [Min,Max].
+
+![Alt text](images/Publisher_fixed_value.png)
+**Random Byte Array:**
+
+The data in form of random byte array with the size array as an input.
+For example, if you type 9 in the field size array, so without encoding, time header, number sequence, the message has 9 bytes of content(random data) and 1 byte of flag header
+and so, 10 bytes to publish.
+The images below show when you publish with option : One Connection Per Topic and the data is type of Random Byte Array.
+In the terminal,you see that there are two connections of 2 client Id : "Didier Donsez 0" and "Didier Donsez 1"
+
+![Alt text](images/One_connection_per_topic.png)
+
+![Alt text](images/Random_Byte_Array.png)
+
+
+For mesuring, thanks to Jmeter, we can add some listeners:
+
+![Alt text](images/Publisher_result.png)
+
+## MQTT Subscriber
+
+
+![Alt text](images/MQTT_Subscriber.png)
+
+
+
+*Name:* Name of the MQTT Subscriber
+*Comments:* Your comments
+*Provider URL:* The address of MQTT server
+*Client Id:* Your Id in the session
+*Topic:* The topic you want to subscribe.
+*Use Authorization :* Necessary in the case the connection need username and password
+*User:* your username
+*Password:* your password
+*Number of samples to aggregate:* In other way, the number of message you want to receive from
+the topic in one session
+*Time out (milliseconds):* Timeout for the connection to receive message from the topic
+
+![Alt text](images/Subscriber_result.png)
+
+
+![Alt text](images/Publisher_Subscriber.png)
+
+
+
+ Grenoble, France 14/03/2014,
+
+ ERODS Team
+
+ http://www.liglab.fr/erods?lang=fr&var_mode=calcul
+
+
diff --git a/images/Flag_Header.png b/images/Flag_Header.png
new file mode 100644
index 0000000..d7031c7
Binary files /dev/null and b/images/Flag_Header.png differ
diff --git a/images/Flag_Header_Example.png b/images/Flag_Header_Example.png
new file mode 100644
index 0000000..3263864
Binary files /dev/null and b/images/Flag_Header_Example.png differ
diff --git a/images/MQTT_Publisher.png b/images/MQTT_Publisher.png
new file mode 100644
index 0000000..396de6e
Binary files /dev/null and b/images/MQTT_Publisher.png differ
diff --git a/images/MQTT_Subscriber.png b/images/MQTT_Subscriber.png
new file mode 100644
index 0000000..6211e19
Binary files /dev/null and b/images/MQTT_Subscriber.png differ
diff --git a/images/Main_Interface_Jmeter.png b/images/Main_Interface_Jmeter.png
new file mode 100644
index 0000000..9172dad
Binary files /dev/null and b/images/Main_Interface_Jmeter.png differ
diff --git a/images/Message.png b/images/Message.png
new file mode 100644
index 0000000..b1fbd8c
Binary files /dev/null and b/images/Message.png differ
diff --git a/images/One_connection_per_topic.png b/images/One_connection_per_topic.png
new file mode 100644
index 0000000..240efdf
Binary files /dev/null and b/images/One_connection_per_topic.png differ
diff --git a/images/Publisher_Subscriber.png b/images/Publisher_Subscriber.png
new file mode 100644
index 0000000..ec64e8b
Binary files /dev/null and b/images/Publisher_Subscriber.png differ
diff --git a/images/Publisher_Text.png b/images/Publisher_Text.png
new file mode 100644
index 0000000..fffad13
Binary files /dev/null and b/images/Publisher_Text.png differ
diff --git a/images/Publisher_fixed_value.png b/images/Publisher_fixed_value.png
new file mode 100644
index 0000000..836c5e8
Binary files /dev/null and b/images/Publisher_fixed_value.png differ
diff --git a/images/Publisher_generated_value.png b/images/Publisher_generated_value.png
new file mode 100644
index 0000000..946210b
Binary files /dev/null and b/images/Publisher_generated_value.png differ
diff --git a/images/Publisher_result.png b/images/Publisher_result.png
new file mode 100644
index 0000000..f8feede
Binary files /dev/null and b/images/Publisher_result.png differ
diff --git a/images/Random_Byte_Array.png b/images/Random_Byte_Array.png
new file mode 100644
index 0000000..64eef3a
Binary files /dev/null and b/images/Random_Byte_Array.png differ
diff --git a/images/Receive.png b/images/Receive.png
new file mode 100644
index 0000000..e660dc7
Binary files /dev/null and b/images/Receive.png differ
diff --git a/images/Subscriber_result.png b/images/Subscriber_result.png
new file mode 100644
index 0000000..55e588f
Binary files /dev/null and b/images/Subscriber_result.png differ
diff --git a/libs/mqtt-websocket-java-1.0.1.jar b/libs/mqtt-websocket-java-1.0.1.jar
new file mode 100644
index 0000000..3541284
Binary files /dev/null and b/libs/mqtt-websocket-java-1.0.1.jar differ
diff --git a/libs/org.eclipse.paho.client.mqttv3-1.0.0.jar b/libs/org.eclipse.paho.client.mqttv3-1.0.0.jar
new file mode 100644
index 0000000..79e4413
Binary files /dev/null and b/libs/org.eclipse.paho.client.mqttv3-1.0.0.jar differ
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..ce94d46
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,90 @@
+
+
+
+ 4.0.0
+
+ winglet.jmeter.mqttws
+ mqttws-jmeter
+ 0.0.1-SNAPSHOT
+ Apache JMeter :: MQTT WS Sampler
+ MQTT Sampler with WebSockets support for Apache JMeter
+
+
+ 2.10
+
+
+
+
+ org.apache.jmeter
+ ApacheJMeter_core
+ ${jmeter-version}
+ provided
+
+
+
+ org.apache.jmeter
+ ApacheJMeter_java
+ ${jmeter-version}
+ provided
+
+
+
+ io.inventit.dev
+ mqtt-websocket-java
+ 1.0.1
+
+
+
+
+ ${project.artifactId}
+ install
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.5.1
+
+
+ 1.6
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 2.1
+
+
+ package
+
+ shade
+
+
+
+
+
+
+
+
diff --git a/ressource/messages.properties b/ressource/messages.properties
new file mode 100644
index 0000000..54c80ad
--- /dev/null
+++ b/ressource/messages.properties
@@ -0,0 +1,1378 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+# Warning: JMeterUtils.getResString() replaces space with '_'
+# and converts keys to lowercase before lookup
+# => All keys in this file must also be lower case or they won't match
+#
+
+# Please add new entries in alphabetical order
+
+about=About Apache JMeter
+active_threads_tooltip=Running threads
+add=Add
+add_from_clipboard=Add from Clipboard
+add_from_suggested_excludes=Add suggested Excludes
+add_as_child=Add as Child
+add_parameter=Add Variable
+add_pattern=Add Pattern\:
+add_test=Add Test
+add_user=Add User
+add_value=Add Value
+addtest=Add test
+aggregate_graph=Statistical Graphs
+aggregate_graph_choose_color=Choose color
+aggregate_graph_choose_foreground_color=Foreground color
+aggregate_graph_color_bar=Color\:
+aggregate_graph_column=Column\:
+aggregate_graph_column_selection=Column label selection\:
+aggregate_graph_column_settings=Column settings
+aggregate_graph_columns_to_display=Columns to display\:
+aggregate_graph_dimension=Graph size
+aggregate_graph_display=Display Graph
+aggregate_graph_draw_outlines=Draw outlines bar?
+aggregate_graph_dynamic_size=Dynamic graph size
+aggregate_graph_font=Font\:
+aggregate_graph_height=Height\:
+aggregate_graph_increment_scale=Increment scale\:
+aggregate_graph_legend=Legend
+aggregate_graph_legend.placement.bottom=Bottom
+aggregate_graph_legend.placement.left=Left
+aggregate_graph_legend.placement.right=Right
+aggregate_graph_legend.placement.top=Top
+aggregate_graph_legend_placement=Placement\:
+aggregate_graph_max_length_xaxis_label=Max length of x-axis label\:
+aggregate_graph_ms=Milliseconds
+aggregate_graph_no_values_to_graph=No values to graph
+aggregate_graph_number_grouping=Show number grouping?
+aggregate_graph_response_time=Response Time
+aggregate_graph_save=Save Graph
+aggregate_graph_save_table=Save Table Data
+aggregate_graph_save_table_header=Save Table Header
+aggregate_graph_size=Size\:
+aggregate_graph_style=Style\:
+aggregate_graph_sync_with_name=Synchronize with name
+aggregate_graph_tab_graph=Graph
+aggregate_graph_tab_settings=Settings
+aggregate_graph_title=Aggregate Graph
+aggregate_graph_title_group=Title
+aggregate_graph_use_group_name=Include group name in label?
+aggregate_graph_user_title=Graph title\:
+aggregate_graph_value_font=Value font\:
+aggregate_graph_value_labels_vertical=Value labels vertical?
+aggregate_graph_width=Width\:
+aggregate_graph_xaxis_group=X Axis
+aggregate_graph_yaxis_group=Y Axis (milli-seconds)
+aggregate_graph_yaxis_max_value=Scale maximum value\:
+aggregate_report=Aggregate Report
+aggregate_report_90=90%
+aggregate_report_90%_line=90% Line
+aggregate_report_bandwidth=KB/sec
+aggregate_report_count=# Samples
+aggregate_report_error=Error
+aggregate_report_error%=Error %
+aggregate_report_max=Max
+aggregate_report_median=Median
+aggregate_report_min=Min
+aggregate_report_rate=Throughput
+aggregate_report_stddev=Std. Dev.
+aggregate_report_total_label=TOTAL
+ajp_sampler_title=AJP/1.3 Sampler
+als_message=Note\: The Access Log Parser is generic in design and allows you to plugin
+als_message2=your own parser. To do so, implement the LogParser, add the jar to the
+als_message3=/lib directory and enter the class in the sampler.
+analyze=Analyze Data File...
+anchor_modifier_title=HTML Link Parser
+appearance=Look and Feel
+argument_must_not_be_negative=The Argument must not be negative\!
+arguments_panel_title=Command parameters
+assertion_assume_success=Ignore Status
+assertion_body_resp=Response Body
+assertion_code_resp=Response Code
+assertion_contains=Contains
+assertion_equals=Equals
+assertion_headers=Response Headers
+assertion_matches=Matches
+assertion_message_resp=Response Message
+assertion_network_size=Full Response
+assertion_not=Not
+assertion_pattern_match_rules=Pattern Matching Rules
+assertion_patterns_to_test=Patterns to Test
+assertion_resp_field=Response Field to Test
+assertion_resp_size_field=Response Size Field to Test
+assertion_substring=Substring
+assertion_text_document=Document (text)
+assertion_text_resp=Text Response
+assertion_textarea_label=Assertions\:
+assertion_title=Response Assertion
+assertion_url_samp=URL Sampled
+assertion_visualizer_title=Assertion Results
+attribute=Attribute
+attribute_field=Attribute\:
+attrs=Attributes
+auth_base_url=Base URL
+auth_manager_title=HTTP Authorization Manager
+auth_manager_options=Options
+auth_manager_clear_per_iter=Clear auth on each iteration?
+auths_stored=Authorizations Stored in the Authorization Manager
+average=Average
+average_bytes=Avg. Bytes
+bind=Thread Bind
+bouncy_castle_unavailable_message=The jars for bouncy castle are unavailable, please add them to your classpath.
+browse=Browse...
+bsf_sampler_title=BSF Sampler
+bsf_script=Script to run (variables: ctx vars props SampleResult sampler log Label FileName Parameters args[] OUT)
+bsf_script_file=Script file to run
+bsf_script_language=Scripting language\:
+bsf_script_parameters=Parameters to pass to script/file\:
+bsh_assertion_script=Script (see below for variables that are defined)
+bsh_assertion_script_variables=The following variables are defined for the script:\nRead/Write: Failure, FailureMessage, SampleResult, vars, props, log.\nReadOnly: Response[Data|Code|Message|Headers], RequestHeaders, SampleLabel, SamplerData, ctx
+bsh_assertion_title=BeanShell Assertion
+bsh_function_expression=Expression to evaluate
+bsh_sampler_title=BeanShell Sampler
+bsh_script=Script (see below for variables that are defined)
+bsh_script_file=Script file
+bsh_script_parameters=Parameters (-> String Parameters and String []bsh.args)
+bsh_script_reset_interpreter=Reset bsh.Interpreter before each call
+bsh_script_variables=The following variables are defined for the script\:\nSampleResult, ResponseCode, ResponseMessage, IsSuccess, Label, FileName, ctx, vars, props, log
+busy_testing=I'm busy testing, please stop the test before changing settings
+cache_manager_size=Max Number of elements in cache
+cache_manager_title=HTTP Cache Manager
+cache_session_id=Cache Session Id?
+cancel=Cancel
+cancel_exit_to_save=There are test items that have not been saved. Do you wish to save before exiting?
+cancel_new_from_template=There are test items that have not been saved. Do you wish to save before creating a test plan from selected template?
+cancel_new_to_save=There are test items that have not been saved. Do you wish to save before clearing the test plan?
+cancel_revert_project=There are test items that have not been saved. Do you wish to revert to the previously saved test plan?
+cssjquery_attribute=Attribute\:
+cssjquery_impl=CSS/JQuery implementation\:
+cssjquery_render_no_text=Data response result isn't text.
+cssjquery_tester_button_test=Test
+cssjquery_tester_field=Selector\:
+cssjquery_tester_title=CSS/JQuery Tester
+change_parent=Change Controller
+char_value=Unicode character number (decimal or 0xhex)
+check_return_code_title=Check Return Code
+choose_function=Choose a function
+choose_language=Choose Language
+clear=Clear
+clear_all=Clear All
+clear_cache_per_iter=Clear cache each iteration?
+clear_cookies_per_iter=Clear cookies each iteration?
+clipboard_node_read_error=An error occurred while copying node
+close=Close
+closeconnection=Close connection
+column_delete_disallowed=Deleting this column is not permitted
+column_number=Column number of CSV file | next | *alias
+command_config_box_title=Command to Execute
+command_config_std_streams_title=Standard streams (files)
+command_field_title=Command:
+compare=Compare
+comparefilt=Compare filter
+comparison_differ_content=Responses differ in content
+comparison_differ_time=Responses differ in response time by more than
+comparison_invalid_node=Invalid Node
+comparison_regex_string=Regex String
+comparison_regex_substitution=Substitution
+comparison_response_time=Response Time:
+comparison_unit=\ ms
+comparison_visualizer_title=Comparison Assertion Visualizer
+config_element=Config Element
+config_save_settings=Configure
+configure_wsdl=Configure
+confirm=Confirm
+constant_throughput_timer_memo=Add a delay between sampling to attain constant throughput
+constant_timer_delay=Thread Delay (in milliseconds)\:
+constant_timer_memo=Add a constant delay between sampling
+constant_timer_title=Constant Timer
+content_encoding=Content encoding\:
+controller=Controller
+cookie_implementation_choose=Implementation:
+cookie_manager_policy=Cookie Policy:
+cookie_manager_title=HTTP Cookie Manager
+cookie_options=Options
+cookies_stored=User-Defined Cookies
+copy=Copy
+counter_config_title=Counter
+counter_per_user=Track counter independently for each user
+counter_reset_per_tg_iteration=Reset counter on each Thread Group Iteration
+countlim=Size limit
+csvread_file_file_name=CSV file to get values from | *alias
+cut=Cut
+cut_paste_function=Copy and paste function string
+database_conn_pool_max_usage=Max Usage For Each Connection\:
+database_conn_pool_props=Database Connection Pool
+database_conn_pool_size=Number of Connections in Pool\:
+database_conn_pool_title=JDBC Database Connection Pool Defaults
+database_driver_class=Driver Class\:
+database_login_title=JDBC Database Login Defaults
+database_sql_query_string=SQL Query String\:
+database_sql_query_title=JDBC SQL Query Defaults
+database_testing_title=JDBC Request
+database_url=JDBC URL\:
+database_url_jdbc_props=Database URL and JDBC Driver
+ddn=DN
+de=German
+debug_off=Disable debug
+debug_on=Enable debug
+default_parameters=Default Parameters
+default_value_field=Default Value\:
+delay=Startup delay (seconds)
+delayed_start=Delay Thread creation until needed
+delete=Delete
+delete_parameter=Delete Variable
+delete_test=Delete Test
+delete_user=Delete User
+deltest=Deletion test
+deref=Dereference aliases
+description=Description
+detail=Detail
+directory_field_title=Working directory:
+disable=Disable
+distribution_graph_title=Distribution Graph (alpha)
+distribution_note1=The graph will update every 10 samples
+dn=DN
+domain=Domain
+done=Done
+down=Down
+duplicate=Duplicate
+duration=Duration (seconds)
+duration_assertion_duration_test=Duration to Assert
+duration_assertion_failure=The operation lasted too long\: It took {0} milliseconds, but should not have lasted longer than {1} milliseconds.
+duration_assertion_input_error=Please enter a valid positive integer.
+duration_assertion_label=Duration in milliseconds\:
+duration_assertion_title=Duration Assertion
+edit=Edit
+email_results_title=Email Results
+en=English
+enable=Enable
+encode?=Encode?
+encoded_value=URL Encoded Value
+endtime=End Time
+entry_dn=Entry DN
+entrydn=Entry DN
+environment_panel_title=Environment Variables
+eolbyte=End of line(EOL) byte value:
+error_indicator_tooltip=Show the number of errors in log, click to open Log Viewer panel
+error_loading_help=Error loading help page
+error_occurred=Error Occurred
+error_title=Error
+es=Spanish
+escape_html_string=String to escape
+eval_name_param=Text containing variable and function references
+evalvar_name_param=Name of variable
+example_data=Sample Data
+example_title=Example Sampler
+exit=Exit
+expand=Expand
+expected_return_code_title=Expected Return Code:
+expiration=Expiration
+expression_field=CSS/JQuery expression\:
+field_name=Field name
+file=File
+file_already_in_use=That file is already in use
+file_visualizer_append=Append to Existing Data File
+file_visualizer_auto_flush=Automatically Flush After Each Data Sample
+file_visualizer_browse=Browse...
+file_visualizer_close=Close
+file_visualizer_file_options=File Options
+file_visualizer_filename=Filename
+file_visualizer_flush=Flush
+file_visualizer_missing_filename=No output filename specified.
+file_visualizer_open=Open
+file_visualizer_output_file=Write results to file / Read from file
+file_visualizer_submit_data=Include Submitted Data
+file_visualizer_title=File Reporter
+file_visualizer_verbose=Verbose Output
+filename=File Name
+follow_redirects=Follow Redirects
+follow_redirects_auto=Redirect Automatically
+font.sansserif=Sans Serif
+font.serif=Serif
+fontstyle.bold=Bold
+fontstyle.italic=Italic
+fontstyle.normal=Normal
+foreach_controller_title=ForEach Controller
+foreach_end_index=End index for loop (inclusive)
+foreach_input=Input variable prefix
+foreach_output=Output variable name
+foreach_start_index=Start index for loop (exclusive)
+foreach_use_separator=Add "_" before number ?
+format=Number format
+fr=French
+ftp_binary_mode=Use Binary mode ?
+ftp_get=get(RETR)
+ftp_local_file=Local File:
+ftp_local_file_contents=Local File Contents:
+ftp_put=put(STOR)
+ftp_remote_file=Remote File:
+ftp_sample_title=FTP Request Defaults
+ftp_save_response_data=Save File in Response ?
+ftp_testing_title=FTP Request
+function_dialog_menu_item=Function Helper Dialog
+function_helper_title=Function Helper
+function_name_param=Name of variable in which to store the result (required)
+function_name_paropt=Name of variable in which to store the result (optional)
+function_params=Function Parameters
+functional_mode=Functional Test Mode (i.e. save Response Data and Sampler Data)
+functional_mode_explanation=Selecting Functional Test Mode may adversely affect performance.
+gaussian_timer_delay=Constant Delay Offset (in milliseconds)\:
+gaussian_timer_memo=Adds a random delay with a gaussian distribution
+gaussian_timer_range=Deviation (in milliseconds)\:
+gaussian_timer_title=Gaussian Random Timer
+generate=Generate
+generator=Name of Generator class
+generator_cnf_msg=Could not find the generator class. Please make sure you place your jar file in the /lib directory.
+generator_illegal_msg=Could not access the generator class due to IllegalAccessException.
+generator_instantiate_msg=Could not create an instance of the generator parser. Please make sure the generator implements Generator interface.
+get_xml_from_file=File with SOAP XML Data (overrides above text)
+get_xml_from_random=Message(s) Folder
+graph_apply_filter=Apply filter
+graph_choose_graphs=Graphs to Display
+graph_full_results_title=Graph Full Results
+graph_pointshape_circle=Circle
+graph_pointshape_diamond=Diamond
+graph_pointshape_square=Square
+graph_pointshape_triangle=Triangle
+graph_pointshape_none=None
+graph_resp_time_interval_label=Interval (ms):
+graph_resp_time_interval_reload=Apply interval
+graph_resp_time_not_enough_data=Unable to graph, not enough data
+graph_resp_time_series_selection=Sampler label selection:
+graph_resp_time_settings_line=Line settings
+graph_resp_time_settings_pane=Graph settings
+graph_resp_time_shape_label=Shape point:
+graph_resp_time_stroke_width=Stroke width:
+graph_resp_time_title=Response Time Graph
+graph_resp_time_title_label=Graph title:
+graph_resp_time_xaxis_time_format=Time format (SimpleDateFormat):
+graph_results_average=Average
+graph_results_data=Data
+graph_results_deviation=Deviation
+graph_results_latest_sample=Latest Sample
+graph_results_median=Median
+graph_results_ms=ms
+graph_results_no_samples=No of Samples
+graph_results_throughput=Throughput
+graph_results_title=Graph Results
+grouping_add_separators=Add separators between groups
+grouping_in_controllers=Put each group in a new controller
+grouping_in_transaction_controllers=Put each group in a new transaction controller
+grouping_mode=Grouping\:
+grouping_no_groups=Do not group samplers
+grouping_store_first_only=Store 1st sampler of each group only
+header_manager_title=HTTP Header Manager
+headers_stored=Headers Stored in the Header Manager
+heap_dump=Create a heap dump
+help=Help
+help_node=What's this node?
+html_assertion_file=Write JTidy report to file
+html_assertion_label=HTML Assertion
+html_assertion_title=HTML Assertion
+html_extractor_type=CSS/JQuery Extractor Implementation
+html_extractor_title=CSS/JQuery Extractor
+html_parameter_mask=HTML Parameter Mask (DEPRECATED)
+http_implementation=Implementation:
+http_response_code=HTTP response code
+http_url_rewriting_modifier_title=HTTP URL Re-writing Modifier
+http_user_parameter_modifier=HTTP User Parameter Modifier
+httpmirror_title=HTTP Mirror Server
+httpmirror_settings=Settings
+httpmirror_max_pool_size=Max number of Threads:
+httpmirror_max_queue_size=Max queue size:
+id_prefix=ID Prefix
+id_suffix=ID Suffix
+if_controller_evaluate_all=Evaluate for all children?
+if_controller_expression=Interpret Condition as Variable Expression?
+if_controller_label=Condition (default Javascript)
+if_controller_title=If Controller
+ignore_subcontrollers=Ignore sub-controller blocks
+include_controller=Include Controller
+include_equals=Include Equals?
+include_path=Include Test Plan
+increment=Increment
+infinite=Forever
+initial_context_factory=Initial Context Factory
+insert_after=Insert After
+insert_before=Insert Before
+insert_parent=Insert Parent
+interleave_control_title=Interleave Controller
+intsum_param_1=First int to add.
+intsum_param_2=Second int to add - further ints can be summed by adding further arguments.
+invalid_data=Invalid data
+invalid_mail=Error occurred sending the e-mail
+invalid_mail_address=One or more invalid e-mail addresses detected
+invalid_mail_server=Problem contacting the e-mail server (see JMeter log file)
+invalid_variables=Invalid variables
+iteration_counter_arg_1=TRUE, for each user to have own counter, FALSE for a global counter
+iterator_num=Loop Count\:
+ja=Japanese
+jar_file=Jar Files
+java_request=Java Request
+java_request_defaults=Java Request Defaults
+javascript_expression=JavaScript expression to evaluate
+jexl_expression=JEXL expression to evaluate
+############################################################ MQTT ############################################################
+mqtt_clean_session= Clean Session
+mqtt_suffix_length= Length
+mqtt_suffix_client_id= Random Suffix
+mqtt_publisher=MQTT Publisher
+mqtt_provider_url=Provider URL
+mqtt_topic=List topic
+mqtt_dest_setup=Setup
+mqtt_dest_setup_static=At startup
+mqtt_dest_setup_dynamic=Each sample
+mqtt_use_auth=Use Authorization?
+mqtt_user=User
+mqtt_pwd=Password
+mqtt_itertions=Number of samples to aggregate
+mqtt_config=Message source
+mqtt_use_file=From file
+mqtt_use_random_file=Random File from folder specified below
+mqtt_use_text=Textarea
+mqtt_message_type=Message Type
+mqtt_text_message=Text
+mqtt_map_message=Map Message
+mqtt_object_message=Object Message
+mqtt_bytes_message=Bytes Message
+mqtt_file=File
+mqtt_random_file=Random folder containing files ending with .dat for bytes messages, .txt or .obj for text and Object messages
+mqtt_auth_required=Required
+mqtt_text_area=Text Message
+mqtt_subscriber_title=MQTT Subscriber
+mqtt_durable_subscription_id=Durable Subscription ID
+mqtt_client_id=Client ID
+mqtt_read_response=Read Response
+mqtt_timeout=Timeout (milliseconds)
+mqtt_client_type=Client
+mqtt_stop_between_samples=Stop between samples?
+mqtt_subscriber_on_message=Use MessageListener.onMessage()
+mqtt_subscriber_receive=Use MessageConsumer.receive()
+mqtt_separator=Separator
+mqtt_use_time_stamp= Add TimeStamp
+mqtt_use_number_seq= Add Number Sequence
+mqtt_generated_value= Generated Value
+mqtt_fixed_value= Fixed Value
+mqtt_type_of_generated_value = Type of generated value
+mqtt_long_value = Long
+mqtt_int_value = Integer
+mqtt_double_value = Double
+mqtt_float_value = Float
+mqtt_string_value = String
+mqtt_type_of_fixed_value = Type of fixed value
+mqtt_min_value = Min
+mqtt_max_value = Max
+mqtt_value = Value
+mqtt_pseudo_random = Pseudo
+mqtt_secure_random = Secure
+mqtt_type_random = Type of random
+mqtt_seed_random = Seed
+mqtt_send_as_retained_msg = Retained
+mqtt_qos = Quality of service
+mqtt_extactly_once = Exactly once [2]
+mqtt_at_least_once = At least once [1]
+mqtt_at_most_once = At most once [0]
+mqtt_client_id= Client Id
+mqtt_plain_text= Plain Text
+mqtt_base64= Base64
+mqtt_binhex= BinHex
+mqtt_binary= Binary
+mqtt_message_format= Message Format
+mqtt_big_volume= Random Byte Array
+mqtt_size_array= Size Array
+mqtt_no_encoding= No Encoding
+mqtt_round_robin= Round Robin
+mqtt_random= Random
+mqtt_topic_choice= Strategy
+mqtt_connection_per_topic= One connection per topic
+################################################################################################################################
+
+jms_auth_required=Required
+jms_bytes_message=Bytes Message
+jms_client_caption=Receiver client uses MessageConsumer.receive() to listen for message.
+jms_client_caption2=MessageListener uses onMessage(Message) interface to listen for new messages.
+jms_client_id=Client ID
+jms_client_type=Client
+jms_communication_style=Communication style
+jms_concrete_connection_factory=Concrete Connection Factory
+jms_config=Message source
+jms_config_title=JMS Configuration
+jms_connection_factory=Connection Factory
+jms_correlation_title=Use alternate fields for message correlation
+jms_dest_setup=Setup
+jms_dest_setup_dynamic=Each sample
+jms_dest_setup_static=At startup
+jms_durable_subscription_id=Durable Subscription ID
+jms_file=File
+jms_initial_context_factory=Initial Context Factory
+jms_itertions=Number of samples to aggregate
+jms_jndi_defaults_title=JNDI Default Configuration
+jms_jndi_props=JNDI Properties
+jms_map_message=Map Message
+jms_message_title=Message properties
+jms_message_type=Message Type
+jms_msg_content=Content
+jms_object_message=Object Message
+jms_point_to_point=JMS Point-to-Point
+jms_properties=JMS Properties
+jms_properties_title=JMS Properties
+jms_properties_name=Name
+jms_properties_type=Class of value
+jms_properties_value=Value
+jms_props=JMS Properties
+jms_provider_url=Provider URL
+jms_publisher=JMS Publisher
+jms_pwd=Password
+jms_queue=Queue
+jms_queue_connection_factory=QueueConnection Factory
+jms_queueing=JMS Resources
+jms_random_file=Random folder containing files ending with .dat for bytes messages, .txt or .obj for text and Object messages
+jms_read_response=Read Response
+jms_receive_queue=JNDI name Receive queue
+jms_request=Request Only
+jms_requestreply=Request Response
+jms_sample_title=JMS Default Request
+jms_selector=JMS Selector
+jms_send_queue=JNDI name Request queue
+jms_separator=Separator
+jms_stop_between_samples=Stop between samples?
+jms_subscriber_on_message=Use MessageListener.onMessage()
+jms_subscriber_receive=Use MessageConsumer.receive()
+jms_subscriber_title=JMS Subscriber
+jms_testing_title=Messaging Request
+jms_text_area=Text Message or Object Message serialized to XML by XStream
+jms_text_message=Text Message
+jms_timeout=Timeout (milliseconds)
+jms_topic=Destination
+jms_use_auth=Use Authorization?
+jms_use_file=From file
+jms_use_non_persistent_delivery=Use non-persistent delivery mode?
+jms_use_properties_file=Use jndi.properties file
+jms_use_random_file=Random File from folder specified below
+jms_use_req_msgid_as_correlid=Use Request Message Id
+jms_use_res_msgid_as_correlid=Use Response Message Id
+jms_use_text=Textarea
+jms_user=User
+jndi_config_title=JNDI Configuration
+jndi_lookup_name=Remote Interface
+jndi_lookup_title=JNDI Lookup Configuration
+jndi_method_button_invoke=Invoke
+jndi_method_button_reflect=Reflect
+jndi_method_home_name=Home Method Name
+jndi_method_home_parms=Home Method Parameters
+jndi_method_name=Method Configuration
+jndi_method_remote_interface_list=Remote Interfaces
+jndi_method_remote_name=Remote Method Name
+jndi_method_remote_parms=Remote Method Parameters
+jndi_method_title=Remote Method Configuration
+jndi_testing_title=JNDI Request
+jndi_url_jndi_props=JNDI Properties
+junit_append_error=Append assertion errors
+junit_append_exception=Append runtime exceptions
+junit_constructor_error=Unable to create an instance of the class
+junit_constructor_string=Constructor String Label
+junit_create_instance_per_sample=Create a new instance per sample
+junit_do_setup_teardown=Do not call setUp and tearDown
+junit_error_code=Error Code
+junit_error_default_code=9999
+junit_error_default_msg=An unexpected error occured
+junit_error_msg=Error Message
+junit_failure_code=Failure Code
+junit_failure_default_code=0001
+junit_failure_default_msg=Test failed
+junit_failure_msg=Failure Message
+junit_junit4=Search for JUnit 4 annotations (instead of JUnit 3)
+junit_pkg_filter=Package Filter
+junit_request=JUnit Request
+junit_request_defaults=JUnit Request Defaults
+junit_success_code=Success Code
+junit_success_default_code=1000
+junit_success_default_msg=Test successful
+junit_success_msg=Success Message
+junit_test_config=JUnit Test Parameters
+junit_test_method=Test Method
+ldap_argument_list=LDAPArgument List
+ldap_connto=Connection timeout (in milliseconds)
+ldap_parse_results=Parse the search results ?
+ldap_sample_title=LDAP Request Defaults
+ldap_search_baseobject=Perform baseobject search
+ldap_search_onelevel=Perform onelevel search
+ldap_search_subtree=Perform subtree search
+ldap_secure=Use Secure LDAP Protocol ?
+ldap_testing_title=LDAP Request
+ldapext_sample_title=LDAP Extended Request Defaults
+ldapext_testing_title=LDAP Extended Request
+library=Library
+load=Load
+load_wsdl=Load WSDL
+log_errors_only=Errors
+log_file=Location of log File
+log_function_comment=Additional comment (optional)
+log_function_level=Log level (default INFO) or OUT or ERR
+log_function_string=String to be logged
+log_function_string_ret=String to be logged (and returned)
+log_function_throwable=Throwable text (optional)
+log_only=Log/Display Only:
+log_parser=Name of Log Parser class
+log_parser_cnf_msg=Could not find the class. Please make sure you place your jar file in the /lib directory.
+log_parser_illegal_msg=Could not access the class due to IllegalAccessException.
+log_parser_instantiate_msg=Could not create an instance of the log parser. Please make sure the parser implements LogParser interface.
+log_sampler=Tomcat Access Log Sampler
+log_success_only=Successes
+logic_controller_title=Simple Controller
+login_config=Login Configuration
+login_config_element=Login Config Element
+longsum_param_1=First long to add
+longsum_param_2=Second long to add - further longs can be summed by adding further arguments.
+loop_controller_title=Loop Controller
+looping_control=Looping Control
+lower_bound=Lower Bound
+mail_reader_account=Username:
+mail_reader_all_messages=All
+mail_reader_delete=Delete messages from the server
+mail_reader_folder=Folder:
+mail_reader_num_messages=Number of messages to retrieve:
+mail_reader_password=Password:
+mail_reader_port=Server Port (optional):
+mail_reader_server=Server Host:
+mail_reader_server_type=Protocol (e.g. pop3, imaps):
+mail_reader_storemime=Store the message using MIME (raw)
+mail_reader_title=Mail Reader Sampler
+mail_sent=Mail sent successfully
+mailer_addressees=Addressee(s):
+mailer_attributes_panel=Mailing attributes
+mailer_connection_security=Connection security:
+mailer_error=Couldn't send mail. Please correct any misentries.
+mailer_failure_limit=Failure Limit:
+mailer_failure_subject=Failure Subject:
+mailer_failures=Failures:
+mailer_from=From:
+mailer_host=Host:
+mailer_login=Login:
+mailer_msg_title_error=Error
+mailer_msg_title_information=Information
+mailer_password=Password:
+mailer_port=Port:
+mailer_string=E-Mail Notification
+mailer_success_limit=Success Limit:
+mailer_success_subject=Success Subject:
+mailer_test_mail=Test Mail
+mailer_title_message=Message
+mailer_title_settings=Mailer settings
+mailer_title_smtpserver=SMTP server
+mailer_visualizer_title=Mailer Visualizer
+match_num_field=Match No. (0 for Random)\:
+max=Maximum
+maximum_param=The maximum value allowed for a range of values
+md5hex_assertion_failure=Error asserting MD5 sum : got {0} but should have been {1}
+md5hex_assertion_label=MD5Hex
+md5hex_assertion_md5hex_test=MD5Hex to Assert
+md5hex_assertion_title=MD5Hex Assertion
+mechanism=Mechanism
+memory_cache=Memory Cache
+menu_assertions=Assertions
+menu_close=Close
+menu_collapse_all=Collapse All
+menu_config_element=Config Element
+menu_edit=Edit
+menu_expand_all=Expand All
+menu_fragments=Test Fragment
+menu_generative_controller=Sampler
+menu_listener=Listener
+menu_logic_controller=Logic Controller
+menu_logger_panel=Log Viewer
+menu_merge=Merge
+menu_modifiers=Modifiers
+menu_non_test_elements=Non-Test Elements
+menu_open=Open
+menu_post_processors=Post Processors
+menu_pre_processors=Pre Processors
+menu_response_based_modifiers=Response Based Modifiers
+menu_search=Search
+menu_search_reset=Reset Search
+menu_tables=Table
+menu_threads=Threads (Users)
+menu_timer=Timer
+menu_toolbar=Toolbar
+metadata=MetaData
+method=Method\:
+mimetype=Mimetype
+minimum_param=The minimum value allowed for a range of values
+minute=minute
+modddn=Old entry name
+modification_controller_title=Modification Controller
+modification_manager_title=Modification Manager
+modify_test=Modify Test
+modtest=Modification test
+module_controller_module_to_run=Module To Run
+module_controller_title=Module Controller
+module_controller_warning=Could not find module:
+monitor_equation_active=Active: (busy/max) > 25%
+monitor_equation_dead=Dead: no response
+monitor_equation_healthy=Healthy: (busy/max) < 25%
+monitor_equation_load=Load: ( (busy / max) * 50) + ( (used memory / max memory) * 50)
+monitor_equation_warning=Warning: (busy/max) > 67%
+monitor_health_tab_title=Health
+monitor_health_title=Monitor Results
+monitor_is_title=Use as Monitor
+monitor_label_left_bottom=0 %
+monitor_label_left_middle=50 %
+monitor_label_left_top=100 %
+monitor_label_prefix=Connection Prefix
+monitor_label_right_active=Active
+monitor_label_right_dead=Dead
+monitor_label_right_healthy=Healthy
+monitor_label_right_warning=Warning
+monitor_legend_health=Health
+monitor_legend_load=Load
+monitor_legend_memory_per=Memory % (used/total)
+monitor_legend_thread_per=Thread % (busy/max)
+monitor_load_factor_mem=50
+monitor_load_factor_thread=50
+monitor_performance_servers=Servers
+monitor_performance_tab_title=Performance
+monitor_performance_title=Performance Graph
+name=Name\:
+new=New
+newdn=New distinguished name
+next=Next
+no=Norwegian
+number_of_threads=Number of Threads (users)\:
+obsolete_test_element=This test element is obsolete
+once_only_controller_title=Once Only Controller
+opcode=opCode
+open=Open...
+option=Options
+optional_tasks=Optional Tasks
+paramtable=Send Parameters With the Request\:
+password=Password
+paste=Paste
+paste_insert=Paste As Insert
+path=Path\:
+path_extension_choice=Path Extension (use ";" as separator)
+path_extension_dont_use_equals=Do not use equals in path extension (Intershop Enfinity compatibility)
+path_extension_dont_use_questionmark=Do not use questionmark in path extension (Intershop Enfinity compatibility)
+patterns_to_exclude=URL Patterns to Exclude
+patterns_to_include=URL Patterns to Include
+pkcs12_desc=PKCS 12 Key (*.p12)
+pl=Polish
+poisson_timer_delay=Constant Delay Offset (in milliseconds)\:
+poisson_timer_memo=Adds a random delay with a poisson distribution
+poisson_timer_range=Lambda (in milliseconds)\:
+poisson_timer_title=Poisson Random Timer
+port=Port\:
+post_as_parameters=Parameters
+post_body=Body Data
+post_body_raw=Body Data
+post_thread_group_title=tearDown Thread Group
+previous=Previous
+property_as_field_label={0}\:
+property_default_param=Default value
+property_edit=Edit
+property_editor.value_is_invalid_message=The text you just entered is not a valid value for this property.\nThe property will be reverted to its previous value.
+property_editor.value_is_invalid_title=Invalid input
+property_name_param=Name of property
+property_returnvalue_param=Return Original Value of property (default false) ?
+#property_tool_tip={0}\: {1}
+property_tool_tip={0}
{1}
+property_undefined=Undefined
+property_value_param=Value of property
+property_visualiser_title=Property Display
+protocol=Protocol [http]\:
+protocol_java_border=Java class
+protocol_java_classname=Classname\:
+protocol_java_config_tile=Configure Java Sample
+protocol_java_test_title=Java Testing
+provider_url=Provider URL
+proxy_assertions=Add Assertions
+proxy_cl_error=If specifying a proxy server, host and port must be given
+proxy_content_type_exclude=Exclude\:
+proxy_content_type_filter=Content-type filter
+proxy_content_type_include=Include\:
+proxy_daemon_bind_error=Could not create script recording proxy - port in use. Choose another port.
+proxy_daemon_error=Could not create script recording proxy - see log for details
+proxy_daemon_error_from_clipboard=from clipboard
+proxy_daemon_error_not_retrieve=Could not add retrieve
+proxy_daemon_error_read_args=Could not add read arguments from clipboard\:
+proxy_daemon_msg_check_details=Please check the details below when installing the certificate in the browser
+proxy_daemon_msg_created_in_bin=created in JMeter bin directory
+proxy_daemon_msg_install_as_in_doc=You can install it following instructions in Component Reference documentation (see Installing the JMeter CA certificate for HTTPS recording paragraph)
+proxy_daemon_msg_rootca_cert=Root CA certificate\:
+proxy_domains=HTTPS Domains \:
+proxy_domains_dynamic_mode_tooltip=List of domain names for HTTPS url, ex. jmeter.apache.org or wildcard domain like *.apache.org. Use comma as separator.
+proxy_domains_dynamic_mode_tooltip_java6=To activate this field, use a Java 7+ runtime environment
+proxy_general_settings=Global Settings
+proxy_headers=Capture HTTP Headers
+proxy_regex=Regex matching
+proxy_sampler_settings=HTTP Sampler settings
+proxy_sampler_type=Type\:
+proxy_separators=Add Separators
+proxy_settings_port_error_digits=Only digits allowed
+proxy_settings_port_error_invalid_data=Invalid data
+proxy_target=Target Controller\:
+proxy_test_plan_content=Test plan content
+proxy_title=HTTP(S) Test Script Recorder
+pt_br=Portugese (Brazilian)
+ramp_up=Ramp-Up Period (in seconds)\:
+random_control_title=Random Controller
+random_order_control_title=Random Order Controller
+random_string_chars_to_use=Chars to use for random string generation
+random_string_length=Random string length
+read_response_message=Read response is not checked. To see the response, please check the box in the sampler.
+read_response_note=If read response is unchecked, the sampler will not read the response
+read_response_note2=or set the SampleResult. This improves performance, but it means
+read_response_note3=the response content won't be logged.
+read_soap_response=Read SOAP Response
+realm=Realm
+record_controller_title=Recording Controller
+ref_name_field=Reference Name\:
+regex_extractor_title=Regular Expression Extractor
+regex_field=Regular Expression\:
+regex_params_names_field=Parameter names regexp group number
+regex_params_values_field=Parameter values regex group number
+regex_params_ref_name_field=Regular Expression Reference Name
+regex_params_title=RegEx User Parameters
+regex_source=Response Field to check
+regex_src_body=Body
+regex_src_body_as_document=Body as a Document
+regex_src_body_unescaped=Body (unescaped)
+regex_src_hdrs=Headers
+regex_src_url=URL
+regexfunc_param_1=Regular expression used to search previous sample - or variable.
+regexfunc_param_2=Template for the replacement string, using groups from the regular expression. Format is $[group]$. Example $1$.
+regexfunc_param_3=Which match to use. An integer 1 or greater, RAND to indicate JMeter should randomly choose, A float, or ALL indicating all matches should be used ([1])
+regexfunc_param_4=Between text. If ALL is selected, the between text will be used to generate the results ([""])
+regexfunc_param_5=Default text. Used instead of the template if the regular expression finds no matches ([""])
+regexfunc_param_7=Input variable name containing the text to be parsed ([previous sample])
+regexp_render_no_text=Data response result isn't text.
+regexp_tester_button_test=Test
+regexp_tester_field=Regular expression\:
+regexp_tester_title=RegExp Tester
+remote_error_init=Error initialising remote server
+remote_error_starting=Error starting remote server
+remote_exit=Remote Exit
+remote_exit_all=Remote Exit All
+remote_shut=Remote Shutdown
+remote_shut_all=Remote Shutdown All
+remote_start=Remote Start
+remote_start_all=Remote Start All
+remote_stop=Remote Stop
+remote_stop_all=Remote Stop All
+remove=Remove
+remove_confirm_title=Confirm remove?
+remove_confirm_msg=Are you sure you want remove the selected element(s)?
+rename=Rename entry
+report=Report
+report_bar_chart=Bar Chart
+report_bar_graph_url=URL
+report_base_directory=Base Directory
+report_chart_caption=Chart Caption
+report_chart_x_axis=X Axis
+report_chart_x_axis_label=Label for X Axis
+report_chart_y_axis=Y Axis
+report_chart_y_axis_label=Label for Y Axis
+report_line_graph=Line Graph
+report_line_graph_urls=Include URLs
+report_output_directory=Output Directory for Report
+report_page=Report Page
+report_page_element=Page Element
+report_page_footer=Page Footer
+report_page_header=Page Header
+report_page_index=Create Page Index
+report_page_intro=Page Introduction
+report_page_style_url=Stylesheet url
+report_page_title=Page Title
+report_pie_chart=Pie Chart
+report_plan=Report Plan
+report_select=Select
+report_summary=Report Summary
+report_table=Report Table
+report_writer=Report Writer
+report_writer_html=HTML Report Writer
+request_data=Request Data
+reset_gui=Reset Gui
+response_save_as_md5=Save response as MD5 hash?
+restart=Restart
+resultaction_title=Result Status Action Handler
+resultsaver_addtimestamp=Add timestamp
+resultsaver_errors=Save Failed Responses only
+resultsaver_numberpadlen=Minumum Length of sequence number
+resultsaver_prefix=Filename prefix\:
+resultsaver_skipautonumber=Don't add number to prefix
+resultsaver_skipsuffix=Don't add suffix
+resultsaver_success=Save Successful Responses only
+resultsaver_title=Save Responses to a file
+resultsaver_variable=Variable Name:
+retobj=Return object
+return_code_config_box_title=Return Code Configuration
+reuseconnection=Re-use connection
+revert_project=Revert
+revert_project?=Revert project?
+root=Root
+root_title=Root
+run=Run
+running_test=Running test
+runtime_controller_title=Runtime Controller
+runtime_seconds=Runtime (seconds)
+sample_result_save_configuration=Sample Result Save Configuration
+sample_scope=Apply to:
+sample_scope_all=Main sample and sub-samples
+sample_scope_children=Sub-samples only
+sample_scope_parent=Main sample only
+sample_scope_variable=JMeter Variable
+sampler_label=Label
+sampler_on_error_action=Action to be taken after a Sampler error
+sampler_on_error_continue=Continue
+sampler_on_error_start_next_loop=Start Next Thread Loop
+sampler_on_error_stop_test=Stop Test
+sampler_on_error_stop_test_now=Stop Test Now
+sampler_on_error_stop_thread=Stop Thread
+save=Save
+save?=Save?
+save_all_as=Save Test Plan as
+save_as=Save Selection As...
+save_as_error=More than one item selected!
+save_as_test_fragment=Save as Test Fragment
+save_as_test_fragment_error=One of the selected nodes cannot be put inside a Test Fragment
+save_as_image=Save Node As Image
+save_as_image_all=Save Screen As Image
+save_assertionresultsfailuremessage=Save Assertion Failure Message
+save_assertions=Save Assertion Results (XML)
+save_asxml=Save As XML
+save_bytes=Save byte count
+save_code=Save Response Code
+save_datatype=Save Data Type
+save_encoding=Save Encoding
+save_fieldnames=Save Field Names (CSV)
+save_filename=Save Response Filename
+save_graphics=Save Graph
+save_hostname=Save Hostname
+save_idletime=Save Idle Time
+save_label=Save Label
+save_latency=Save Latency
+save_message=Save Response Message
+save_overwrite_existing_file=The selected file already exists, do you want to overwrite it?
+save_requestheaders=Save Request Headers (XML)
+save_responsedata=Save Response Data (XML)
+save_responseheaders=Save Response Headers (XML)
+save_samplecount=Save Sample and Error Counts
+save_samplerdata=Save Sampler Data (XML)
+save_subresults=Save Sub Results (XML)
+save_success=Save Success
+save_threadcounts=Save Active Thread Counts
+save_threadname=Save Thread Name
+save_time=Save Elapsed Time
+save_timestamp=Save Time Stamp
+save_url=Save URL
+save_workbench=Save WorkBench
+sbind=Single bind/unbind
+scheduler=Scheduler
+scheduler_configuration=Scheduler Configuration
+scope=Scope
+search_base=Search base
+search_filter=Search Filter
+search_test=Search Test
+search_text_button_close=Close
+search_text_button_find=Find
+search_text_button_next=Find next
+search_text_chkbox_case=Case sensitive
+search_text_chkbox_regexp=Regular exp.
+search_text_field=Search:
+search_text_msg_not_found=Text not found
+search_text_title_not_found=Not found
+search_tree_title=Search Tree
+search=Search
+search_expand=Search & Expand
+searchbase=Search base
+searchfilter=Search Filter
+searchtest=Search test
+second=second
+secure=Secure
+send_file=Send Files With the Request\:
+send_file_browse=Browse...
+send_file_filename_label=File Path\:
+send_file_mime_label=MIME Type\:
+send_file_param_name_label=Parameter Name\:
+server=Server Name or IP\:
+servername=Servername \:
+session_argument_name=Session Argument Name
+setup_thread_group_title=setUp Thread Group
+should_save=You should save your test plan before running it. \nIf you are using supporting data files (ie, for CSV Data Set or _StringFromFile), \nthen it is particularly important to first save your test script. \nDo you want to save your test plan first?
+shutdown=Shutdown
+simple_config_element=Simple Config Element
+simple_data_writer_title=Simple Data Writer
+size_assertion_comparator_error_equal=been equal to
+size_assertion_comparator_error_greater=been greater than
+size_assertion_comparator_error_greaterequal=been greater or equal to
+size_assertion_comparator_error_less=been less than
+size_assertion_comparator_error_lessequal=been less than or equal to
+size_assertion_comparator_error_notequal=not been equal to
+size_assertion_comparator_label=Type of Comparison
+size_assertion_failure=The result was the wrong size\: It was {0} bytes, but should have {1} {2} bytes.
+size_assertion_input_error=Please enter a valid positive integer.
+size_assertion_label=Size in bytes\:
+size_assertion_size_test=Size to Assert
+size_assertion_title=Size Assertion
+smime_assertion_issuer_dn=Issuer distinguished name
+smime_assertion_message_position=Execute assertion on message at position
+smime_assertion_not_signed=Message not signed
+smime_assertion_signature=Signature
+smime_assertion_signer=Signer certificate
+smime_assertion_signer_by_file=Certificate file
+smime_assertion_signer_constraints=Check values
+smime_assertion_signer_dn=Signer distinguished name
+smime_assertion_signer_email=Signer email address
+smime_assertion_signer_no_check=No check
+smime_assertion_signer_serial=Serial Number
+smime_assertion_title=SMIME Assertion
+smime_assertion_verify_signature=Verify signature
+smtp_additional_settings=Additional Settings
+smtp_attach_file=Attach file(s):
+smtp_attach_file_tooltip=Separate multiple files with ";"
+smtp_auth_settings=Auth settings
+smtp_bcc=Address To BCC:
+smtp_cc=Address To CC:
+smtp_default_port=(Defaults: SMTP:25, SSL:465, StartTLS:587)
+smtp_eml=Send .eml:
+smtp_enabledebug=Enable debug logging?
+smtp_enforcestarttls=Enforce StartTLS
+smtp_enforcestarttls_tooltip=Enforces the server to use StartTLS. If not selected and the SMTP-Server doesn't support StartTLS, a normal SMTP-Connection will be used as fallback instead. Please note that this checkbox creates a file in "/tmp/", so this will cause problems under windows.
+smtp_from=Address From:
+smtp_header_add=Add Header
+smtp_header_name=Header Name
+smtp_header_remove=Remove
+smtp_header_value=Header Value
+smtp_mail_settings=Mail settings
+smtp_message=Message:
+smtp_message_settings=Message settings
+smtp_messagesize=Calculate message size
+smtp_password=Password:
+smtp_plainbody=Send plain body (i.e. not multipart/mixed)
+smtp_replyto=Address Reply-To:
+smtp_sampler_title=SMTP Sampler
+smtp_security_settings=Security settings
+smtp_server=Server:
+smtp_server_port=Port:
+smtp_server_settings=Server settings
+smtp_subject=Subject:
+smtp_suppresssubj=Suppress Subject Header
+smtp_timestamp=Include timestamp in subject
+smtp_to=Address To:
+smtp_trustall=Trust all certificates
+smtp_trustall_tooltip=Enforces JMeter to trust all certificates, whatever CA it comes from.
+smtp_truststore=Local truststore:
+smtp_truststore_tooltip=The pathname of the truststore. Relative paths are resolved against the current directory. Failing that, against the directory containing the test script (JMX file)
+smtp_useauth=Use Auth
+smtp_usenone=Use no security features
+smtp_username=Username:
+smtp_usessl=Use SSL
+smtp_usestarttls=Use StartTLS
+smtp_usetruststore=Use local truststore
+smtp_usetruststore_tooltip=Allows JMeter to use a local truststore.
+soap_action=Soap Action
+soap_data_title=Soap/XML-RPC Data
+soap_sampler_title=SOAP/XML-RPC Request
+soap_send_action=Send SOAPAction:
+soap_sampler_file_invalid=Filename references a missing or unreadable file\:
+solinger=SO_LINGER:
+spline_visualizer_average=Average
+spline_visualizer_incoming=Incoming
+spline_visualizer_maximum=Maximum
+spline_visualizer_minimum=Minimum
+spline_visualizer_title=Spline Visualizer
+spline_visualizer_waitingmessage=Waiting for samples
+split_function_separator=String to split on. Default is , (comma).
+split_function_string=String to split
+ssl_alias_prompt=Please type your preferred alias
+ssl_alias_select=Select your alias for the test
+ssl_alias_title=Client Alias
+ssl_error_title=Key Store Problem
+ssl_pass_prompt=Please type your password
+ssl_pass_title=KeyStore Password
+ssl_port=SSL Port
+sslmanager=SSL Manager
+start=Start
+start_no_timers=Start no pauses
+starttime=Start Time
+stop=Stop
+stopping_test=Shutting down all test threads. You can see number of active threads in the upper right corner of GUI. Please be patient.
+stopping_test_failed=One or more test threads won't exit; see log file.
+stopping_test_host=Host
+stopping_test_title=Stopping Test
+string_from_file_encoding=File encoding if not the platform default (opt)
+string_from_file_file_name=Enter path (absolute or relative) to file
+string_from_file_seq_final=Final file sequence number (opt)
+string_from_file_seq_start=Start file sequence number (opt)
+summariser_title=Generate Summary Results
+summary_report=Summary Report
+switch_controller_label=Switch Value
+switch_controller_title=Switch Controller
+system_sampler_stderr=Standard error (stderr):
+system_sampler_stdin=Standard input (stdin):
+system_sampler_stdout=Standard output (stdout):
+system_sampler_title=OS Process Sampler
+table_visualizer_bytes=Bytes
+table_visualizer_latency=Latency
+table_visualizer_sample_num=Sample #
+table_visualizer_sample_time=Sample Time(ms)
+table_visualizer_start_time=Start Time
+table_visualizer_status=Status
+table_visualizer_success=Success
+table_visualizer_thread_name=Thread Name
+table_visualizer_warning=Warning
+target_server=Target Server
+tcp_classname=TCPClient classname\:
+tcp_config_title=TCP Sampler Config
+tcp_nodelay=Set NoDelay
+tcp_port=Port Number\:
+tcp_request_data=Text to send
+tcp_sample_title=TCP Sampler
+tcp_timeout=Timeout (milliseconds)\:
+teardown_on_shutdown=Run tearDown Thread Groups after shutdown of main threads
+template_choose=Select Template
+template_create_from=Create
+template_field=Template\:
+template_load?=Load template ?
+template_menu=Templates...
+template_merge_from=Merge
+template_reload=Reload templates
+template_title=Templates
+test=Test
+test_action_action=Action
+test_action_duration=Duration (milliseconds)
+test_action_pause=Pause
+test_action_restart_next_loop=Go to next loop iteration
+test_action_stop=Stop
+test_action_stop_now=Stop Now
+test_action_target=Target
+test_action_target_test=All Threads
+test_action_target_thread=Current Thread
+test_action_title=Test Action
+test_configuration=Test Configuration
+test_fragment_title=Test Fragment
+test_plan=Test Plan
+test_plan_classpath_browse=Add directory or jar to classpath
+testconfiguration=Test Configuration
+testplan.serialized=Run Thread Groups consecutively (i.e. run groups one at a time)
+testplan_comments=Comments\:
+testt=Test
+textbox_cancel=Cancel
+textbox_close=Close
+textbox_save_close=Save & Close
+textbox_title_edit=Edit text
+textbox_title_view=View text
+textbox_tooltip_cell=Double click to view/edit
+thread_delay_properties=Thread Delay Properties
+thread_group_title=Thread Group
+thread_properties=Thread Properties
+threadgroup=Thread Group
+throughput_control_bynumber_label=Total Executions
+throughput_control_bypercent_label=Percent Executions
+throughput_control_perthread_label=Per User
+throughput_control_title=Throughput Controller
+throughput_control_tplabel=Throughput
+time_format=Format string for SimpleDateFormat (optional)
+timelim=Time limit
+timeout_config_box_title=Timeout configuration
+timeout_title=Timeout (ms)
+toggle=Toggle
+toolbar_icon_set_not_found=The file description of toolbar icon set is not found. See logs.
+total_threads_tooltip=Total number of threads to run
+tr=Turkish
+transaction_controller_include_timers=Include duration of timer and pre-post processors in generated sample
+transaction_controller_parent=Generate parent sample
+transaction_controller_title=Transaction Controller
+unbind=Thread Unbind
+unescape_html_string=String to unescape
+unescape_string=String containing Java escapes
+uniform_timer_delay=Constant Delay Offset (in milliseconds)\:
+uniform_timer_memo=Adds a random delay with a uniform distribution
+uniform_timer_range=Random Delay Maximum (in milliseconds)\:
+uniform_timer_title=Uniform Random Timer
+up=Up
+update=Update
+update_per_iter=Update Once Per Iteration
+upload=File Upload
+upper_bound=Upper Bound
+url=URL
+url_config_get=GET
+url_config_http=HTTP
+url_config_https=HTTPS
+url_config_post=POST
+url_config_protocol=Protocol\:
+url_config_title=HTTP Request Defaults
+url_full_config_title=UrlFull Sample
+url_multipart_config_title=HTTP Multipart Request Defaults
+urldecode_string=String with URL encoded chars to decode
+urlencode_string=String to encode in URL encoded chars
+use_expires=Use Cache-Control/Expires header when processing GET requests
+use_keepalive=Use KeepAlive
+use_multipart_for_http_post=Use multipart/form-data for POST
+use_multipart_mode_browser=Browser-compatible headers
+use_recording_controller=Use Recording Controller
+user=User
+user_defined_test=User Defined Test
+user_defined_variables=User Defined Variables
+user_param_mod_help_note=(Do not change this. Instead, modify the file of that name in JMeter's /bin directory)
+user_parameters_table=Parameters
+user_parameters_title=User Parameters
+userdn=Username
+username=Username
+userpw=Password
+value=Value
+value_to_quote_meta=Value to escape from ORO Regexp meta chars
+var_name=Reference Name
+variable_name_param=Name of variable (may include variable and function references)
+view_graph_tree_title=View Graph Tree
+view_results_assertion_error=Assertion error:
+view_results_assertion_failure=Assertion failure:
+view_results_assertion_failure_message=Assertion failure message:
+view_results_autoscroll=Scroll automatically?
+view_results_childsamples=Child samples?
+view_results_desc=Shows the text results of sampling in tree form
+view_results_error_count=Error Count:
+view_results_fields=fields:
+view_results_in_table=View Results in Table
+view_results_latency=Latency:
+view_results_load_time=Load time:
+view_results_render=Render:
+view_results_render_document=Document
+view_results_render_html=HTML
+view_results_render_html_embedded=HTML (download resources)
+view_results_render_json=JSON
+view_results_render_text=Text
+view_results_render_xml=XML
+view_results_request_headers=Request Headers:
+view_results_response_code=Response code:
+view_results_response_headers=Response headers:
+view_results_response_message=Response message:
+view_results_response_missing_tika=Missing tika-app.jar in classpath. Unable to convert to plain text this kind of document.\nDownload the tika-app-x.x.jar file from http://tika.apache.org/download.html\nAnd put the file in /lib directory.
+view_results_response_partial_message=Start of message:
+view_results_response_too_large_message=Response too large to be displayed. Size:
+view_results_sample_count=Sample Count:
+view_results_sample_start=Sample Start:
+view_results_search_pane=Search pane
+view_results_size_body_in_bytes=Body size in bytes:
+view_results_size_headers_in_bytes=Headers size in bytes:
+view_results_size_in_bytes=Size in bytes:
+view_results_tab_assertion=Assertion result
+view_results_tab_request=Request
+view_results_tab_response=Response data
+view_results_tab_sampler=Sampler result
+view_results_table_fields_key=Additional field
+view_results_table_fields_value=Value
+view_results_table_headers_key=Response header
+view_results_table_headers_value=Value
+view_results_table_request_headers_key=Request header
+view_results_table_request_headers_value=Value
+view_results_table_request_http_cookie=Cookie
+view_results_table_request_http_host=Host
+view_results_table_request_http_method=Method
+view_results_table_request_http_nohttp=No HTTP Sample
+view_results_table_request_http_path=Path
+view_results_table_request_http_port=Port
+view_results_table_request_http_protocol=Protocol
+view_results_table_request_params_key=Parameter name
+view_results_table_request_params_value=Value
+view_results_table_request_raw_nodata=No data to display
+view_results_table_request_tab_http=HTTP
+view_results_table_request_tab_raw=Raw
+view_results_table_result_tab_parsed=Parsed
+view_results_table_result_tab_raw=Raw
+view_results_thread_name=Thread Name:
+view_results_title=View Results
+view_results_tree_title=View Results Tree
+warning=Warning!
+web_cannot_convert_parameters_to_raw=Cannot convert parameters to Body Data \nbecause one of the parameters has a name
+web_cannot_switch_tab=You cannot switch because data cannot be converted\n to target Tab data, empty data to switch
+web_parameters_lost_message=Switching to Body Data will convert the parameters.\nParameter table will be cleared when you select\nanother node or save the test plan.\nOK to proceeed?
+web_proxy_server_title=Proxy Server
+web_request=HTTP Request
+web_server=Web Server
+web_server_client=Client implementation:
+web_server_domain=Server Name or IP\:
+web_server_port=Port Number\:
+web_server_timeout_connect=Connect:
+web_server_timeout_response=Response:
+web_server_timeout_title=Timeouts (milliseconds)
+web_testing2_title=HTTP Request HTTPClient
+web_testing_concurrent_download=Use concurrent pool. Size:
+web_testing_embedded_url_pattern=URLs must match\:
+web_testing_retrieve_images=Retrieve All Embedded Resources
+web_testing_retrieve_title=Embedded Resources from HTML Files
+web_testing_source_ip=Source address
+web_testing_source_ip_hostname=IP/Hostname
+web_testing_source_ip_device=Device
+web_testing_source_ip_device_ipv4=Device IPv4
+web_testing_source_ip_device_ipv6=Device IPv6
+web_testing_title=HTTP Request
+webservice_configuration_wizard=WSDL helper
+webservice_get_xml_from_random_title=Use random messages SOAP
+webservice_maintain_session=Maintain HTTP Session
+webservice_message_soap=WebService message
+webservice_methods=Web Methods
+webservice_proxy_host=Proxy Host
+webservice_proxy_note=If Use HTTP Proxy is checked, but no host or port are provided, the sampler
+webservice_proxy_note2=will look at command line options. If no proxy host or port are provided by
+webservice_proxy_note3=either, it will fail silently.
+webservice_proxy_port=Proxy Port
+webservice_sampler_title=WebService(SOAP) Request (DEPRECATED)
+webservice_soap_action=SOAPAction
+webservice_timeout=Timeout:
+webservice_use_proxy=Use HTTP Proxy
+while_controller_label=Condition (function or variable)
+while_controller_title=While Controller
+workbench_title=WorkBench
+wsdl_helper_error=The WSDL was not valid, please double check the url.
+wsdl_url=WSDL URL
+wsdl_url_error=The WSDL was emtpy.
+xml_assertion_title=XML Assertion
+xml_download_dtds=Fetch external DTDs
+xml_namespace_button=Use Namespaces
+xml_tolerant_button=Use Tidy (tolerant parser)
+xml_validate_button=Validate XML
+xml_whitespace_button=Ignore Whitespace
+xmlschema_assertion_label=File Name:
+xmlschema_assertion_title=XML Schema Assertion
+xpath_assertion_button=Validate
+xpath_assertion_check=Check XPath Expression
+xpath_assertion_error=Error with XPath
+xpath_assertion_failed=Invalid XPath Expression
+xpath_assertion_label=XPath
+xpath_assertion_negate=True if nothing matches
+xpath_assertion_option=XML Parsing Options
+xpath_assertion_test=XPath Assertion
+xpath_assertion_tidy=Try and tidy up the input
+xpath_assertion_title=XPath Assertion
+xpath_assertion_valid=Valid XPath Expression
+xpath_assertion_validation=Validate the XML against the DTD
+xpath_assertion_whitespace=Ignore whitespace
+xpath_expression=XPath expression to match against
+xpath_extractor_fragment=Return entire XPath fragment instead of text content?
+xpath_extractor_query=XPath query:
+xpath_extractor_title=XPath Extractor
+xpath_file_file_name=XML file to get values from
+xpath_tester=XPath Tester
+xpath_tester_button_test=Test
+xpath_tester_field=XPath expression
+xpath_tester_fragment=Return entire XPath fragment instead of text content?
+xpath_tester_no_text=Data response result isn't text.
+xpath_tester_title=XPath Tester
+xpath_tidy_quiet=Quiet
+xpath_tidy_report_errors=Report errors
+xpath_tidy_show_warnings=Show warnings
+you_must_enter_a_valid_number=You must enter a valid number
+zh_cn=Chinese (Simplified)
+zh_tw=Chinese (Traditional)
diff --git a/sample-jmeter-testplans/mqtt.jmx b/sample-jmeter-testplans/mqtt.jmx
new file mode 100644
index 0000000..8d4b603
--- /dev/null
+++ b/sample-jmeter-testplans/mqtt.jmx
@@ -0,0 +1,204 @@
+
+
+
+
+
+ false
+ false
+
+
+
+
+
+
+
+ continue
+
+ false
+ 1
+
+ 1
+ 0
+ 1442389004000
+ 1442389004000
+ false
+
+
+
+
+
+ tcp://test.mosquitto.org:1883
+ /mitsos/
+ ewewew
+ ewewew
+ false
+ false
+
+ false
+ mqtt_round_robin
+ mqtt_at_most_once
+ false
+ ttytytytytyt
+ 100
+ 20000
+
+
+
+
+ haha
+
+ Assertion.response_data
+ false
+ 2
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+
+
+ continue
+
+ false
+ 1
+
+ 1
+ 6
+ 1442316565000
+ 1442316565000
+ false
+
+
+
+
+
+ tcp://test.mosquitto.org:1883
+ /mitsos/
+
+
+ hahaha
+ mqtt_text_message
+ 100
+ false
+ mqtt_at_most_once
+ false
+ mqtt_int_value
+
+ mqtt_pseudo_random
+
+
+ mqtt_int_value
+
+ true
+ false
+ qraftgst
+ mqtt_no_encoding
+ UTF-8
+
+ mqtt_round_robin
+ false
+ false
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+
+
+
diff --git a/script/TestPlan.tmpl.jmx b/script/TestPlan.tmpl.jmx
new file mode 100644
index 0000000..03d6cfa
--- /dev/null
+++ b/script/TestPlan.tmpl.jmx
@@ -0,0 +1,60 @@
+
+
+
+
+
+ false
+ false
+
+
+
+
+
+
+
+ continue
+
+ false
+ __LOOP_COUNT__
+
+ __NUMCLIENT__
+ __RAMP_TIME__
+ 1397652808000
+ 1397652808000
+ false
+
+
+
+
+
+ __URL__
+ __TOPIC__
+
+
+
+ mqtt_generated_value
+ __NUMBER_SAMPLE__
+ false
+ __QOS__
+ __RETAIN__
+ mqtt_int_value
+
+ mqtt_pseudo_random
+ 9999
+ 9
+ mqtt_float_value
+ 5
+ false
+ false
+ __CLIENT_ID__
+ mqtt_no_encoding
+ UTF-8
+
+ mqtt_round_robin
+ false
+
+
+
+
+
+
diff --git a/script/execute.sh b/script/execute.sh
new file mode 100644
index 0000000..f5648df
--- /dev/null
+++ b/script/execute.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+
+target="azureuser@10.0.0.7" # target of the test
+master="azureuser@10.0.0.4" # jmeter master of the test
+#Generate number of clients (number of connection for each test)
+i=0 # loop count number
+step=200 # step for number of clients
+for ((c=100;c<=10000;c=c+$step))
+do
+ ANUMCLIENT[$i]=$c;
+ i=$i+1;
+done
+
+# Quality of services
+AQOS=(0 1 2)
+ARETAIN=(true false)
+
+# Jmeter server (slave )
+JMETERSERVERS=10.0.0.5
+
+if [ ! -z "$JMETERSERVERS" ]
+then
+ REMOTE="-R $JMETERSERVERS"
+fi
+#----------------------------------Create Directory-----------------------------------------------#
+if [ -d ~/METRICS ]
+then
+ rm -r ~/METRICS
+fi
+ mkdir ~/METRICS ~/METRICS/CPU ~/METRICS/IO ~/METRICS/MEMO ~/METRICS/Logs ~/METRICS/Results ~/METRICS/Summarisers ~/METRICS/Summarisers/Total
+
+#------------------------------------Run The Test-------------------------------------------------#
+
+for NUMCLIENT in ${ANUMCLIENT[*]}
+do
+for QOS in ${AQOS[*]}
+do
+for RETAIN in ${ARETAIN[*]}
+do
+ SUFFIX=$NUMCLIENT.$QOS.$RETAIN
+ echo "running testplan.$SUFFIX.jmx"
+ # Start mesuring the metrics
+ ssh $target ./getmetrics.sh
+ #-------------------------------------------------/
+ ./../jmeter -n -t TestPlans/testplan.$SUFFIX.jmx -p specific.properties -l ~/METRICS/Results/result.$SUFFIX.jtl -j ~/METRICS/Logs/log.$SUFFIX.log $REMOTE
+ cat Logs/log.$SUFFIX.log | grep 'Summariser' > ~/METRICS/Summarisers/summariser.$SUFFIX.log
+ cat Logs/log.$SUFFIX.log | grep 'summary =' >> ~/METRICS/Summarisers/Total/total.$QOS.$RETAIN.log
+
+ #Stop mesuring load at the target and get the result to local machine
+
+ ssh $target ./stopgetmetrics.sh
+ scp $target:cpuload.log ~/METRICS/CPU/cpuload.$SUFFIX.log
+ scp $target:memo.log ~/METRICS/MEMO/memo.$SUFFIX.log
+ scp $target:io.log ~/METRICS/IO/io.$SUFFIX.log
+ #-------------------------------------------------/
+done
+done
+done
+
+#echo Please read 16.7 Reducing resource requirements http://jmeter.apache.org/usermanual/best-practices.html
+#echo Please read 2.4.3 2.4.7 http://jmeter.apache.org/usermanual/get-started.html
+#echo Please read http://jmeter.apache.org/usermanual/jmeter_distributed_testing_step_by_step.pdf
+# 2.4.3 Non-GUI Mode (Command Line mode)
+
+# For non-interactive testing, you may choose to run JMeter without the GUI. To do so, use the following command options:
+
+# -n This specifies JMeter is to run in non-gui mode
+# -t [name of JMX file that contains the Test Plan].
+# -l [name of JTL file to log sample results to].
+# -j [name of JMeter run log file].
+# -r Run the test in the servers specified by the JMeter property "remote_hosts"
+# -R [list of remote servers] Run the test in the specified remote servers
+
+# The script also lets you specify the optional firewall/proxy server information:
+
+# -H [proxy server hostname or ip address]
+# -P [proxy server port]
+
+# Example : jmeter -n -t my_test.jmx -l log.jtl -H my.proxy.server -P 8000
+
+# If the property jmeterengine.stopfail.system.exit is set to true (default is false), then JMeter will invoke System.exit(1) if it cannot stop all threads. Normally this is not necessary.
diff --git a/script/generate.sh b/script/generate.sh
new file mode 100644
index 0000000..c6f3e4c
--- /dev/null
+++ b/script/generate.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+client_id=$(hostname -I) #client id of publisher
+target="tcp:\/\/10.0.0.7:1883" # target for testing
+loop_count=1
+ramp_time=1
+number_sample=1
+i=0 # loop count number
+step=200 # step for number of clients
+for ((c=100;c<=10000;c=c+$step))
+do
+ ANUMCLIENT[$i]=$c;
+ i=$i+1;
+done
+AQOS=(0 1 2)
+ARETAIN=(true false)
+qos[0]=mqtt_at_most_once
+qos[1]=mqtt_at_least_once
+qos[2]=mqtt_extactly_once
+if [ -d "TestPlans" ]; then
+ rm -r TestPlans
+fi
+ mkdir TestPlans
+for NUMCLIENT in ${ANUMCLIENT[*]}
+do
+for QOS in ${AQOS[*]}
+do
+for RETAIN in ${ARETAIN[*]}
+do
+
+ SUFFIX=$NUMCLIENT.$QOS.$RETAIN
+ echo "generating testplan.$SUFFIX.jmx"
+ sed "s/__NUMCLIENT__/$NUMCLIENT/g" TestPlan.tmpl.jmx | sed "s/__QOS__/${qos[$QOS]}/g" | sed "s/__RETAIN__/$RETAIN/g" | sed "s/__RAMP_TIME__/$ramp_time/g" | sed "s/__LOOP_COUNT__/$loop_count/g" | sed "s/__NUMBER_SAMPLE__/$number_sample/g"| sed "s/__CLIENT_ID__/$client_id/g" | sed "s/__URL__/$target/g" > TestPlans/testplan.$SUFFIX.jmx
+done
+done
+done
diff --git a/script/getmetrics.sh b/script/getmetrics.sh
new file mode 100644
index 0000000..d204348
--- /dev/null
+++ b/script/getmetrics.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+sar -u 1 > cpuload.log &
+pid_cpu=$!
+echo $pid_cpu > pid_cpu.log
+sar -r 1 > memo.log &
+pid_memo=$!
+echo $pid_memo > pid_memo.log
+sar -b 1 > io.log &
+pid_io=$!
+echo $pid_io > pid_io.log
+echo "Getting metrics with process id : $pid_cpu $pid_memo $pid_io"
+
diff --git a/script/stopgetmetrics.sh b/script/stopgetmetrics.sh
new file mode 100644
index 0000000..c267365
--- /dev/null
+++ b/script/stopgetmetrics.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+pid_cpu=$(cat pid_cpu.log)
+kill $pid_cpu
+pid_memo=$(cat pid_memo.log)
+kill $pid_memo
+pid_io=$(cat pid_io.log)
+kill $pid_io
+echo "Killed getmetrics process whose pid $pid_cpu $pid_memo $pid_io"
+rm pid_cpu.log pid_memo.log pid_io.log
diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/client/MqttPublisher.java b/src/main/java/org/apache/jmeter/protocol/mqttws/client/MqttPublisher.java
new file mode 100644
index 0000000..faaf747
--- /dev/null
+++ b/src/main/java/org/apache/jmeter/protocol/mqttws/client/MqttPublisher.java
@@ -0,0 +1,383 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+
+ Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team
+
+*/
+
+package org.apache.jmeter.protocol.mqttws.client;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.Serializable;
+import java.net.URISyntaxException;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import java.util.Date;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+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.protocol.mqttws.control.gui.MQTTPublisherGui;
+import org.apache.jmeter.protocol.mqttws.control.gui.MQTTSubscriberGui;
+import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.threads.JMeterContext;
+import org.apache.jmeter.threads.JMeterContextService;
+import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
+import org.eclipse.paho.client.mqttv3.MqttCallback;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.eclipse.paho.client.mqttv3.MqttSecurityException;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.BinaryCodec;
+import org.apache.commons.codec.binary.Hex;
+
+
+
+
+import io.inventit.dev.mqtt.paho.MqttWebSocketAsyncClient;
+
+public class MqttPublisher extends AbstractJavaSamplerClient implements Serializable, MqttCallback {
+ private static final long serialVersionUID = 1L;
+ private MqttWebSocketAsyncClient client;
+ public static int numSeq=0;
+ public int quality = 0;
+ private AtomicInteger total = new AtomicInteger(0);
+ String myname = this.getClass().getName();
+
+
+
+ @Override
+ public Arguments getDefaultParameters() {
+ Arguments defaultParameters = new Arguments();
+ defaultParameters.addArgument("HOST", "tcp://localhost:1883");
+ defaultParameters.addArgument("CLIENT_ID", "${__time(YMDHMS)}${__threadNum}");
+ defaultParameters.addArgument("TOPIC", "TEST.MQTT");
+ defaultParameters.addArgument("AGGREGATE", "100");
+ defaultParameters.addArgument("DURABLE", "false");
+ return defaultParameters;
+ }
+
+ public void setupTest(JavaSamplerContext context){
+ //nothing yet
+ }
+
+ public void delayedSetupTest(JavaSamplerContext context){
+ System.out.println(myname + ">>>> in setupTest");
+ String host = context.getParameter("HOST");
+ String clientId = context.getParameter("CLIENT_ID");
+ if("TRUE".equalsIgnoreCase(context.getParameter("RANDOM_SUFFIX"))){
+ clientId= MqttPublisher.getClientId(clientId,Integer.parseInt(context.getParameter("SUFFIX_LENGTH")));
+ }
+ try {
+ System.out.println("Host: " + host + "clientID: " + clientId);
+ client = new MqttWebSocketAsyncClient(host, clientId, new MemoryPersistence());
+ } catch (MqttException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+
+ MqttConnectOptions options = new MqttConnectOptions();
+ options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
+ options.setCleanSession(true);
+ /*String user = context.getParameter("USER");
+ String pwd = context.getParameter("PASSWORD");
+ boolean durable = Boolean.parseBoolean(context.getParameter("DURABLE"));
+ options.setCleanSession(!durable);
+ if (user != null) {
+ options.setUserName(user);
+ if ( pwd!=null ) {
+ options.setPassword(pwd.toCharArray());
+ }
+ }
+ */
+ //TODO more options here
+ try {
+ client.connect(options);
+ int i=0;
+ if (!client.isConnected() && (i<5) ) {
+ try {
+ i++;
+ Thread.sleep(2000);
+ System.out.println(".");
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ } catch (MqttSecurityException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (MqttException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ client.setCallback(this);
+ }
+
+
+ public SampleResult runTest(JavaSamplerContext context) {
+ delayedSetupTest(context);
+ SampleResult result = new SampleResult();
+ result.setSampleLabel(context.getParameter("SAMPLER_NAME"));
+
+ if (!client.isConnected() ) {
+ System.out.println(myname + " >>>> Client is not connected - Aborting test");
+ result.setSuccessful(false);
+ return result;
+ }
+ result.sampleStart(); // start stopwatch
+ try {
+ produce(context);
+ } catch (Exception e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ //consider it a success if client gets connected
+ //in future we might add more criteria for this
+ if (client.isConnected() ) {
+ result.setResponseOK();
+ }
+ result.sampleEnd();
+ System.out.println(myname + ">>>> ending runTest");
+ return result;
+
+ }
+
+
+ public void close(JavaSamplerContext context) {
+
+
+ }
+
+ private static final String mycharset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ public static String getClientId(String clientPrefix, int suffixLength) {
+ Random rand = new Random(System.nanoTime()*System.currentTimeMillis());
+ StringBuilder sb = new StringBuilder();
+ sb.append(clientPrefix);
+ for (int i = 0; i < suffixLength; i++) {
+ int pos = rand.nextInt(mycharset.length());
+ sb.append(mycharset.charAt(pos));
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public void connectionLost(Throwable arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void deliveryComplete(IMqttDeliveryToken arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void messageArrived(String str, MqttMessage msg) throws Exception {
+ System.out.println("got message: " + new String(msg.getPayload()));
+ // TODO Auto-generated method stub
+
+ }
+
+
+private void produce(JavaSamplerContext context) throws Exception {
+
+ // ---------------------Type of message -------------------//
+
+ if ("FIXED".equals(context.getParameter("TYPE_MESSAGE"))) {
+ System.out.println("Fixed - TODO");
+ /*
+ produce(context.getParameter("MESSAGE"),
+ context.getParameter("TOPIC"),
+ Integer.parseInt(context.getParameter("AGGREGATE")),
+ context.getParameter("QOS"),
+ context.getParameter("RETAINED"),
+ context.getParameter("TIME_STAMP"),
+ context.getParameter("NUMBER_SEQUENCE"),
+ context.getParameter("TYPE_VALUE"),
+ context.getParameter("FORMAT"),
+ context.getParameter("CHARSET"),
+ context.getParameter("LIST_TOPIC"),
+ context.getParameter("STRATEGY"),
+ context.getParameter("PER_TOPIC"));
+*/
+ } else if ("RANDOM".equals(context.getParameter("TYPE_MESSAGE"))) {
+
+ System.out.println("Randomly - TODO");
+ /*produceRandomly(context.getParameter("SEED"),context.getParameter("MIN_RANDOM_VALUE"),
+ context.getParameter("MAX_RANDOM_VALUE"),context.getParameter("TYPE_RANDOM_VALUE"),
+ context.getParameter("TOPIC"),Integer.parseInt(context.getParameter("AGGREGATE")),
+ context.getParameter("QOS"),context.getParameter("RETAINED"),
+ context.getParameter("TIME_STAMP"),context.getParameter("NUMBER_SEQUENCE"),
+ context.getParameter("TYPE_VALUE"),
+ context.getParameter("FORMAT"),
+ context.getParameter("CHARSET"),
+ context.getParameter("LIST_TOPIC"),
+ context.getParameter("STRATEGY"),
+ context.getParameter("PER_TOPIC"));
+ */
+
+ } else if ("TEXT".equals(context.getParameter("TYPE_MESSAGE"))) {
+ produce(context.getParameter("MESSAGE"),
+ context.getParameter("TOPIC"),
+ Integer.parseInt(context.getParameter("AGGREGATE")),
+ context.getParameter("QOS"),
+ context.getParameter("RETAINED"),
+ context.getParameter("TIME_STAMP"),
+ context.getParameter("NUMBER_SEQUENCE"),
+ context.getParameter("TYPE_VALUE"),
+ context.getParameter("FORMAT"),
+ context.getParameter("CHARSET"),
+ //context.getParameter("LIST_TOPIC"),
+ "FALSE",
+ context.getParameter("STRATEGY"),
+ context.getParameter("PER_TOPIC"));
+ } else if("BYTE_ARRAY".equals(context.getParameter("TYPE_MESSAGE"))){
+ System.out.println("Byte Array - TODO");
+ /*
+ produceBigVolume(
+ context.getParameter("TOPIC"),
+ Integer.parseInt(context.getParameter("AGGREGATE")),
+ context.getParameter("QOS"),
+ context.getParameter("RETAINED"),
+ context.getParameter("TIME_STAMP"),
+ context.getParameter("NUMBER_SEQUENCE"),
+ context.getParameter("FORMAT"),
+ context.getParameter("CHARSET"),
+ context.getParameter("SIZE_ARRAY"),
+ context.getParameter("LIST_TOPIC"),
+ context.getParameter("STRATEGY"),
+ context.getParameter("PER_TOPIC"));
+ */
+ }
+
+ }
+
+
+
+
+
+
+
+ private void produce(String message, String topic, int aggregate,
+ String qos, String isRetained, String useTimeStamp, String useNumberSeq,String type_value, String format, String charset,String isListTopic,String strategy,String isPerTopic) throws Exception {
+ System.out.println(myname + ">>>> Starting publishing: ");
+ try {
+ // Quality
+ if (MQTTPublisherGui.EXACTLY_ONCE.equals(qos)) {
+ quality = 0;
+ } else if (MQTTPublisherGui.AT_LEAST_ONCE.equals(qos)) {
+ quality = 1;
+ } else if (MQTTPublisherGui.AT_MOST_ONCE.equals(qos)) {
+ quality = 2;
+ }
+ // Retained
+ boolean retained = false;
+ if ("TRUE".equals(isRetained))
+ retained = true;
+ //TODO send next one to GUI
+ boolean throttle = true;
+ // List topic
+ if("FALSE".equals(isListTopic)){
+ for (int i = 0; i < aggregate; ++i) {
+ byte[] payload = createPayload(message, useTimeStamp, useNumberSeq, type_value,format, charset);
+ //if (quality!=0) {
+ if (throttle) {
+ Thread.sleep(100);
+ }
+ this.client.publish(topic,payload,quality,retained);
+ System.out.print("*");
+ total.incrementAndGet();
+ }
+ System.out.println("");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ getLogger().warn(e.getLocalizedMessage(), e);
+ }
+ }
+
+ public byte[] createPayload(String message, String useTimeStamp, String useNumSeq ,String type_value, String format, String charset) throws IOException, NumberFormatException {
+ ByteArrayOutputStream b = new ByteArrayOutputStream();
+ DataOutputStream d = new DataOutputStream(b);
+// flags
+ byte flags=0x00;
+ if("TRUE".equals(useTimeStamp)) flags|=0x80;
+ if("TRUE".equals(useNumSeq)) flags|=0x40;
+ if (MQTTPublisherGui.INT.equals(type_value)) flags|=0x20;
+ if (MQTTPublisherGui.LONG.equals(type_value)) flags|=0x10;
+ if (MQTTPublisherGui.FLOAT.equals(type_value)) flags|=0x08;
+ if (MQTTPublisherGui.DOUBLE.equals(type_value)) flags|=0x04;
+ if (MQTTPublisherGui.STRING.equals(type_value)) flags|=0x02;
+ if(!"TEXT".equals(type_value)){
+ d.writeByte(flags);
+ }
+// TimeStamp
+ if("TRUE".equals(useTimeStamp)){
+ Date date= new java.util.Date();
+ d.writeLong(date.getTime());
+ }
+// Number Sequence
+ if("TRUE".equals(useNumSeq)){
+ d.writeInt(numSeq++);
+
+ }
+// Value
+ if (MQTTPublisherGui.INT.equals(type_value)) {
+ d.writeInt(Integer.parseInt(message));
+ } else if (MQTTPublisherGui.LONG.equals(type_value)) {
+ d.writeLong(Long.parseLong(message));
+ } else if (MQTTPublisherGui.DOUBLE.equals(type_value)) {
+ d.writeDouble(Double.parseDouble(message));
+ } else if (MQTTPublisherGui.FLOAT.equals(type_value)) {
+ d.writeDouble(Float.parseFloat(message));
+ } else if (MQTTPublisherGui.STRING.equals(type_value)) {
+ d.write(message.getBytes());
+ } else if ("TEXT".equals(type_value)) {
+ d.write(message.getBytes());
+ }
+
+// Format: Encoding
+ if(MQTTPublisherGui.BINARY.equals(format)){
+ BinaryCodec encoder= new BinaryCodec();
+ return encoder.encode(b.toByteArray());
+ } else if(MQTTPublisherGui.BASE64.equals(format)){
+ return Base64.encodeBase64(b.toByteArray());
+ } else if(MQTTPublisherGui.BINHEX.equals(format)){
+ Hex encoder= new Hex();
+ return encoder.encode(b.toByteArray());
+ } else if(MQTTPublisherGui.PLAIN_TEXT.equals(format)){
+ String s= new String (b.toByteArray(),charset);
+ return s.getBytes();
+
+ } else return b.toByteArray();
+ }
+
+
+}
diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/client/MqttSubscriber.java b/src/main/java/org/apache/jmeter/protocol/mqttws/client/MqttSubscriber.java
new file mode 100644
index 0000000..12d13d6
--- /dev/null
+++ b/src/main/java/org/apache/jmeter/protocol/mqttws/client/MqttSubscriber.java
@@ -0,0 +1,276 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+
+ Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team
+
+*/
+
+package org.apache.jmeter.protocol.mqttws.client;
+import java.io.Serializable;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Timer;
+import java.util.TimerTask;
+
+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.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
+import org.eclipse.paho.client.mqttv3.MqttCallback;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.eclipse.paho.client.mqttv3.MqttSecurityException;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+import io.inventit.dev.mqtt.paho.MqttWebSocketAsyncClient;
+
+public class MqttSubscriber extends AbstractJavaSamplerClient implements Serializable, MqttCallback {
+ private static final long serialVersionUID = 1L;
+ private MqttWebSocketAsyncClient client;
+ private List allmessages = new ArrayList();
+ private AtomicInteger nummsgs = new AtomicInteger(0);
+
+ static long msgs_aggregate = Long.MAX_VALUE;
+ static long timeout = 10000;
+
+ static String host ;
+ static String clientId ;
+
+ String myname = this.getClass().getName();
+
+
+ @Override
+ public Arguments getDefaultParameters() {
+ Arguments defaultParameters = new Arguments();
+ defaultParameters.addArgument("HOST", "tcp://localhost:1883");
+ defaultParameters.addArgument("CLIENT_ID", "${__time(YMDHMS)}${__threadNum}");
+ defaultParameters.addArgument("TOPIC", "TEST.MQTT");
+ defaultParameters.addArgument("AGGREGATE", "100");
+ defaultParameters.addArgument("DURABLE", "false");
+ return defaultParameters;
+ }
+
+ public void setupTest(JavaSamplerContext context){
+ //do nothing yet
+ }
+
+ public void delayedSetup(JavaSamplerContext context){
+ //System.out.println(myname + ">>>> in setupTest");
+ host = context.getParameter("HOST");
+ clientId = context.getParameter("CLIENT_ID");
+
+ if("TRUE".equalsIgnoreCase(context.getParameter("RANDOM_SUFFIX"))){
+ clientId= MqttPublisher.getClientId(clientId,Integer.parseInt(context.getParameter("SUFFIX_LENGTH")));
+ }
+ try {
+ System.out.println("Host: " + host + "clientID: " + clientId);
+ client = new MqttWebSocketAsyncClient(host, clientId, new MemoryPersistence());
+ //client = new MqttClient(host, clientId, new MemoryPersistence());
+ } catch (MqttException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ /*
+ //wait out for messages till TIMEOUT expires or aggregate msgs count if set
+ if (!context.getParameter("AGGREGATE").trim().equals("")) {
+ try {
+ msgs_aggregate = Long.parseLong(context.getParameter("AGGREGATE"));
+ } catch (NumberFormatException e) {
+ msgs_aggregate = Long.MAX_VALUE;
+ }
+ }
+ */
+ if ( !context.getParameter("AGGREGATE").equals("")) {
+ msgs_aggregate = Long.parseLong(context.getParameter("AGGREGATE"));
+ }
+ if ( !context.getParameter("TIMEOUT").equals("") ) {
+ timeout = Long.parseLong(context.getParameter("TIMEOUT"));
+ }
+
+ System.out.println("nummsgs: " + msgs_aggregate + " - timeout: " + timeout);
+
+ MqttConnectOptions options = new MqttConnectOptions();
+ options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
+ options.setCleanSession(true);
+ /*String user = context.getParameter("USER");
+ String pwd = context.getParameter("PASSWORD");
+ boolean durable = Boolean.parseBoolean(context.getParameter("DURABLE"));
+ options.setCleanSession(!durable);
+ if (user != null) {
+ options.setUserName(user);
+ if ( pwd!=null ) {
+ options.setPassword(pwd.toCharArray());
+ }
+ }
+ */
+ //TODO more options here
+ try {
+ client.connect(options);
+ int i=0;
+ if (!client.isConnected() && (i<5) ) {
+ try {
+ i++;
+ Thread.sleep(2000);
+ System.out.println(".");
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ } catch (MqttSecurityException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (MqttException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ client.setCallback(this);
+
+ }
+
+
+ private class EndTask extends TimerTask {
+ boolean timeup = false;
+ public void run() {
+ System.out.println("Time's up!");
+ timeup = true;
+ }
+ public boolean isTimeUp(){
+ return timeup;
+ }
+ }
+
+ @Override
+ public SampleResult runTest(JavaSamplerContext context) {
+ delayedSetup(context);
+ //System.out.println(myname + " >>>> in runtest");
+ SampleResult result = new SampleResult();
+ result.setSampleLabel(context.getParameter("SAMPLER_NAME"));
+
+
+ if (!client.isConnected() ) {
+ System.out.println(myname + " >>>> Client is not connected - Returning false");
+ result.setSuccessful(false);
+ return result;
+ }
+ result.sampleStart(); // start stopwatch
+ try {
+ System.out.println("Subscribing to topic: " + context.getParameter("TOPIC"));
+ client.subscribe(context.getParameter("TOPIC"), 0);
+ } catch (MqttException e) {
+ System.out.println("ohohohoh");
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ EndTask endtask = new EndTask();
+ Timer timer = new Timer();
+ timer.schedule( endtask, timeout);
+ while ( !endtask.isTimeUp() && nummsgs.get()>>> Stopping listening. Heard " + nummsgs.get() + " so far");
+ result.sampleEnd();
+ try {
+ StringBuilder allmsgs = new StringBuilder();
+ if ( !allmessages.isEmpty() ) {
+ for (String s : this.allmessages)
+ {
+ allmsgs.append(s + "\n");
+ }
+ result.setResponseMessage("Received " + allmessages.size() + " messages: \n" + allmsgs.toString() );
+ result.setResponseData(allmsgs.toString(),null);
+ } else {
+ result.setResponseMessage("No messages received");
+ result.setResponseCode("FAILED");
+ }
+ if ( msgs_aggregate != Long.MAX_VALUE) {
+ if ( nummsgs.get() >= msgs_aggregate ) {
+ result.setResponseOK();
+ }
+ else
+ result.setResponseCode("FAILED");
+ } else {
+ if (nummsgs.get()!=0) {
+ result.setResponseOK();
+ }
+ }
+ } catch (Exception e) {
+ result.sampleEnd(); // stop stopwatch
+ result.setSuccessful(false);
+ result.setResponseMessage("Exception: " + e);
+ // get stack trace as a String to return as document data
+ java.io.StringWriter stringWriter = new java.io.StringWriter();
+ e.printStackTrace( new java.io.PrintWriter(stringWriter) );
+ result.setResponseData(stringWriter.toString(), null);
+ result.setDataType(org.apache.jmeter.samplers.SampleResult.TEXT);
+ result.setResponseCode("FAILED");
+ }
+
+ System.out.println("ending runTest");
+ return result;
+ }
+
+
+ public void close(JavaSamplerContext context) {
+
+
+ }
+
+ private static final String mycharset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ public static String getClientId(String clientPrefix, int suffixLength) {
+ Random rand = new Random(System.nanoTime()*System.currentTimeMillis());
+ StringBuilder sb = new StringBuilder();
+ sb.append(clientPrefix);
+ for (int i = 0; i < suffixLength; i++) {
+ int pos = rand.nextInt(mycharset.length());
+ sb.append(mycharset.charAt(pos));
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public void connectionLost(Throwable arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void deliveryComplete(IMqttDeliveryToken arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void messageArrived(String str, MqttMessage msg) throws Exception {
+ nummsgs.incrementAndGet();
+ System.out.println("got message: " + new String(msg.getPayload()));
+ // TODO Auto-generated method stub
+ allmessages.add(new String(msg.getPayload()));
+ }
+}
diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/control/gui/MQTTPublisherGui.java b/src/main/java/org/apache/jmeter/protocol/mqttws/control/gui/MQTTPublisherGui.java
new file mode 100644
index 0000000..05b3a6a
--- /dev/null
+++ b/src/main/java/org/apache/jmeter/protocol/mqttws/control/gui/MQTTPublisherGui.java
@@ -0,0 +1,476 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+
+ Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team
+
+*/
+
+package org.apache.jmeter.protocol.mqttws.control.gui;
+import org.apache.jmeter.gui.util.JLabeledRadioI18N;
+import org.apache.jmeter.gui.util.JSyntaxTextArea;
+import org.apache.jmeter.gui.util.JTextScrollPane;
+import org.apache.jmeter.gui.util.VerticalPanel;
+import org.apache.jmeter.protocol.mqttws.sampler.PublisherSampler;
+import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.util.JMeterUtils;
+import org.apache.jorphan.gui.JLabeledPasswordField;
+import org.apache.jorphan.gui.JLabeledTextField;
+
+import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+
+/**
+ * @author Tuan Hiep
+ *
+ */
+public class MQTTPublisherGui extends AbstractSamplerGui implements
+ ChangeListener {
+
+ private static final long serialVersionUID = 240L;
+ /** Take source from the named file */
+ public static final String USE_FILE_RSC = "mqtt_use_file"; //$NON-NLS-1$
+ /** Take source from a random file */
+ public static final String USE_RANDOM_RSC = "mqtt_use_random_file"; //$NON-NLS-1$
+ /** Take source from the text area */
+ private static final String USE_TEXT_RSC = "mqtt_use_text"; //$NON-NLS-1$
+ /** Create a TextMessage */
+ public static final String TEXT_MSG_RSC = "mqtt_text_message"; //$NON-NLS-1$
+ /** Create a big volume message */
+ public static final String BIG_VOLUME = "mqtt_big_volume"; //$NON-NLS-1$
+ /** Create a MapMessage */
+ public static final String MAP_MSG_RSC = "mqtt_map_message"; //$NON-NLS-1$
+ /** Create an ObjectMessage */
+ public static final String OBJECT_MSG_RSC = "mqtt_object_message"; //$NON-NLS-1$
+ /** Create a BytesMessage */
+ public static final String BYTES_MSG_RSC = "mqtt_bytes_message"; //$NON-NLS-1$
+ /** Create a message of type long number */
+ public static final String LONG = "mqtt_long_value"; //$NON-NLS-1$
+ /** Create a Message of type integer number */
+ public static final String INT = "mqtt_int_value"; //$NON-NLS-1$
+ /** Create a Message of type double number */
+ public static final String DOUBLE = "mqtt_double_value"; //$NON-NLS-1$
+ /** Create a Message of type double number */
+ public static final String FLOAT = "mqtt_float_value"; //$NON-NLS-1$
+ /** Create a Message of type String */
+ public static final String STRING = "mqtt_string_value"; //$NON-NLS-1$
+
+ // These are the names of properties used to define the labels
+ private static final String DEST_SETUP_STATIC = "mqtt_dest_setup_static"; // $NON-NLS-1$
+ private static final String DEST_SETUP_DYNAMIC = "mqtt_dest_setup_dynamic"; // $NON-NLS-1$
+ public static final String GENERATED_VALUE = "mqtt_generated_value"; // $NON-NLS-1$
+ public static final String FIXED_VALUE = "mqtt_fixed_value";// $NON-NLS-1$
+ public static final String PSEUDO = "mqtt_pseudo_random";// $NON-NLS-1$
+ public static final String SECURE = "mqtt_secure_random";// $NON-NLS-1$
+ public static final String EXACTLY_ONCE = "mqtt_extactly_once";// $NON-NLS-1$
+ public static final String AT_LEAST_ONCE = "mqtt_at_least_once";// $NON-NLS-1$
+ public static final String AT_MOST_ONCE = "mqtt_at_most_once";// $NON-NLS-1$
+ public static final String PLAIN_TEXT = "mqtt_plain_text";// $NON-NLS-1$
+ public static final String BASE64 = "mqtt_base64";// $NON-NLS-1$
+ public static final String BINHEX = "mqtt_binhex";// $NON-NLS-1$
+ public static final String BINARY = "mqtt_binary";// $NON-NLS-1$
+ public static final String NO_ENCODING = "mqtt_no_encoding";// $NON-NLS-1$
+ public static final String ROUND_ROBIN = "mqtt_round_robin";// $NON-NLS-1$
+ public static final String RANDOM = "mqtt_random";// $NON-NLS-1$
+ // Button group resources
+ private static final String[] DEST_SETUP_ITEMS = { DEST_SETUP_STATIC,DEST_SETUP_DYNAMIC };
+ private final JLabeledRadioI18N destSetup = new JLabeledRadioI18N("mqtt_dest_setup", DEST_SETUP_ITEMS, DEST_SETUP_STATIC); // $NON-NLS-1$
+ private static final String[] MSGTYPES_ITEMS = { TEXT_MSG_RSC,GENERATED_VALUE,FIXED_VALUE,BIG_VOLUME };
+ private static final String[] TOPIC_CHOICES={ROUND_ROBIN,RANDOM};
+ private static final String[] MSGFORMAT_ITEMS = {NO_ENCODING,BINARY,BASE64,BINHEX,PLAIN_TEXT};
+ private static final String[] VALTYPES_ITEMS = { INT,LONG,FLOAT,DOUBLE};
+ private static final String[] FVALTYPES_ITEMS = {INT,LONG,FLOAT,DOUBLE,STRING};
+ private static final String[] RANTYPES_ITEMS = {PSEUDO,SECURE};
+ private static final String[] QTYPES_ITEMS = {AT_MOST_ONCE,AT_LEAST_ONCE,EXACTLY_ONCE};
+ private final JLabeledTextField urlField = new JLabeledTextField(JMeterUtils.getResString("mqtt_provider_url")); //$NON-NLS-1$
+ private final JLabeledTextField mqttDestination = new JLabeledTextField(JMeterUtils.getResString("mqtt_topic")); //$NON-NLS-1$
+ private final JCheckBox useAuth = new JCheckBox(JMeterUtils.getResString("mqtt_use_auth"), false); //$NON-NLS-1$
+ private final JLabeledTextField mqttUser = new JLabeledTextField(JMeterUtils.getResString("mqtt_user")); //$NON-NLS-1$
+ private final JLabeledTextField mqttPwd = new JLabeledPasswordField(JMeterUtils.getResString("mqtt_pwd")); //$NON-NLS-1$
+ private final JLabeledTextField iterations = new JLabeledTextField( JMeterUtils.getResString("mqtt_itertions")); //$NON-NLS-1$
+ private final JSyntaxTextArea textMessage = new JSyntaxTextArea(10, 50); // $NON-NLS-1$
+ private final JLabeledRadioI18N msgChoice = new JLabeledRadioI18N("mqtt_message_type", MSGTYPES_ITEMS, TEXT_MSG_RSC); //$NON-NLS-1$
+ private final JLabeledRadioI18N msgFormat = new JLabeledRadioI18N("mqtt_message_format", MSGFORMAT_ITEMS,NO_ENCODING); //$NON-NLS-1$
+ private final JLabeledRadioI18N topicChoice = new JLabeledRadioI18N("mqtt_topic_choice", TOPIC_CHOICES,ROUND_ROBIN); //$NON-NLS-1$
+ private final JCheckBox connectionPerTopic = new JCheckBox(JMeterUtils.getResString("mqtt_connection_per_topic"), false); // $NON-NLS-1$
+ private final JCheckBox suffixClientId = new JCheckBox(JMeterUtils.getResString("mqtt_suffix_client_id"),true); // $NON-NLS-1$
+ private final JLabeledTextField suffixLength = new JLabeledTextField(JMeterUtils.getResString("mqtt_suffix_length")); //$NON-NLS-1$
+ // For messages content
+ private final JCheckBox useTimeStamp = new JCheckBox(JMeterUtils.getResString("mqtt_use_time_stamp"), false); // $NON-NLS-1$
+ private final JCheckBox useNumberSeq = new JCheckBox(JMeterUtils.getResString("mqtt_use_number_seq"), false); // $NON-NLS-1$
+ private final JCheckBox isRetained = new JCheckBox(JMeterUtils.getResString("mqtt_send_as_retained_msg"), false); // $NON-NLS-1$
+ private final JLabeledRadioI18N typeQoSValue = new JLabeledRadioI18N("mqtt_qos", QTYPES_ITEMS,AT_MOST_ONCE); //$NON-NLS-1$
+ private final JLabeledRadioI18N typeGeneratedValue = new JLabeledRadioI18N("mqtt_type_of_generated_value", VALTYPES_ITEMS,INT); //$NON-NLS-1$
+ private final JLabeledRadioI18N typeFixedValue = new JLabeledRadioI18N("mqtt_type_of_fixed_value", FVALTYPES_ITEMS,INT); //$NON-NLS-1$
+ private final JLabeledTextField min = new JLabeledTextField(JMeterUtils.getResString("mqtt_min_value")); //$NON-NLS-1$
+ private final JLabeledTextField max = new JLabeledTextField(JMeterUtils.getResString("mqtt_max_value")); //$NON-NLS-1$
+ private final JLabeledTextField value = new JLabeledTextField(JMeterUtils.getResString("mqtt_value")); //$NON-NLS-1$
+ private final JLabeledRadioI18N typeRandom = new JLabeledRadioI18N("mqtt_type_random", RANTYPES_ITEMS,PSEUDO); //$NON-NLS-1$
+ private final JLabeledTextField seed = new JLabeledTextField(JMeterUtils.getResString("mqtt_seed_random")); //$NON-NLS-1$
+ private final JLabel textArea = new JLabel(JMeterUtils.getResString("mqtt_text_area"));
+ private final JTextScrollPane textPanel = new JTextScrollPane(textMessage);
+ private final JLabeledTextField clientId = new JLabeledTextField(JMeterUtils.getResString("mqtt_client_id")); //$NON-NLS-1$
+ private JComboBox CharsetChooser =new JComboBox(new String[] { "UTF-8", "UTF-16", "US-ASCII","UTF-16BE","UTF-16LE","ISO-8859-1"});
+ private final JLabeledTextField sizeArray = new JLabeledTextField(JMeterUtils.getResString("mqtt_size_array")); //$NON-NLS-1$
+ public MQTTPublisherGui() {
+ init();
+ }
+
+ private void init() {
+ setLayout(new BorderLayout());
+ setBorder(makeBorder());
+ add(makeTitlePanel(), BorderLayout.NORTH);
+ JPanel mainPanel = new VerticalPanel();
+ add(mainPanel, BorderLayout.CENTER);
+//-----------------------------------URL/CLIENT_ID---------------------------------------//
+ JPanel DPanel = new JPanel();
+ DPanel.setLayout(new BoxLayout(DPanel, BoxLayout.X_AXIS));
+ DPanel.add(urlField);
+ DPanel.add(clientId);
+ //DPanel.add(suffixClientId);
+ //DPanel.add(suffixLength);
+ JPanel ControlPanel = new VerticalPanel();
+ ControlPanel.add(DPanel);
+ ControlPanel.add(createDestinationPane());
+ ControlPanel.add(createAuthPane());
+ ControlPanel.add(iterations);
+ ControlPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray),"Connection Info"));
+ mainPanel.add(ControlPanel);
+//---------------------------------------Message Format----------------------------------//
+ JPanel FormatPanel = new JPanel();
+ FormatPanel.setLayout(new BoxLayout(FormatPanel, BoxLayout.X_AXIS));
+ msgFormat.setLayout(new BoxLayout(msgFormat, BoxLayout.X_AXIS));
+ FormatPanel.add(msgFormat);
+ Dimension minSize = new Dimension(10, 15);
+ Dimension prefSize = new Dimension(10, 15);
+ Dimension maxSize = new Dimension(Short.MAX_VALUE, 100);
+ FormatPanel.add(new Box.Filler(minSize, prefSize, maxSize));
+ FormatPanel.add(CharsetChooser);
+ JPanel EncodePanel = new VerticalPanel();
+ EncodePanel.add(FormatPanel);
+ EncodePanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray),"Encoding"));
+ mainPanel.add(EncodePanel);
+ JPanel StampPanel = new VerticalPanel();
+ StampPanel.add(useTimeStamp);
+ StampPanel.add(useNumberSeq);
+ StampPanel.add(isRetained);
+ typeQoSValue.setLayout(new BoxLayout(typeQoSValue, BoxLayout.X_AXIS));
+ StampPanel.add(this.typeQoSValue);
+ StampPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray),"Option"));
+ mainPanel.add(StampPanel);
+//--------------------------------------Message Type-------------------------------------//
+ JPanel ContentPanel = new VerticalPanel();
+ msgChoice.setLayout(new BoxLayout(msgChoice, BoxLayout.X_AXIS));
+ ContentPanel.add(msgChoice);
+ ContentPanel.add(sizeArray);
+
+//----------------------------------Fixed Value Panel------------------------------------//
+ JPanel FPanel = new JPanel();
+ typeFixedValue.setLayout(new BoxLayout(typeFixedValue, BoxLayout.Y_AXIS));
+ FPanel.add(typeFixedValue);
+ FPanel.add(value);
+ ContentPanel.add(FPanel);
+//----------------------------------Generated Value Panel--------------------------------//
+ JPanel GPanel = new JPanel();
+ typeGeneratedValue.setLayout(new BoxLayout(typeGeneratedValue, BoxLayout.Y_AXIS));
+ GPanel.add(typeGeneratedValue);
+ GPanel.add(min);
+ GPanel.add(max);
+ this.typeRandom.setLayout(new BoxLayout(typeRandom, BoxLayout.Y_AXIS));
+ GPanel.add(typeRandom);
+ GPanel.add(seed);
+ ContentPanel.add(GPanel);
+//---------------------------------Big Volume ------------------------------------------//
+
+ ContentPanel.add(sizeArray);
+//-------------------------------------Content Panel -----------------------------------//
+
+ JPanel messageContentPanel = new JPanel(new BorderLayout());
+ messageContentPanel.add(this.textArea, BorderLayout.NORTH);
+ messageContentPanel.add(this.textPanel,BorderLayout.CENTER);
+ ContentPanel.add(messageContentPanel);
+ ContentPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray),"Content"));
+ mainPanel.add(ContentPanel);
+ useAuth.addChangeListener(this);
+ msgChoice.addChangeListener(this);
+ typeFixedValue.addChangeListener(this);
+ typeQoSValue.addChangeListener(this);
+ typeRandom.addChangeListener(this);
+ msgFormat.addChangeListener(this);
+ suffixClientId.addChangeListener(this);
+
+ }
+
+ /**
+ *
+ * @return JPanel Panel with checkbox to choose user and password
+ */
+ private Component createAuthPane() {
+ JPanel panel = new JPanel();
+ panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
+ panel.add(useAuth);
+ panel.add(Box.createHorizontalStrut(10));
+ panel.add(mqttUser);
+ panel.add(Box.createHorizontalStrut(10));
+ panel.add(mqttPwd);
+ return panel;
+ }
+
+ /**
+ *
+ * @return JPanel that contains destination infos
+ */
+ private Component createDestinationPane() {
+ JPanel panel = new VerticalPanel(); //new BorderLayout(3, 0)
+ this.mqttDestination.setLayout((new BoxLayout(mqttDestination, BoxLayout.X_AXIS)));
+ panel.add(mqttDestination);
+ JPanel TPanel = new JPanel();
+ TPanel.setLayout(new BoxLayout(TPanel,BoxLayout.X_AXIS));
+ this.connectionPerTopic.setLayout(new BoxLayout(connectionPerTopic,BoxLayout.X_AXIS));
+ this.connectionPerTopic.setAlignmentX(CENTER_ALIGNMENT);
+ TPanel.add(connectionPerTopic);
+ TPanel.add(Box.createHorizontalStrut(100));
+ this.topicChoice.setLayout(new BoxLayout(topicChoice,BoxLayout.X_AXIS));
+ TPanel.add(topicChoice);
+ panel.add(TPanel);
+ return panel;
+ }
+
+ /**
+ * To Clear the GUI
+ */
+ @Override
+ public void clearGui() {
+ super.clearGui();
+ urlField.setText(""); // $NON-NLS-1$
+ mqttDestination.setText(""); // $NON-NLS-1$
+ mqttUser.setText(""); // $NON-NLS-1$
+ mqttPwd.setText(""); // $NON-NLS-1$
+ textMessage.setInitialText(""); // $NON-NLS-1$
+ msgChoice.setText(""); // $NON-NLS-1$
+ updateConfig(USE_TEXT_RSC);
+ msgChoice.setText(TEXT_MSG_RSC);
+ iterations.setText("1"); // $NON-NLS-1$
+ useAuth.setSelected(false);
+ mqttUser.setEnabled(false);
+ mqttPwd.setEnabled(false);
+ destSetup.setText(DEST_SETUP_STATIC);
+ textArea.setText("");
+ clientId.setText("");
+ connectionPerTopic.setSelected(false);
+
+
+ }
+
+ private void setupSamplerProperties(PublisherSampler sampler) {
+ this.configureTestElement(sampler);
+ sampler.setProviderUrl(urlField.getText());
+ sampler.setDestination(mqttDestination.getText());
+ sampler.setUsername(mqttUser.getText());
+ sampler.setPassword(mqttPwd.getText());
+ sampler.setTextMessage(textMessage.getText());
+ sampler.setMessageChoice(msgChoice.getText());
+ sampler.setIterations(iterations.getText());
+ sampler.setUseAuth(useAuth.isSelected());
+ sampler.setQuality(typeQoSValue.getText());
+ sampler.setRetained(isRetained.isSelected());
+ sampler.setTYPE_FIXED_VALUE(typeFixedValue.getText());
+ sampler.setFIXED_VALUE(this.value.getText());
+ sampler.setTYPE_RANDOM_VALUE(this.typeRandom.getText());
+ sampler.setMAX_RANDOM_VALUE(this.max.getText());
+ sampler.setMIN_RANDOM_VALUE(this.min.getText());
+ sampler.setTYPE_GENERATED_VALUE(this.typeGeneratedValue.getText());
+ sampler.setSEED(this.seed.getText());
+ sampler.setUSE_TIMESTAMP(useTimeStamp.isSelected());
+ sampler.setUSE_NUMBER_SEQUENCE(useNumberSeq.isSelected());
+ sampler.setCLIENT_ID(clientId.getText());
+ sampler.setFORMAT(msgFormat.getText());
+ sampler.setCHARSET((String) this.CharsetChooser.getSelectedItem());
+ sampler.setSIZE_ARRAY(this.sizeArray.getText());
+ sampler.setSTRATEGY(this.topicChoice.getText());
+ sampler.setOneConnectionPerTopic(this.connectionPerTopic.isSelected());
+ //we might need this in future
+ //sampler.setRandomSuffix(this.suffixClientId.isSelected());
+ sampler.setRandomSuffix(false);
+ sampler.setLength(this.suffixLength.getText());
+ }
+
+ /**
+ * the implementation loads the URL and the soap action for the request.
+ */
+ @Override
+ public void configure(TestElement el) {
+ super.configure(el);
+ PublisherSampler sampler = (PublisherSampler) el;
+ urlField.setText(sampler.getProviderUrl());
+ mqttDestination.setText(sampler.getDestination());
+ mqttUser.setText(sampler.getUsername());
+ mqttPwd.setText(sampler.getPassword());
+ textMessage.setInitialText(sampler.getTextMessage());
+ textMessage.setCaretPosition(0);
+ clientId.setText(sampler.getCLIENT_ID());
+ connectionPerTopic.setSelected(sampler.isOneConnectionPerTopic());
+ msgChoice.setText(sampler.getMessageChoice());
+ iterations.setText(sampler.getIterations());
+ useAuth.setSelected(sampler.isUseAuth());
+ mqttUser.setEnabled(useAuth.isSelected());
+ mqttPwd.setEnabled(useAuth.isSelected());
+ updateChoice(msgChoice.getText());
+ updateChoice(msgFormat.getText());
+ updateChoice("Suffix=" + String.valueOf(this.suffixClientId.isSelected()));
+
+ }
+
+ @Override
+ public TestElement createTestElement() {
+ PublisherSampler sampler = new PublisherSampler();
+ setupSamplerProperties(sampler);
+ return sampler;
+ }
+ /**
+ * To Update the parameter of field in the GUI
+ *
+ * @param command
+ */
+
+ private void updateConfig(String command) {
+
+ if (command.equals(USE_TEXT_RSC)) {
+ textMessage.setEnabled(true);
+
+ }
+
+ }
+
+ @Override
+ public String getLabelResource() {
+ return "mqtt_publisher"; //$NON-NLS-1$
+ }
+
+ @Override
+ public void modifyTestElement(TestElement s) {
+ PublisherSampler sampler = (PublisherSampler) s;
+ setupSamplerProperties(sampler);
+ }
+
+ /**
+ * When we change some parameter by clicking on the GUI
+ */
+ @Override
+ public void stateChanged(ChangeEvent event) {
+
+
+ if (event.getSource() == msgChoice) {
+ updateChoice(msgChoice.getText());
+ } else if (event.getSource() == useAuth) {
+ mqttUser.setEnabled(useAuth.isSelected());
+ mqttPwd.setEnabled(useAuth.isSelected());
+ }
+ else if (event.getSource()==msgFormat){
+ updateChoice(msgFormat.getText());
+ }
+ else if(event.getSource()==suffixClientId){
+ updateChoice("Suffix="+String.valueOf(this.suffixClientId.isSelected()));
+ }
+ }
+
+ /**
+ * To Update the choice of message to send
+ *
+ * @param command
+ */
+ private void updateChoice(String command) {
+
+ if(TEXT_MSG_RSC.equals(command)){
+ this.typeGeneratedValue.setVisible(false);
+ this.typeFixedValue.setVisible(false);
+ this.max.setVisible(false);
+ this.min.setVisible(false);
+ this.value.setVisible(false);
+ this.typeRandom.setVisible(false);
+ this.seed.setVisible(false);
+ this.textArea.setVisible(true);
+ this.textPanel.setVisible(true);
+ this.sizeArray.setVisible(false); }
+ else if(GENERATED_VALUE.equals(command)) {
+ this.typeFixedValue.setVisible(false);
+ this.value.setVisible(false);
+ this.textArea.setVisible(false);
+ this.textPanel.setVisible(false);
+ this.typeGeneratedValue.setVisible(true);
+ this.max.setVisible(true);
+ this.min.setVisible(true);
+ this.typeRandom.setVisible(true);
+ this.seed.setVisible(true);
+ this.sizeArray.setVisible(false);
+ } else if(FIXED_VALUE.equals(command)){
+ this.typeGeneratedValue.setVisible(false);
+ this.typeFixedValue.setVisible(true);
+ this.max.setVisible(false);
+ this.min.setVisible(false);
+ this.value.setVisible(true);
+ this.typeRandom.setVisible(false);
+ this.seed.setVisible(false);
+ this.textArea.setVisible(false);
+ this.textPanel.setVisible(false);
+ this.sizeArray.setVisible(false); }
+ else if(BIG_VOLUME.equals(command)){
+ this.typeGeneratedValue.setVisible(false);
+ this.typeFixedValue.setVisible(false);
+ this.max.setVisible(false);
+ this.min.setVisible(false);
+ this.value.setVisible(false);
+ this.typeRandom.setVisible(false);
+ this.seed.setVisible(false);
+ this.textArea.setVisible(false);
+ this.textPanel.setVisible(false);
+ this.sizeArray.setVisible(true);
+ }
+ else if(BINARY.equals(command)){
+ this.CharsetChooser.setVisible(false);
+ }
+ else if(BINHEX.equals(command)){
+ this.CharsetChooser.setVisible(false);
+ }
+ else if(BASE64.equals(command)){
+ this.CharsetChooser.setVisible(false);
+ }
+ else if(PLAIN_TEXT.equals(command)){
+ this.CharsetChooser.setVisible(true);
+ }
+ else if(NO_ENCODING.equals(command)){
+ this.CharsetChooser.setVisible(false);
+ }
+ else if("suffix=true".equalsIgnoreCase(command)){
+ this.suffixLength.setVisible(true);
+
+ }
+ else if("suffix=false".equalsIgnoreCase(command)){
+ this.suffixLength.setVisible(false);
+ }
+ validate();
+ }
+
+}
+
\ No newline at end of file
diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/control/gui/MQTTSubscriberGui.java b/src/main/java/org/apache/jmeter/protocol/mqttws/control/gui/MQTTSubscriberGui.java
new file mode 100644
index 0000000..4300729
--- /dev/null
+++ b/src/main/java/org/apache/jmeter/protocol/mqttws/control/gui/MQTTSubscriberGui.java
@@ -0,0 +1,247 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+
+ Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team
+
+*/
+
+package org.apache.jmeter.protocol.mqttws.control.gui;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.apache.jmeter.gui.util.JLabeledRadioI18N;
+import org.apache.jmeter.gui.util.VerticalPanel;
+import org.apache.jmeter.protocol.mqttws.sampler.SubscriberSampler;
+import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.util.JMeterUtils;
+import org.apache.jorphan.gui.JLabeledPasswordField;
+import org.apache.jorphan.gui.JLabeledTextField;
+
+/**
+ * This is the GUI for mqtt Subscriber
+ *
+ */
+public class MQTTSubscriberGui extends AbstractSamplerGui implements ChangeListener {
+
+ private static final long serialVersionUID = 240L;
+ public static final String AT_MOST_ONCE = "mqtt_at_most_once";// $NON-NLS-1$
+ public static final String EXACTLY_ONCE = "mqtt_extactly_once";// $NON-NLS-1$
+ public static final String AT_LEAST_ONCE = "mqtt_at_least_once";// $NON-NLS-1$
+ private static final String[] QTYPES_ITEMS = {AT_MOST_ONCE,AT_LEAST_ONCE,EXACTLY_ONCE};
+ public static final String ROUND_ROBIN = "mqtt_round_robin";// $NON-NLS-1$
+ public static final String RANDOM = "mqtt_random";// $NON-NLS-1$
+ private static final String[] TOPIC_CHOICES={ROUND_ROBIN,RANDOM};
+ private final JLabeledTextField urlField = new JLabeledTextField(JMeterUtils.getResString("mqtt_provider_url")); // $NON-NLS-1$
+ private final JLabeledTextField mqttDestination = new JLabeledTextField(JMeterUtils.getResString("mqtt_topic")); // $NON-NLS-1$
+ private final JLabeledTextField mqttUser = new JLabeledTextField(JMeterUtils.getResString("mqtt_user")); // $NON-NLS-1$
+ private final JLabeledTextField mqttPwd = new JLabeledPasswordField(JMeterUtils.getResString("mqtt_pwd")); // $NON-NLS-1$
+ private final JCheckBox useAuth = new JCheckBox(JMeterUtils.getResString("mqtt_use_auth"), false); //$NON-NLS-1$
+ private final JLabeledTextField timeout = new JLabeledTextField(JMeterUtils.getResString("mqtt_timeout")); //$NON-NLS-1$
+ private final JLabeledTextField separator = new JLabeledTextField(JMeterUtils.getResString("mqtt_separator")); //$NON-NLS-1$
+ private final JCheckBox suffixClientId = new JCheckBox(JMeterUtils.getResString("mqtt_suffix_client_id"),true); // $NON-NLS-1$
+ private final JLabeledTextField suffixLength = new JLabeledTextField(JMeterUtils.getResString("mqtt_suffix_length")); //$NON-NLS-1$
+ private final JCheckBox connectionPerTopic = new JCheckBox(JMeterUtils.getResString("mqtt_connection_per_topic"), false); // $NON-NLS-1$
+ private final JLabeledRadioI18N topicChoice = new JLabeledRadioI18N("mqtt_topic_choice", TOPIC_CHOICES,ROUND_ROBIN); //$NON-NLS-1$
+ private final JCheckBox stopBetweenSamples = new JCheckBox(JMeterUtils.getResString("mqtt_stop_between_samples"), true); // $NON-NLS-1$
+ private final JLabeledTextField clientId = new JLabeledTextField(JMeterUtils.getResString("mqtt_client_id")); //$NON-NLS-1$
+ private final JLabeledRadioI18N typeQoSValue = new JLabeledRadioI18N("mqtt_qos", QTYPES_ITEMS,AT_MOST_ONCE); //$NON-NLS-1$
+ private final JCheckBox cleanSession = new JCheckBox(JMeterUtils.getResString("mqtt_clean_session"), false); // $NON-NLS-1$
+ private final JLabeledTextField iterations = new JLabeledTextField( JMeterUtils.getResString("mqtt_itertions")); //$NON-NLS-1$
+
+ public MQTTSubscriberGui() {
+ init();
+ }
+
+ @Override
+ public String getLabelResource() {
+ return "mqtt_subscriber_title"; // $NON-NLS-1$
+ }
+
+ /**
+ * @see org.apache.jmeter.gui.JMeterGUIComponent#createTestElement()
+ */
+ @Override
+ public TestElement createTestElement() {
+ SubscriberSampler sampler = new SubscriberSampler();
+ modifyTestElement(sampler);
+ return sampler;
+ }
+
+ /**
+ * Modifies a given TestElement to mirror the data in the gui components.
+ *
+ * @see org.apache.jmeter.gui.JMeterGUIComponent#modifyTestElement(TestElement)
+ */
+ @Override
+ public void modifyTestElement(TestElement s) {
+ SubscriberSampler sampler = (SubscriberSampler) s;
+ this.configureTestElement(sampler);
+ sampler.setProviderUrl(urlField.getText());
+ sampler.setDestination(mqttDestination.getText());
+ sampler.setClientID(clientId.getText());
+ sampler.setUsername(mqttUser.getText());
+ sampler.setPassword(mqttPwd.getText());
+ sampler.setUseAuth(useAuth.isSelected());
+ sampler.setTimeout(timeout.getText());
+ sampler.setIterations(iterations.getText());
+ //we might need this in future - for now it's causing problems
+ //sampler.setRandomSuffix(this.suffixClientId.isSelected());
+ sampler.setRandomSuffix(false);
+ sampler.setLength(this.suffixLength.getText());
+ sampler.setOneConnectionPerTopic(this.connectionPerTopic.isSelected());
+ sampler.setSTRATEGY(this.topicChoice.getText());
+ sampler.setQuality(typeQoSValue.getText());
+ sampler.setCLEANSESSION(cleanSession.isSelected());
+
+ }
+
+ private void init() {
+ setLayout(new BorderLayout());
+ setBorder(makeBorder());
+ add(makeTitlePanel(), BorderLayout.NORTH);
+ JPanel mainPanel = new VerticalPanel();
+ add(mainPanel, BorderLayout.CENTER);
+ JPanel DPanel = new JPanel();
+ DPanel.setLayout(new BoxLayout(DPanel, BoxLayout.X_AXIS));
+ DPanel.add(urlField);
+ DPanel.add(clientId);
+ //DPanel.add(suffixClientId);
+ //DPanel.add(suffixLength);
+ JPanel ControlPanel = new VerticalPanel();
+ ControlPanel.add(DPanel);
+ ControlPanel.add(createDestinationPane());
+ ControlPanel.add(cleanSession);
+ ControlPanel.add(createAuthPane());
+ ControlPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray),"Connection Info"));
+ mainPanel.add(ControlPanel);
+ JPanel TPanel = new VerticalPanel();
+ TPanel.setLayout(new BoxLayout(TPanel, BoxLayout.X_AXIS));
+ timeout.setLayout(new BoxLayout(timeout, BoxLayout.X_AXIS));
+ iterations.setLayout(new BoxLayout(iterations, BoxLayout.X_AXIS));
+ typeQoSValue.setLayout(new BoxLayout(typeQoSValue, BoxLayout.X_AXIS));
+ TPanel.add(typeQoSValue);
+ TPanel.add(timeout);
+ TPanel.add(iterations);
+ TPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray),"Option"));
+ mainPanel.add(TPanel);
+ useAuth.addChangeListener(this);
+ suffixClientId.addChangeListener(this);
+
+ }
+ /**
+ *
+ * @return JPanel Panel with checkbox to choose user and password
+ */
+ private Component createAuthPane() {
+ JPanel panel = new JPanel();
+ panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
+ panel.add(useAuth);
+ panel.add(Box.createHorizontalStrut(10));
+ panel.add(mqttUser);
+ panel.add(Box.createHorizontalStrut(10));
+ panel.add(mqttPwd);
+ return panel;
+ }
+ /**
+ * the implementation loads the URL and the soap action for the request.
+ */
+ @Override
+ public void configure(TestElement el) {
+ super.configure(el);
+ SubscriberSampler sampler = (SubscriberSampler) el;
+ urlField.setText(sampler.getProviderUrl());
+ mqttDestination.setText(sampler.getDestination());
+ clientId.setText(sampler.getClientId());
+ mqttUser.setText(sampler.getUsername());
+ mqttPwd.setText(sampler.getPassword());
+ useAuth.setSelected(sampler.isUseAuth());
+ mqttUser.setEnabled(useAuth.isSelected());
+ mqttPwd.setEnabled(useAuth.isSelected());
+ timeout.setText(sampler.getTimeout());
+ iterations.setText(sampler.getIterations());
+ }
+
+ @Override
+ public void clearGui(){
+ super.clearGui();
+ urlField.setText(""); // $NON-NLS-1$
+ mqttDestination.setText(""); // $NON-NLS-1$
+ clientId.setText(""); // $NON-NLS-1$
+ mqttUser.setText(""); // $NON-NLS-1$
+ mqttPwd.setText(""); // $NON-NLS-1$
+ timeout.setText(""); // $NON-NLS-1$
+ iterations.setText("1");// $NON-NLS-1$
+ separator.setText(""); // $NON-NLS-1$
+ useAuth.setSelected(false);
+ mqttUser.setEnabled(false);
+ mqttPwd.setEnabled(false);
+ stopBetweenSamples.setSelected(false);
+
+ }
+
+ /**
+ * When the state of a widget changes, it will notify the gui. the method
+ * then enables or disables certain parameters.
+ */
+ @Override
+ public void stateChanged(ChangeEvent event) {
+ if (event.getSource() == useAuth) {
+ mqttUser.setEnabled(useAuth.isSelected());
+ mqttPwd.setEnabled(useAuth.isSelected());
+ }
+ else if(event.getSource()==suffixClientId){
+ updateChoice("Suffix="+String.valueOf(this.suffixClientId.isSelected()));
+ }
+ }
+
+ private void updateChoice(String command) {
+ if("suffix=true".equalsIgnoreCase(command)){
+ this.suffixLength.setVisible(true);
+ }
+ else if("suffix=false".equalsIgnoreCase(command)){
+ this.suffixLength.setVisible(false);
+ }
+ validate();
+ }
+
+ private JPanel createDestinationPane() {
+ JPanel panel = new VerticalPanel(); //new BorderLayout(3, 0)
+ this.mqttDestination.setLayout((new BoxLayout(mqttDestination, BoxLayout.X_AXIS)));
+ panel.add(mqttDestination);
+ JPanel TPanel = new JPanel();
+ TPanel.setLayout(new BoxLayout(TPanel,BoxLayout.X_AXIS));
+ this.connectionPerTopic.setLayout(new BoxLayout(connectionPerTopic,BoxLayout.X_AXIS));
+ this.connectionPerTopic.setAlignmentX(CENTER_ALIGNMENT);
+ TPanel.add(connectionPerTopic);
+ TPanel.add(Box.createHorizontalStrut(100));
+ this.topicChoice.setLayout(new BoxLayout(topicChoice,BoxLayout.X_AXIS));
+ TPanel.add(topicChoice);
+ panel.add(TPanel);
+ return panel;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/BaseMQTTSampler.java b/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/BaseMQTTSampler.java
new file mode 100644
index 0000000..7583f4a
--- /dev/null
+++ b/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/BaseMQTTSampler.java
@@ -0,0 +1,166 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+
+ Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team
+
+*/
+
+package org.apache.jmeter.protocol.mqttws.sampler;
+import org.apache.jmeter.samplers.AbstractSampler;
+import org.apache.jmeter.samplers.Entry;
+import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.util.JMeterUtils;
+
+public abstract class BaseMQTTSampler extends AbstractSampler {
+ private static final long serialVersionUID = 240L;
+ private static final String PROVIDER_URL = "mqtt.provider_url"; // $NON-NLS-1$
+ private static final String DEST = "mqtt.topic"; // $NON-NLS-1$
+ private static final String PRINCIPAL = "mqtt.security_principle"; // $NON-NLS-1$
+ private static final String CREDENTIALS = "mqtt.security_credentials"; // $NON-NLS-1$
+ private static final String ITERATIONS = "mqtt.iterations"; // $NON-NLS-1$
+ private static final String USE_AUTH = "mqtt.authenticate"; // $NON-NLS-1$
+ private static final String REQUIRED = JMeterUtils.getResString("mqtt_auth_required"); // $NON-NLS-1$
+
+
+ /**
+ * Constructor
+ */
+ public BaseMQTTSampler() {
+ }
+
+ @Override
+ public SampleResult sample(Entry e) {
+ return this.sample();
+ }
+ public abstract SampleResult sample() ;
+
+ // ------------- get/set properties ----------------------//
+
+ /**
+ *
+ * @param url the provider URL
+ */
+ public void setProviderUrl(String url) {
+ setProperty(PROVIDER_URL, url);
+ }
+
+ /**
+ *
+ * @return the provider URL
+ */
+ public String getProviderUrl() {
+ return getPropertyAsString(PROVIDER_URL);
+ }
+ /**
+ * set the destination (topic or queue name)
+ *
+ * @param dest the destination
+ */
+ public void setDestination(String dest) {
+ setProperty(DEST, dest);
+ }
+ /**
+ * return the destination (topic or queue name)
+ *
+ * @return the destination
+ */
+ public String getDestination() {
+ return getPropertyAsString(DEST);
+ }
+
+ /**
+ * set the username to login into the mqtt server if needed
+ *
+ * @param user
+ */
+ public void setUsername(String user) {
+ setProperty(PRINCIPAL, user);
+ }
+
+ /**
+ * return the username used to login to the mqtt server
+ *
+ * @return the username used to login to the mqtt server
+ */
+ public String getUsername() {
+ return getPropertyAsString(PRINCIPAL);
+ }
+ /**
+ * Set the password to login to the mqtt server
+ *
+ * @param pwd
+ */
+ public void setPassword(String pwd) {
+ setProperty(CREDENTIALS, pwd);
+ }
+
+ /**
+ * return the password used to login to the mqtt server
+ *
+ * @return the password used to login to the mqtt server
+ */
+ public String getPassword() {
+ return getPropertyAsString(CREDENTIALS);
+ }
+ /**
+ * set the number of iterations the sampler should aggregate
+ *
+ * @param count
+ */
+ public void setIterations(String count) {
+ setProperty(ITERATIONS, count);
+ }
+
+ /**
+ * get the iterations as string
+ *
+ * @return the number of iterations
+ */
+ public String getIterations() {
+ return getPropertyAsString(ITERATIONS);
+ }
+
+ /**
+ * return the number of iterations as int instead of string
+ *
+ * @return the number of iterations as int instead of string
+ */
+ public int getIterationCount() {
+ return getPropertyAsInt(ITERATIONS);
+ }
+
+ /**
+ * Set whether authentication is required for mqtt server
+ *
+ * @param useAuth
+ */
+ public void setUseAuth(boolean useAuth) {
+ setProperty(USE_AUTH, useAuth);
+ }
+ /**
+ *
+ *
+ * @return whether mqtt server requires authentication
+ */
+ public boolean isUseAuth() {
+ final String useAuth = getPropertyAsString(USE_AUTH);
+ return useAuth.equalsIgnoreCase("true") || useAuth.equals(REQUIRED); // $NON-NLS-1$
+ }
+
+
+}
diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/PublisherSampler.java b/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/PublisherSampler.java
new file mode 100644
index 0000000..2333634
--- /dev/null
+++ b/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/PublisherSampler.java
@@ -0,0 +1,470 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+
+ Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team
+
+ */
+
+package org.apache.jmeter.protocol.mqttws.sampler;
+import java.io.IOException;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.jmeter.config.Arguments;
+import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
+import org.apache.jmeter.protocol.mqttws.client.MqttPublisher;
+import org.apache.jmeter.protocol.mqttws.control.gui.MQTTPublisherGui;
+import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.testelement.TestStateListener;
+import org.apache.jmeter.testelement.ThreadListener;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+public class PublisherSampler extends BaseMQTTSampler implements ThreadListener,TestStateListener {
+
+ private static final long serialVersionUID = 233L;
+ private static final Logger log = LoggingManager.getLoggerForClass();
+ private static final String TEXT_MSG = "mqtt.text_message"; //$NON-NLS-1$
+ private static final String CONFIG_CHOICE = "mqtt.config_choice"; //$NON-NLS-1$
+ private static final String MESSAGE_CHOICE = "mqtt.config_msg_type"; //$NON-NLS-1$
+ private static final String QUALITY = "mqtt.quality"; //$NON-NLS-1$
+ private static final String TYPE_FIXED_VALUE = "mqtt.type_fixed_value"; //$NON-NLS-1$
+ private static String CLIENT_ID = "mqtt.clientid"; //$NON-NLS-1$
+ private static String RETAIN = "mqtt.retain"; //$NON-NLS-1$
+ private static String USE_TIMESTAMP = "mqtt.use_timestamp"; //$NON-NLS-1$
+ private static String USE_NUMBER_SEQUENCE = "mqtt.use_number_sequence"; //$NON-NLS-1$
+ private static String FIXED_VALUE = "mqtt.fixed_value"; //$NON-NLS-1$
+ private static String TYPE_RANDOM_VALUE = "mqtt.type_random_value"; //$NON-NLS-1$
+ private static String MIN_RANDOM_VALUE = "mqtt.min_random_value"; //$NON-NLS-1$
+ private static String MAX_RANDOM_VALUE = "mqtt.max_random_value"; //$NON-NLS-1$
+ private static String TYPE_GENERATED_VALUE = "mqtt.type_generated_value"; //$NON-NLS-1$
+ private static String SEED = "mqtt.seed"; //$NON-NLS-1$
+ private static String FORMAT = "mqtt.format"; //$NON-NLS-1$
+ private static String CHARSET = "mqtt.charset"; //$NON-NLS-1$
+ private static String SIZE_ARRAY = "mqtt.size_array"; //$NON-NLS-1$
+ private static String STRATEGY = "mqtt.strategy"; //$NON-NLS-1$
+ private static String OneConnectionPerTopic = "mqtt.one_connection_per_topic"; //$NON-NLS-1$
+ private static String RandomSuffix="mqtt.random_suffix_client_id";//$NON-NLS-1$
+ private static String Length="mqtt.suffix.length";//$NON-NLS-1$
+ public transient MqttPublisher producer = null;
+ public static AtomicInteger numberOfConnection= new AtomicInteger(0);
+ private JavaSamplerContext context = null;
+
+ /**
+ * Constructor
+ */
+
+ public PublisherSampler() {
+ }
+
+ // ---------------------Get/Set Property--------------------------//
+
+ public void setTYPE_FIXED_VALUE(String type) {
+ setProperty(TYPE_FIXED_VALUE, type);
+ }
+ public String getLength() {
+ return getPropertyAsString(Length);
+ }
+ public void setLength(String length) {
+ setProperty(Length,length);
+ }
+
+ public boolean useRandomSuffix() {
+
+ String randomSuffix = getPropertyAsString(RandomSuffix);
+ if("TRUE".equalsIgnoreCase(randomSuffix)){
+ return true;
+ }
+ else {
+ return false;
+ }
+
+ }
+
+ public void setRandomSuffix(boolean randomSuffix) {
+ setProperty(RandomSuffix,randomSuffix);
+
+ }
+
+ public boolean isOneConnectionPerTopic() {
+
+ String perTopic = getPropertyAsString(OneConnectionPerTopic);
+ if("TRUE".equalsIgnoreCase(perTopic)){
+ return true;
+ }
+ else {
+ return false;
+ }
+
+ }
+ public void setOneConnectionPerTopic(boolean oneConnectionPerTopic) {
+
+ setProperty(OneConnectionPerTopic, oneConnectionPerTopic);
+ }
+
+ public String getSTRATEGY() {
+ return getPropertyAsString(STRATEGY);
+
+ }
+
+ public void setSTRATEGY(String sTRATEGY) {
+ setProperty(STRATEGY,sTRATEGY);
+
+ }
+
+ public String getSIZE_ARRAY() {
+ return getPropertyAsString(SIZE_ARRAY);
+ }
+
+ public void setSIZE_ARRAY(String sIZE_ARRAY) {
+ setProperty(SIZE_ARRAY,sIZE_ARRAY);
+ }
+
+ public String getCHARSET() {
+ return getPropertyAsString(CHARSET);
+ }
+
+ public void setCHARSET(String cHARSET) {
+ setProperty(CHARSET,cHARSET);
+ }
+
+ public String getFORMAT() {
+ return getPropertyAsString(FORMAT);
+ }
+
+ public void setFORMAT(String fORMAT) {
+ setProperty(FORMAT,fORMAT);
+ }
+
+ public String getCLIENT_ID() {
+ return getPropertyAsString(CLIENT_ID);
+ }
+
+ public void setCLIENT_ID(String cLIENT_ID) {
+ setProperty(CLIENT_ID,cLIENT_ID);
+ }
+
+ public boolean isUSE_TIMESTAMP() {
+ String isUseTimeStamp = getPropertyAsString(USE_TIMESTAMP);
+ if("TRUE".equalsIgnoreCase(isUseTimeStamp)){
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ public void setUSE_TIMESTAMP(boolean uSE_TIMESTAMP) {
+ setProperty(USE_TIMESTAMP,uSE_TIMESTAMP);
+ }
+
+ public boolean isUSE_NUMBER_SEQUENCE() {
+ String isUseNumberSequence = getPropertyAsString(USE_NUMBER_SEQUENCE);
+ if("TRUE".equalsIgnoreCase(isUseNumberSequence)){
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ public void setUSE_NUMBER_SEQUENCE(boolean uSE_NUMBER_SEQUENCE) {
+ setProperty(USE_NUMBER_SEQUENCE,uSE_NUMBER_SEQUENCE);
+ }
+ public String getSEED() {
+ return getPropertyAsString(SEED);
+ }
+ public void setSEED(String sEED) {
+ setProperty(SEED,sEED);
+ }
+ public String getTYPE_GENERATED_VALUE() {
+ return getPropertyAsString(TYPE_GENERATED_VALUE);
+ }
+ public void setTYPE_GENERATED_VALUE(String tYPE_GENERATED_VALUE) {
+ setProperty(TYPE_GENERATED_VALUE,tYPE_GENERATED_VALUE);
+ }
+
+ public String getTYPE_RANDOM_VALUE() {
+ return getPropertyAsString(TYPE_RANDOM_VALUE);
+ }
+
+ public void setTYPE_RANDOM_VALUE(String tYPE_RANDOM_VALUE) {
+ setProperty(TYPE_RANDOM_VALUE,tYPE_RANDOM_VALUE);
+ }
+
+ public String getMIN_RANDOM_VALUE() {
+ return getPropertyAsString(MIN_RANDOM_VALUE);
+
+ }
+
+ public void setMIN_RANDOM_VALUE(String mIN_RANDOM_VALUE) {
+ setProperty(MIN_RANDOM_VALUE,mIN_RANDOM_VALUE);
+ }
+
+ public String getMAX_RANDOM_VALUE() {
+ return getPropertyAsString(MAX_RANDOM_VALUE);
+ }
+
+ public void setMAX_RANDOM_VALUE(String mAX_RANDOM_VALUE) {
+ setProperty(MAX_RANDOM_VALUE,mAX_RANDOM_VALUE);
+
+ }
+
+ public String getFIXED_VALUE() {
+ return getPropertyAsString( FIXED_VALUE);
+
+ }
+
+ public void setFIXED_VALUE(String fIXED_VALUE) {
+ setProperty(FIXED_VALUE,fIXED_VALUE);
+
+ }
+
+ public String getTYPE_FIXED_VALUE() {
+ return getPropertyAsString(TYPE_FIXED_VALUE);
+
+ }
+ public void setTextMessage(String message) {
+ setProperty(TEXT_MSG, message);
+ }
+ public void setConfigChoice(String choice) {
+ setProperty(CONFIG_CHOICE, choice);
+
+ }
+
+ public void setMessageChoice(String choice) {
+ setProperty(MESSAGE_CHOICE, choice);
+
+ }
+
+ public String getTextMessage() {
+ return getPropertyAsString(TEXT_MSG);
+ }
+
+ /**
+ * To get the message choice
+ *
+ * @return
+ */
+ public String getMessageChoice() {
+ return getPropertyAsString(MESSAGE_CHOICE);
+ }
+
+ public String getQuality() {
+ return getPropertyAsString(QUALITY);
+ }
+
+ public void setQuality(String quality) {
+ setProperty(QUALITY, quality);
+ }
+
+ public void setRetained(boolean isRetained) {
+
+ setProperty(RETAIN,isRetained);
+ }
+
+ public boolean isRetained() {
+ String isRetain = getPropertyAsString(RETAIN);
+ if("TRUE".equalsIgnoreCase(isRetain)){
+ return true;
+ }
+ else {
+ return false;
+ }
+
+ }
+
+
+ private void logThreadStart() {
+ if (log.isDebugEnabled()) {
+ log.debug("Thread started " + new Date());
+ log.debug("MQTT PublishSampler: ["
+ + Thread.currentThread().getName() + "], hashCode=["
+ + hashCode() + "]");
+
+ }
+
+ }
+
+ @Override
+ public void threadStarted() {
+ logThreadStart();
+
+ if (producer == null) {
+
+ try {
+ producer = new MqttPublisher();
+ } catch (Exception e) {
+ log.warn(e.getLocalizedMessage(), e);
+ }
+ }
+
+ this.producer.setupTest(this.context);
+ }
+
+ @Override
+ public void threadFinished() {
+ log.debug("Thread ended " + new Date());
+
+ if (producer != null) {
+
+
+ }
+
+ }
+
+ // -------------------------Sample------------------------------------//
+
+ @Override
+ public SampleResult sample() {
+ //get context just prior to our actual sampling
+ //so that we won't miss any updates by other samplers
+ //made prior to that point
+ context = getSamplerContext();
+ return this.producer.runTest(context);
+ }
+
+ @Override
+ public void testEnded() {
+ log.debug("Thread ended " + new Date());
+ if (producer != null) {
+ }
+ }
+
+ @Override
+ public void testEnded(String arg0) {
+ testEnded();
+ }
+
+ @Override
+ public void testStarted() {
+ }
+
+ @Override
+ public void testStarted(String arg0) {
+ testStarted();
+ }
+
+ public JavaSamplerContext getSamplerContext() {
+ String host = getProviderUrl();
+ String list_topic = getDestination();
+ String aggregate = "" + getIterationCount();
+ Arguments parameters = new Arguments();
+ parameters.addArgument("SAMPLER_NAME", this.getName());
+ parameters.addArgument("HOST", host);
+ // ------------------------ClientId-----------------------------------//
+ parameters.addArgument("CLIENT_ID", getCLIENT_ID());
+ parameters.addArgument("TOPIC", list_topic);
+
+ // ------------------------Strategy-----------------------------------//
+ if (MQTTPublisherGui.ROUND_ROBIN.equals(this.getSTRATEGY())) {
+ parameters.addArgument("STRATEGY", "ROUND_ROBIN");
+ } else {
+ parameters.addArgument("STRATEGY", "RANDOM");
+ }
+
+ parameters.addArgument("AGGREGATE", aggregate);
+
+ String quality = getQuality();
+ parameters.addArgument("QOS", quality);
+ if (this.isRetained()) {
+ parameters.addArgument("RETAINED", "TRUE");
+ } else {
+ parameters.addArgument("RETAINED", "FALSE");
+ }
+ // -------------------------TimeStamp-----------------------------//
+
+ if (this.isUSE_TIMESTAMP()) {
+ parameters.addArgument("TIME_STAMP", "TRUE");
+ } else
+ parameters.addArgument("TIME_STAMP", "FALSE");
+
+ // -------------------------Number Sequence-----------------------//
+
+ if (this.isUSE_NUMBER_SEQUENCE()) {
+ parameters.addArgument("NUMBER_SEQUENCE", "TRUE");
+ } else
+ parameters.addArgument("NUMBER_SEQUENCE", "FALSE");
+
+ // ---------------------Message Choice----------------------------//
+
+ if (this.getMessageChoice().equals(MQTTPublisherGui.TEXT_MSG_RSC)) {
+
+ parameters.addArgument("MESSAGE", getTextMessage());
+ parameters.addArgument("TYPE_MESSAGE", "TEXT");
+ parameters.addArgument("TYPE_VALUE", "TEXT");
+ } else if (this.getMessageChoice().equals(MQTTPublisherGui.FIXED_VALUE)) {
+
+ parameters.addArgument("MESSAGE", getFIXED_VALUE());
+ parameters.addArgument("TYPE_MESSAGE", "FIXED");
+ parameters.addArgument("TYPE_VALUE", getTYPE_FIXED_VALUE());
+ } else if (this.getMessageChoice().equals(
+ MQTTPublisherGui.GENERATED_VALUE)) {
+ parameters.addArgument("TYPE_MESSAGE", "RANDOM");
+ parameters.addArgument("TYPE_VALUE", getTYPE_GENERATED_VALUE());
+ parameters.addArgument("SEED", getSEED());
+ parameters.addArgument("MIN_RANDOM_VALUE", getMIN_RANDOM_VALUE());
+ parameters.addArgument("MAX_RANDOM_VALUE", getMAX_RANDOM_VALUE());
+ parameters.addArgument("TYPE_RANDOM_VALUE", getTYPE_RANDOM_VALUE());
+ } else if (this.getMessageChoice().equals(MQTTPublisherGui.BIG_VOLUME)) {
+ parameters.addArgument("TYPE_MESSAGE", "BYTE_ARRAY");
+ parameters.addArgument("SIZE_ARRAY", this.getSIZE_ARRAY());
+ }
+
+ // -----------------------User/Password-------------------------------//
+
+ if (this.isUseAuth()) {
+ parameters.addArgument("AUTH", "TRUE");
+ parameters.addArgument("USER", getUsername());
+ parameters.addArgument("PASSWORD", getPassword());
+ } else
+ parameters.addArgument("AUTH", "FALSE");
+ // -----------------------Format--------------------------------------//
+ parameters.addArgument("FORMAT", getFORMAT());
+ if (this.getFORMAT().equals(MQTTPublisherGui.PLAIN_TEXT)) {
+ parameters.addArgument("CHARSET", getCHARSET());
+
+ } else
+ parameters.addArgument("CHARSET", "NULL");
+
+ // -------------------------List Topic Or Not-------------------------//
+
+ String[] topics = list_topic.split("\\s*,\\s*");
+ if (topics.length <= 1) {
+ parameters.addArgument("LIST_TOPIC", "FALSE");
+ } else {
+ parameters.addArgument("LIST_TOPIC", "TRUE");
+ }
+ // ------------------------Connection per topic--------------------//
+
+ if (this.isOneConnectionPerTopic()) {
+ parameters.addArgument("PER_TOPIC", "TRUE");
+ } else {
+ parameters.addArgument("PER_TOPIC", "FALSE");
+ }
+ if(this.useRandomSuffix()){
+ parameters.addArgument("RANDOM_SUFFIX","TRUE");
+ parameters.addArgument("SUFFIX_LENGTH",this.getLength());
+ }else {
+ parameters.addArgument("RANDOM_SUFFIX","FALSE");
+ }
+
+ return new JavaSamplerContext(parameters);
+ }
+
+}
diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/SubscriberSampler.java b/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/SubscriberSampler.java
new file mode 100644
index 0000000..40d75e2
--- /dev/null
+++ b/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/SubscriberSampler.java
@@ -0,0 +1,305 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+
+ Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team
+
+ */
+
+package org.apache.jmeter.protocol.mqttws.sampler;
+
+import java.util.Date;
+
+import org.apache.jmeter.config.Arguments;
+import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
+//import org.apache.jmeter.protocol.mqtt.client.ListenerforSubscribe;
+import org.apache.jmeter.protocol.mqttws.client.MqttSubscriber;
+import org.apache.jmeter.protocol.mqttws.control.gui.MQTTPublisherGui;
+import org.apache.jmeter.samplers.Interruptible;
+import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.testelement.TestStateListener;
+import org.apache.jmeter.testelement.ThreadListener;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+public class SubscriberSampler extends BaseMQTTSampler implements
+ Interruptible, ThreadListener, TestStateListener {
+
+ private static final long serialVersionUID = 240L;
+ private static final Logger log = LoggingManager.getLoggerForClass();
+ private static final String DURABLE_SUBSCRIPTION_ID = "mqtt.durableSubscriptionId"; // $NON-NLS-1$
+ private static final String DURABLE_SUBSCRIPTION_ID_DEFAULT = "";
+ private static final String CLIENT_ID = "mqtt.clientId"; // $NON-NLS-1$
+ private static final String CLIENT_ID_DEFAULT = ""; // $NON-NLS-1$
+ private static final String TIMEOUT = "mqtt.timeout"; // $NON-NLS-1$
+ private static final String TIMEOUT_DEFAULT = "30000"; // $NON-NLS-1$
+ private static final String QUALITY = "mqtt.quality"; //$NON-NLS-1$
+ private static String OneConnectionPerTopic = "mqtt.one_connection_per_topic"; //$NON-NLS-1$
+ public transient MqttSubscriber subscriber = null;
+ private JavaSamplerContext context = null;
+ private static String Length = "mqtt.suffix.length";//$NON-NLS-1$
+ private static String RandomSuffix = "mqtt.random_suffix_client_id";//$NON-NLS-1$
+ private static String STRATEGY = "mqtt.strategy"; //$NON-NLS-1$
+ private static String CLEAN_SESSION="mqtt.clean.session";//$NON-NLS-1$
+
+ public SubscriberSampler() {
+ super();
+ }
+
+ public String getCLEANSESSION() {
+ return getPropertyAsString(CLEAN_SESSION);
+ }
+
+ public void setCLEANSESSION(boolean cLEANSESSION) {
+
+ if(cLEANSESSION) {
+ setProperty(CLEAN_SESSION, "true");
+ }
+ else
+ setProperty(CLEAN_SESSION, "false");
+ }
+
+ public void setOneConnectionPerTopic(boolean oneConnectionPerTopic) {
+ setProperty(OneConnectionPerTopic, oneConnectionPerTopic);
+ }
+
+ public boolean isOneConnectionPerTopic() {
+ String perTopic = getPropertyAsString(OneConnectionPerTopic);
+ if ("TRUE".equalsIgnoreCase(perTopic)) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ public void setQuality(String quality) {
+ setProperty(QUALITY, quality);
+ }
+
+ private String getQuality() {
+ return getPropertyAsString(QUALITY);
+ }
+
+ public String getSTRATEGY() {
+ return getPropertyAsString(STRATEGY);
+
+ }
+
+ public void setSTRATEGY(String sTRATEGY) {
+ setProperty(STRATEGY, sTRATEGY);
+
+ }
+
+ public void setDurableSubscriptionId(String durableSubscriptionId) {
+ setProperty(DURABLE_SUBSCRIPTION_ID, durableSubscriptionId,
+ DURABLE_SUBSCRIPTION_ID_DEFAULT);
+ }
+
+ public void setClientID(String clientId) {
+ setProperty(CLIENT_ID, clientId, CLIENT_ID_DEFAULT);
+
+ }
+
+ public void setTimeout(String timeout) {
+ setProperty(TIMEOUT, timeout, TIMEOUT_DEFAULT);
+ }
+
+ public String getDurableSubscriptionId() {
+ return getPropertyAsString(DURABLE_SUBSCRIPTION_ID);
+ }
+
+ public String getClientId() {
+ return getPropertyAsString(CLIENT_ID, CLIENT_ID_DEFAULT);
+ }
+
+ public String getTimeout() {
+ return getPropertyAsString(TIMEOUT, TIMEOUT_DEFAULT);
+ }
+
+ public void setRandomSuffix(boolean randomSuffix) {
+ setProperty(RandomSuffix, randomSuffix);
+
+ }
+
+ public boolean useRandomSuffix() {
+ String randomSuffix = getPropertyAsString(RandomSuffix);
+ if ("TRUE".equalsIgnoreCase(randomSuffix)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void setLength(String length) {
+ setProperty(Length, length);
+ }
+
+ public String getLength() {
+ return getPropertyAsString(Length);
+ }
+
+ @Override
+ public boolean interrupt() {
+
+ System.out.println("Hello interrupt");
+ //System.out.println("Received " + ListenerforSubscribe.count.get() +" messages");
+ log.debug("Thread ended " + new Date());
+ if (this.subscriber != null) {
+ try {
+ this.subscriber.close(context);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ log.warn(e.getLocalizedMessage(), e);
+ }
+
+ }
+ return false;
+ }
+
+ @Override
+ public void testEnded() {
+ log.debug("Thread ended " + new Date());
+ //System.out.println("Received " + ListenerforSubscribe.count.get() +" messages");
+ if (this.subscriber != null) {
+ try {
+ this.subscriber.close(context);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ log.warn(e.getLocalizedMessage(), e);
+ }
+
+ }
+ }
+
+ @Override
+ public void testEnded(String arg0) {
+ testEnded();
+ }
+
+ @Override
+ public void testStarted() {
+ }
+
+ @Override
+ public void testStarted(String arg0) {
+ testStarted();
+ }
+
+ // ------------------------------ For Thread---------------------------------//
+
+ private void logThreadStart() {
+ if (log.isDebugEnabled()) {
+ log.debug("Thread started " + new Date());
+ log.debug("MQTTSampler: [" + Thread.currentThread().getName()
+ + "], hashCode=[" + hashCode() + "]");
+ }
+ }
+
+ @Override
+ public void threadStarted() {
+ logThreadStart();
+ if (subscriber == null) {
+ try {
+ subscriber = new MqttSubscriber();
+ } catch (Exception e) {
+ log.warn(e.getLocalizedMessage(), e);
+ }
+ }
+ subscriber.setupTest(context);
+ }
+
+ @Override
+ public void threadFinished() {
+ log.debug("Thread ended " + new Date());
+ //System.out.println("Received " + ListenerforSubscribe.count.get() +" messages");
+ if (this.subscriber != null) {
+ try {
+ this.subscriber.close(context);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ log.warn(e.getLocalizedMessage(), e);
+ }
+ }
+ }
+
+ @Override
+ public SampleResult sample() {
+ //get context just prior to our actual sampling
+ //so that we won't miss any updates by other samplers
+ //made prior to that point
+ context = getSamplerContext();
+ return this.subscriber.runTest(context);
+ }
+
+ //get sampler's JMeter context
+ public JavaSamplerContext getSamplerContext() {
+ String host = getProviderUrl();
+ String list_topic = getDestination();
+ String aggregate = "" + getIterationCount();
+ String clientId = getClientId();
+ String timeout = this.getTimeout();
+ Arguments parameters = new Arguments();
+ parameters.addArgument("SAMPLER_NAME", this.getName());
+ parameters.addArgument("HOST", host);
+ parameters.addArgument("CLIENT_ID", clientId);
+ parameters.addArgument("TOPIC", list_topic);
+ // ------------------------Strategy-----------------------------------//
+ if (MQTTPublisherGui.ROUND_ROBIN.equals(this.getSTRATEGY())) {
+ parameters.addArgument("STRATEGY", "ROUND_ROBIN");
+ } else {
+ parameters.addArgument("STRATEGY", "RANDOM");
+ }
+ parameters.addArgument("AGGREGATE", aggregate);
+ String quality = getQuality();
+ parameters.addArgument("QOS", quality);
+ parameters.addArgument("DURABLE",this.getCLEANSESSION());
+ parameters.addArgument("TIMEOUT", timeout);
+
+ if (this.isUseAuth()) {
+ parameters.addArgument("AUTH", "TRUE");
+ parameters.addArgument("USER", getUsername());
+ parameters.addArgument("PASSWORD", getPassword());
+ } else
+ parameters.addArgument("AUTH", "FALSE");
+ // -------------------------List Topic Or Not-------------------------//
+
+ String[] topics = list_topic.split("\\s*,\\s*");
+ if (topics.length <= 1) {
+ parameters.addArgument("LIST_TOPIC", "FALSE");
+ } else {
+ parameters.addArgument("LIST_TOPIC", "TRUE");
+ }
+ // ------------------------Connection per topic--------------------//
+
+ if (this.isOneConnectionPerTopic()) {
+ parameters.addArgument("PER_TOPIC", "TRUE");
+ } else {
+ parameters.addArgument("PER_TOPIC", "FALSE");
+ }
+ if (this.useRandomSuffix()) {
+ parameters.addArgument("RANDOM_SUFFIX", "TRUE");
+ parameters.addArgument("SUFFIX_LENGTH", this.getLength());
+ } else {
+ parameters.addArgument("RANDOM_SUFFIX", "FALSE");
+ }
+ return new JavaSamplerContext(parameters);
+ }
+}