From 54938c5858cbda477515a1edb38624490664efdf Mon Sep 17 00:00:00 2001 From: Vadim Elkin Date: Mon, 14 Apr 2014 14:31:59 -0400 Subject: [PATCH 1/8] Added support for headers and cookies in WebSocket upgrade request --- .../samplers/websocket/WebSocketSampler.java | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java index 5cdc1de..c20aa67 100644 --- a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java +++ b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java @@ -8,6 +8,9 @@ import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.config.Argument; import org.apache.jmeter.config.Arguments; +import org.apache.jmeter.protocol.http.control.CookieManager; +import org.apache.jmeter.protocol.http.control.Header; +import org.apache.jmeter.protocol.http.control.HeaderManager; import org.apache.jmeter.protocol.http.util.EncoderCache; import org.apache.jmeter.protocol.http.util.HTTPArgument; import org.apache.jmeter.protocol.http.util.HTTPConstants; @@ -22,12 +25,14 @@ import java.io.UnsupportedEncodingException; +import java.net.HttpCookie; import java.net.URI; import java.net.URISyntaxException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import org.apache.jmeter.testelement.TestStateListener; +import org.eclipse.jetty.util.HttpCookieStore; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; import org.eclipse.jetty.websocket.client.WebSocketClient; @@ -51,6 +56,9 @@ public class WebSocketSampler extends AbstractSampler implements TestStateListen private static Map connectionList; + private HeaderManager headerManager; + private CookieManager cookieManager; + public WebSocketSampler() { super(); setName("WebSocket sampler"); @@ -81,8 +89,25 @@ private ServiceSocket getConnectionSocket() throws URISyntaxException, Exception } //Start WebSocket client thread and upgrage HTTP connection + if (cookieManager != null) { + HttpCookieStore cookieStore = new HttpCookieStore(); + for (int i = 0; i < cookieManager.getCookieCount(); i++) + cookieStore.add( + new URI(null, + cookieManager.get(i).getDomain(), + cookieManager.get(i).getPath(), + null), + new HttpCookie(cookieManager.get(i).getName(), cookieManager.get(i).getValue())); + webSocketClient.setCookieStore(cookieStore); + } webSocketClient.start(); ClientUpgradeRequest request = new ClientUpgradeRequest(); + if (headerManager != null) { + for (int i = 0; i < headerManager.size(); i++) { + Header header = headerManager.get(i); + request.setHeader(header.getName(), header.getValue()); + } + } webSocketClient.connect(socket, uri, request); //Get connection timeout or use the default value @@ -495,6 +520,13 @@ public void testEnded(String host) { } } - - + public void addTestElement(TestElement el) { + if (el instanceof HeaderManager) { + headerManager = (HeaderManager) el; + } else if (el instanceof CookieManager) { + cookieManager = (CookieManager) el; + } else { + super.addTestElement(el); + } + } } From 3dc887cb327c4c372cd6ad66b0e308739be21d54 Mon Sep 17 00:00:00 2001 From: Vadim Elkin Date: Tue, 15 Apr 2014 16:00:31 -0400 Subject: [PATCH 2/8] Added Clear Backlog option --- .../samplers/websocket/ServiceSocket.java | 4 ++++ .../samplers/websocket/WebSocketSampler.java | 15 +++++++++++--- .../websocket/WebSocketSamplerGui.java | 2 ++ .../websocket/WebSocketSamplerPanel.java | 20 +++++++++++++++++-- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/main/java/JMeter/plugins/functional/samplers/websocket/ServiceSocket.java b/src/main/java/JMeter/plugins/functional/samplers/websocket/ServiceSocket.java index e168afb..bd2e219 100644 --- a/src/main/java/JMeter/plugins/functional/samplers/websocket/ServiceSocket.java +++ b/src/main/java/JMeter/plugins/functional/samplers/websocket/ServiceSocket.java @@ -119,6 +119,10 @@ public String getResponseMessage() { return responseMessage; } + public void clearBacklog() { + responeBacklog.clear(); + } + public boolean awaitClose(int duration, TimeUnit unit) throws InterruptedException { logMessage.append(" - Waiting for messages for ").append(duration).append(" ").append(unit.toString()).append("\n"); boolean res = this.closeLatch.await(duration, unit); diff --git a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java index c20aa67..386f8ae 100644 --- a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java +++ b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java @@ -191,7 +191,10 @@ public SampleResult sample(Entry entry) { //set sampler response sampleResult.setResponseData(socket.getResponseMessage(), getContentEncoding()); - + + if (getClearBacklog()) + socket.clearBacklog(); + } catch (URISyntaxException e) { errorList.append(" - Invalid URI syntax: ").append(e.getMessage()).append("\n").append(StringUtils.join(e.getStackTrace(), "\n")).append("\n"); } catch (IOException e) { @@ -443,8 +446,14 @@ public String getMessageBacklog() { return getPropertyAsString("messageBacklog", "3"); } - - + public void setClearBacklog(Boolean clearBacklog) { + setProperty("clearBacklog", clearBacklog); + } + + public Boolean getClearBacklog() { + return getPropertyAsBoolean("clearBacklog", false); + } + public String getQueryString(String contentEncoding) { // Check if the sampler has a specified content encoding if (JOrphanUtils.isBlank(contentEncoding)) { diff --git a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSamplerGui.java b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSamplerGui.java index 0b6933b..3a6fdc1 100644 --- a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSamplerGui.java +++ b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSamplerGui.java @@ -67,6 +67,7 @@ public void configure(TestElement element) { webSocketSamplerPanel.setProxyPort(webSocketSamplerTestElement.getProxyPort()); webSocketSamplerPanel.setProxyUsername(webSocketSamplerTestElement.getProxyUsername()); webSocketSamplerPanel.setMessageBacklog(webSocketSamplerTestElement.getMessageBacklog()); + webSocketSamplerPanel.setClearBacklog(webSocketSamplerTestElement.getClearBacklog()); Arguments queryStringParameters = webSocketSamplerTestElement.getQueryStringParameters(); if (queryStringParameters != null) { @@ -106,6 +107,7 @@ public void modifyTestElement(TestElement te) { webSocketSamplerTestElement.setProxyPort(webSocketSamplerPanel.getProxyPort()); webSocketSamplerTestElement.setProxyUsername(webSocketSamplerPanel.getProxyUsername()); webSocketSamplerTestElement.setMessageBacklog(webSocketSamplerPanel.getMessageBacklog()); + webSocketSamplerTestElement.setClearBacklog(webSocketSamplerPanel.getClearBacklog()); ArgumentsPanel queryStringParameters = webSocketSamplerPanel.getAttributePanel(); if (queryStringParameters != null) { diff --git a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSamplerPanel.java b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSamplerPanel.java index 4185aa6..b2b5c35 100644 --- a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSamplerPanel.java +++ b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSamplerPanel.java @@ -71,6 +71,7 @@ private void initComponents() { closeConncectionPatternTextField = new javax.swing.JTextField(); jLabel16 = new javax.swing.JLabel(); messageBacklogTextField = new javax.swing.JTextField(); + clearBacklogCheckBox = new javax.swing.JCheckBox(); jPanel6 = new javax.swing.JPanel(); jLabel10 = new javax.swing.JLabel(); proxyAddressTextField = new javax.swing.JTextField(); @@ -250,6 +251,8 @@ private void initComponents() { jLabel16.setText("Message backlog:"); + clearBacklogCheckBox.setText("Clear backlog"); + javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5); jPanel5.setLayout(jPanel5Layout); jPanel5Layout.setHorizontalGroup( @@ -264,7 +267,9 @@ private void initComponents() { .addGap(18, 18, 18) .addComponent(jLabel16) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(messageBacklogTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(messageBacklogTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(clearBacklogCheckBox)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel5Layout.createSequentialGroup() .addComponent(jLabel9) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -276,6 +281,8 @@ private void initComponents() { .addGroup(jPanel5Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(clearBacklogCheckBox)) .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel16) .addComponent(messageBacklogTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -413,6 +420,7 @@ private void initComponents() { private javax.swing.JPanel jPanel6; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextField messageBacklogTextField; + private javax.swing.JCheckBox clearBacklogCheckBox; private javax.swing.JTextField protocolTextField; private javax.swing.JTextField proxyAddressTextField; private javax.swing.JTextField proxyPasswordTextField; @@ -580,7 +588,15 @@ public void setMessageBacklog(String messageBacklog) { public String getMessageBacklog() { return messageBacklogTextField.getText(); - } + } + + public void setClearBacklog(Boolean clearBacklog) { + clearBacklogCheckBox.setSelected(clearBacklog); + } + + public Boolean getClearBacklog() { + return clearBacklogCheckBox.isSelected(); + } /** * @return the attributePanel From 068c4778f25ec33a2ac1b2e81b3c11a758e6b8db Mon Sep 17 00:00:00 2001 From: Vadim Elkin Date: Mon, 21 Apr 2014 09:32:21 -0400 Subject: [PATCH 3/8] Transferring cookie version into WebSocket initial request cookies. --- .../functional/samplers/websocket/WebSocketSampler.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java index 386f8ae..214c67a 100644 --- a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java +++ b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java @@ -91,13 +91,17 @@ private ServiceSocket getConnectionSocket() throws URISyntaxException, Exception //Start WebSocket client thread and upgrage HTTP connection if (cookieManager != null) { HttpCookieStore cookieStore = new HttpCookieStore(); - for (int i = 0; i < cookieManager.getCookieCount(); i++) + for (int i = 0; i < cookieManager.getCookieCount(); i++) { + HttpCookie cookie = new HttpCookie(cookieManager.get(i).getName(), cookieManager.get(i).getValue()); + cookie.setVersion(cookieManager.get(i).getVersion()); cookieStore.add( new URI(null, cookieManager.get(i).getDomain(), cookieManager.get(i).getPath(), null), - new HttpCookie(cookieManager.get(i).getName(), cookieManager.get(i).getValue())); + cookie + ); + } webSocketClient.setCookieStore(cookieStore); } webSocketClient.start(); From a58b83823fc7754e1ba79aeda31ee532eb78871a Mon Sep 17 00:00:00 2001 From: Vadim Elkin Date: Wed, 3 Sep 2014 15:52:29 -0400 Subject: [PATCH 4/8] Setting into cookie manager cookie that may be present in the websocket upgrade response --- .../samplers/websocket/WebSocketSampler.java | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java index 214c67a..0a616b3 100644 --- a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java +++ b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java @@ -8,6 +8,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.config.Argument; import org.apache.jmeter.config.Arguments; +import org.apache.jmeter.protocol.http.control.CookieHandler; import org.apache.jmeter.protocol.http.control.CookieManager; import org.apache.jmeter.protocol.http.control.Header; import org.apache.jmeter.protocol.http.control.HeaderManager; @@ -20,6 +21,8 @@ import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.property.*; import org.apache.jorphan.logging.LoggingManager; +import org.apache.jorphan.reflect.ClassTools; +import org.apache.jorphan.util.JMeterException; import org.apache.jorphan.util.JOrphanUtils; import org.apache.log.Logger; @@ -28,6 +31,7 @@ import java.net.HttpCookie; import java.net.URI; import java.net.URISyntaxException; +import java.net.URL; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -58,13 +62,14 @@ public class WebSocketSampler extends AbstractSampler implements TestStateListen private HeaderManager headerManager; private CookieManager cookieManager; + private CookieHandler cookieHandler; public WebSocketSampler() { super(); setName("WebSocket sampler"); } - private ServiceSocket getConnectionSocket() throws URISyntaxException, Exception { + private ServiceSocket getConnectionSocket() throws Exception { URI uri = getUri(); String connectionId = getThreadName() + getConnectionId(); @@ -124,7 +129,19 @@ private ServiceSocket getConnectionSocket() throws URISyntaxException, Exception } socket.awaitOpen(connectionTimeout, TimeUnit.MILLISECONDS); - + + if (cookieManager != null && cookieHandler != null) { + String setCookieHeader = socket.getSession().getUpgradeResponse().getHeader("set-cookie"); + if (setCookieHeader != null) { + cookieHandler.addCookieFromHeader(cookieManager, true, setCookieHeader, new URL( + uri.getScheme() == null || uri.getScheme().equalsIgnoreCase("ws") ? "HTTP" : "HTTPS", + uri.getHost(), + uri.getPort(), + uri.getQuery() != null ? uri.getPath() + "?" + uri.getQuery() : uri.getPath() + )); + } + } + return socket; } @@ -468,7 +485,7 @@ public String getQueryString(String contentEncoding) { PropertyIterator iter = getQueryStringParameters().iterator(); boolean first = true; while (iter.hasNext()) { - HTTPArgument item = null; + HTTPArgument item; Object objectValue = iter.next().getObjectValue(); try { item = (HTTPArgument) objectValue; @@ -506,8 +523,7 @@ public void setQueryStringParameters(Arguments queryStringParameters) { } public Arguments getQueryStringParameters() { - Arguments args = (Arguments) getProperty("queryStringParameters").getObjectValue(); - return args; + return (Arguments) getProperty("queryStringParameters").getObjectValue(); } @@ -518,7 +534,7 @@ public void testStarted() { @Override public void testStarted(String host) { - connectionList = new ConcurrentHashMap(); + connectionList = new ConcurrentHashMap<>(); } @Override @@ -533,11 +549,17 @@ public void testEnded(String host) { } } + @Override public void addTestElement(TestElement el) { if (el instanceof HeaderManager) { headerManager = (HeaderManager) el; } else if (el instanceof CookieManager) { cookieManager = (CookieManager) el; + try { + cookieHandler = (CookieHandler) ClassTools.construct(cookieManager.getImplementation(), cookieManager.getPolicy()); + } catch (JMeterException e) { + log.error("Failed to construct cookie handler ", e); + } } else { super.addTestElement(el); } From 6ed634474380ff0f404e5c1d28941bdb3e1a692b Mon Sep 17 00:00:00 2001 From: Vadim Elkin Date: Thu, 4 Sep 2014 10:33:57 -0400 Subject: [PATCH 5/8] Remove unused files --- .../WebSocketApplicationConfig.form | 337 ----------- .../WebSocketApplicationConfig.java | 448 --------------- .../WebSocketApplicationRequest.form | 201 ------- .../WebSocketApplicationRequest.java | 315 ----------- .../WebSocketApplicationResponse.form | 150 ----- .../WebSocketApplicationResponse.java | 302 ---------- .../websocketapp/WebSocketSampler.java | 468 ---------------- .../websocketapp/WebSocketSamplerGui.java | 130 ----- .../websocket/WebSocketSamplerPanel.form | 521 ------------------ 9 files changed, 2872 deletions(-) delete mode 100644 src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationConfig.form delete mode 100644 src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationConfig.java delete mode 100644 src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationRequest.form delete mode 100644 src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationRequest.java delete mode 100644 src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationResponse.form delete mode 100644 src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationResponse.java delete mode 100644 src/main/java/JMeter/plugins/controler/websocketapp/WebSocketSampler.java delete mode 100644 src/main/java/JMeter/plugins/controler/websocketapp/WebSocketSamplerGui.java delete mode 100644 src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSamplerPanel.form diff --git a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationConfig.form b/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationConfig.form deleted file mode 100644 index 2b1aa77..0000000 --- a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationConfig.form +++ /dev/null @@ -1,337 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationConfig.java b/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationConfig.java deleted file mode 100644 index 645d183..0000000 --- a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationConfig.java +++ /dev/null @@ -1,448 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package JMeter.plugins.functional.controler.websocketapp; - -import JMeter.plugins.functional.samplers.websocket.*; -import java.awt.Color; -import org.apache.jmeter.config.gui.ArgumentsPanel; -import org.apache.jmeter.protocol.http.gui.HTTPArgumentsPanel; -import org.apache.jorphan.logging.LoggingManager; -import org.apache.log.Logger; - -/** - * - * @author Maciej Zaleski - */ -public class WebSocketApplicationConfig extends javax.swing.JPanel { - private static final Logger log = LoggingManager.getLoggerForClass(); - private HTTPArgumentsPanel attributePanel; - - /** - * Creates new form WebSocketSamplerPanel - */ - public WebSocketApplicationConfig() { - initComponents(); - - attributePanel = new HTTPArgumentsPanel(); - querystringAttributesPanel.add(attributePanel); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - jPanel1 = new javax.swing.JPanel(); - jLabel1 = new javax.swing.JLabel(); - serverAddressTextField = new javax.swing.JTextField(); - jLabel2 = new javax.swing.JLabel(); - serverPortTextField = new javax.swing.JTextField(); - jPanel2 = new javax.swing.JPanel(); - jLabel3 = new javax.swing.JLabel(); - connectionTimeoutTextField = new javax.swing.JTextField(); - jPanel3 = new javax.swing.JPanel(); - jLabel4 = new javax.swing.JLabel(); - jLabel6 = new javax.swing.JLabel(); - protocolTextField = new javax.swing.JTextField(); - contentEncodingTextField = new javax.swing.JTextField(); - ignoreSslErrorsCheckBox = new javax.swing.JCheckBox(); - jLabel15 = new javax.swing.JLabel(); - implementationComboBox = new javax.swing.JComboBox(); - jPanel6 = new javax.swing.JPanel(); - jLabel10 = new javax.swing.JLabel(); - proxyAddressTextField = new javax.swing.JTextField(); - jLabel11 = new javax.swing.JLabel(); - proxyPortTextField = new javax.swing.JTextField(); - jLabel12 = new javax.swing.JLabel(); - proxyUsernameTextField = new javax.swing.JTextField(); - jLabel13 = new javax.swing.JLabel(); - proxyPasswordTextField = new javax.swing.JTextField(); - - jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Web Server")); - - jLabel1.setText("Server Name or IP:"); - - jLabel2.setText("Port Number:"); - - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); - jPanel1.setLayout(jPanel1Layout); - jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabel1) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(serverAddressTextField) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabel2) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(serverPortTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 43, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) - ); - jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel1) - .addComponent(serverAddressTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel2) - .addComponent(serverPortTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Timeout (milliseconds)")); - - jLabel3.setText("Connection:"); - - javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); - jPanel2.setLayout(jPanel2Layout); - jPanel2Layout.setHorizontalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel2Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabel3) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(connectionTimeoutTextField) - .addContainerGap()) - ); - jPanel2Layout.setVerticalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel2Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel3) - .addComponent(connectionTimeoutTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("WebSocket Settings")); - - jLabel4.setText("Protocol [ws/wss]:"); - - jLabel6.setText("Content encoding:"); - - protocolTextField.setToolTipText(""); - - ignoreSslErrorsCheckBox.setText("Ignore SSL certificate errors"); - - jLabel15.setText("Implementation:"); - - implementationComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "RFC6455 (v13)" })); - - javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); - jPanel3.setLayout(jPanel3Layout); - jPanel3Layout.setHorizontalGroup( - jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel3Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel3Layout.createSequentialGroup() - .addComponent(jLabel15) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(implementationComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(18, 18, 18) - .addComponent(jLabel4) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(protocolTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabel6) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(contentEncodingTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(jPanel3Layout.createSequentialGroup() - .addComponent(ignoreSslErrorsCheckBox) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) - ); - jPanel3Layout.setVerticalGroup( - jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel3Layout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel4) - .addComponent(protocolTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel6) - .addComponent(contentEncodingTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel15) - .addComponent(implementationComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(ignoreSslErrorsCheckBox)) - ); - - jPanel6.setBorder(javax.swing.BorderFactory.createTitledBorder("Proxy Server (currently not supported by Jetty)")); - - jLabel10.setText("Server Name or IP:"); - - jLabel11.setText("Port Number:"); - - jLabel12.setText("Username:"); - - jLabel13.setText("Password:"); - - javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6); - jPanel6.setLayout(jPanel6Layout); - jPanel6Layout.setHorizontalGroup( - jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel6Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabel10) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(proxyAddressTextField) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabel11) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(proxyPortTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 39, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(jLabel12) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(proxyUsernameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 64, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(jLabel13) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(proxyPasswordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 64, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) - ); - jPanel6Layout.setVerticalGroup( - jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel6Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(proxyUsernameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel12)) - .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel11) - .addComponent(proxyPortTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel10) - .addComponent(proxyAddressTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel13) - .addComponent(proxyPasswordTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addComponent(jPanel6, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - }// //GEN-END:initComponents - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JTextField connectionTimeoutTextField; - private javax.swing.JTextField contentEncodingTextField; - private javax.swing.JCheckBox ignoreSslErrorsCheckBox; - private javax.swing.JComboBox implementationComboBox; - private javax.swing.JLabel jLabel1; - private javax.swing.JLabel jLabel10; - private javax.swing.JLabel jLabel11; - private javax.swing.JLabel jLabel12; - private javax.swing.JLabel jLabel13; - private javax.swing.JLabel jLabel15; - private javax.swing.JLabel jLabel2; - private javax.swing.JLabel jLabel3; - private javax.swing.JLabel jLabel4; - private javax.swing.JLabel jLabel6; - private javax.swing.JPanel jPanel1; - private javax.swing.JPanel jPanel2; - private javax.swing.JPanel jPanel3; - private javax.swing.JPanel jPanel6; - private javax.swing.JTextField protocolTextField; - private javax.swing.JTextField proxyAddressTextField; - private javax.swing.JTextField proxyPasswordTextField; - private javax.swing.JTextField proxyPortTextField; - private javax.swing.JTextField proxyUsernameTextField; - private javax.swing.JTextField serverAddressTextField; - private javax.swing.JTextField serverPortTextField; - // End of variables declaration//GEN-END:variables - - public void initFields() { - } - - public void setCloseConncectionPattern(String closeConncectionPattern) { - closeConncectionPatternTextField.setText(closeConncectionPattern); - } - - public String getCloseConncectionPattern() { - return closeConncectionPatternTextField.getText(); - } - - public void setConnectionId(String connectionId) { - connectionIdTextField.setText(connectionId); - } - - public String getConnectionId() { - return connectionIdTextField.getText(); - } - - public void setContentEncoding(String contentEncoding) { - contentEncodingTextField.setText(contentEncoding); - } - - public String getContentEncoding() { - return contentEncodingTextField.getText(); - } - - public void setContextPath(String contextPath) { - contextPathTextField.setText(contextPath); - } - - public String getContextPath() { - return contextPathTextField.getText(); - } - - public void setProtocol(String protocol) { - protocolTextField.setText(protocol); - } - - public String getProtocol() { - return protocolTextField.getText(); - } - - public void setProxyAddress(String proxyAddress) { - proxyAddressTextField.setText(proxyAddress); - } - - public String getProxyAddress() { - return proxyAddressTextField.getText(); - } - - public void setProxyPassword(String proxyPassword) { - proxyPasswordTextField.setText(proxyPassword); - } - - public String getProxyPassword() { - return proxyPasswordTextField.getText(); - } - - public void setProxyPort(String proxyPort) { - proxyPortTextField.setText(proxyPort); - } - - public String getProxyPort() { - return proxyPortTextField.getText(); - } - - public void setProxyUsername(String proxyUsername) { - proxyUsernameTextField.setText(proxyUsername); - } - - public String getProxyUsername() { - return proxyUsernameTextField.getText(); - } - - public void setResponsePattern(String responsePattern) { - responsePatternTextField.setText(responsePattern); - } - - public String getResponsePattern() { - return responsePatternTextField.getText(); - } - - public void setResponseTimeout(String responseTimeout) { - responseTimeoutTextField.setText(responseTimeout); - } - - public String getResponseTimeout() { - return responseTimeoutTextField.getText(); - } - - public void setConnectionTimeout(String connectionTimeout) { - connectionTimeoutTextField.setText(connectionTimeout); - } - - public String getConnectionTimeout() { - return connectionTimeoutTextField.getText(); - } - - public void setServerAddress(String serverAddress) { - serverAddressTextField.setText(serverAddress); - } - - public String getServerAddress() { - return serverAddressTextField.getText(); - } - - public void setServerPort(String serverPort) { - serverPortTextField.setText(serverPort); - } - - public String getServerPort() { - return serverPortTextField.getText(); - } - - public void setRequestPayload(String requestPayload) { - requestPayloadEditorPane.setText(requestPayload); - } - - public String getRequestPayload() { - return requestPayloadEditorPane.getText(); - } - - public void setStreamingConnection(Boolean streamingConnection) { - streamingConnectionCheckBox.setSelected(streamingConnection); - } - - public Boolean isStreamingConnection() { - return streamingConnectionCheckBox.isSelected(); - } - - public void setIgnoreSslErrors(Boolean ignoreSslErrors) { - ignoreSslErrorsCheckBox.setSelected(ignoreSslErrors); - } - - public Boolean isIgnoreSslErrors() { - return ignoreSslErrorsCheckBox.isSelected(); - } - - public void setImplementation(String implementation) { - implementationComboBox.setSelectedItem(implementation); - } - - public String getImplementation() { - return (String) implementationComboBox.getSelectedItem(); - } - - public void setMessageBacklog(String messageBacklog) { - messageBacklogTextField.setText(messageBacklog); - } - - public String getMessageBacklog() { - return messageBacklogTextField.getText(); - } - - /** - * @return the attributePanel - */ - public ArgumentsPanel getAttributePanel() { - return attributePanel; - } -} diff --git a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationRequest.form b/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationRequest.form deleted file mode 100644 index fa5ea0a..0000000 --- a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationRequest.form +++ /dev/null @@ -1,201 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - <Editor/> - <Renderer/> - </Column> - <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> - <Title/> - <Editor/> - <Renderer/> - </Column> - <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> - <Title/> - <Editor/> - <Renderer/> - </Column> - <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> - <Title/> - <Editor/> - <Renderer/> - </Column> - </TableColumnModel> - </Property> - <Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor"> - <TableHeader reorderingAllowed="true" resizingAllowed="true"/> - </Property> - </Properties> - </Component> - </SubComponents> - </Container> - </SubComponents> - </Container> - </SubComponents> -</Form> diff --git a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationRequest.java b/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationRequest.java deleted file mode 100644 index 1deb0ea..0000000 --- a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationRequest.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package JMeter.plugins.functional.controler.websocketapp; - -import JMeter.plugins.functional.samplers.websocket.*; -import java.awt.Color; -import org.apache.jmeter.config.gui.ArgumentsPanel; -import org.apache.jmeter.protocol.http.gui.HTTPArgumentsPanel; -import org.apache.jorphan.logging.LoggingManager; -import org.apache.log.Logger; - -/** - * - * @author Maciej Zaleski - */ -public class WebSocketApplicationRequest extends javax.swing.JPanel { - private static final Logger log = LoggingManager.getLoggerForClass(); - private HTTPArgumentsPanel attributePanel; - - /** - * Creates new form WebSocketSamplerPanel - */ - public WebSocketApplicationRequest() { - initComponents(); - - attributePanel = new HTTPArgumentsPanel(); - querystringAttributesPanel.add(attributePanel); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents - private void initComponents() { - - jPanel4 = new javax.swing.JPanel(); - jScrollPane1 = new javax.swing.JScrollPane(); - requestPayloadEditorPane = new javax.swing.JEditorPane(); - jPanel1 = new javax.swing.JPanel(); - jPanel2 = new javax.swing.JPanel(); - jScrollPane2 = new javax.swing.JScrollPane(); - jTable1 = new javax.swing.JTable(); - - jPanel4.setBorder(javax.swing.BorderFactory.createTitledBorder("Client Request")); - - jScrollPane1.setViewportView(requestPayloadEditorPane); - - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); - jPanel1.setLayout(jPanel1Layout); - jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 0, Short.MAX_VALUE) - ); - jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 135, Short.MAX_VALUE) - ); - - javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4); - jPanel4.setLayout(jPanel4Layout); - jPanel4Layout.setHorizontalGroup( - jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel4Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 493, Short.MAX_VALUE) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) - ); - jPanel4Layout.setVerticalGroup( - jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) - ); - - jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Response handlers")); - - jTable1.setModel(new javax.swing.table.DefaultTableModel( - new Object [][] { - {"Successfull", "Quote received", "trade", new Boolean(true)}, - {"Market closed", "Quote failed", "quote", new Boolean(true)}, - {"System unavailable", "Quote failed", "quote", new Boolean(true)} - }, - new String [] { - "Handler name", "Response handler", "Application state", "Enabled" - } - ) { - Class[] types = new Class [] { - java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Boolean.class - }; - - public Class getColumnClass(int columnIndex) { - return types [columnIndex]; - } - }); - jScrollPane2.setViewportView(jTable1); - - javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); - jPanel2.setLayout(jPanel2Layout); - jPanel2Layout.setHorizontalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel2Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jScrollPane2)) - ); - jPanel2Layout.setVerticalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel2Layout.createSequentialGroup() - .addGap(19, 19, 19) - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 155, Short.MAX_VALUE) - .addContainerGap()) - ); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - ); - }// </editor-fold>//GEN-END:initComponents - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JPanel jPanel1; - private javax.swing.JPanel jPanel2; - private javax.swing.JPanel jPanel4; - private javax.swing.JScrollPane jScrollPane1; - private javax.swing.JScrollPane jScrollPane2; - private javax.swing.JTable jTable1; - private javax.swing.JEditorPane requestPayloadEditorPane; - // End of variables declaration//GEN-END:variables - - public void initFields() { - } - - public void setCloseConncectionPattern(String closeConncectionPattern) { - closeConncectionPatternTextField.setText(closeConncectionPattern); - } - - public String getCloseConncectionPattern() { - return closeConncectionPatternTextField.getText(); - } - - public void setConnectionId(String connectionId) { - connectionIdTextField.setText(connectionId); - } - - public String getConnectionId() { - return connectionIdTextField.getText(); - } - - public void setContentEncoding(String contentEncoding) { - contentEncodingTextField.setText(contentEncoding); - } - - public String getContentEncoding() { - return contentEncodingTextField.getText(); - } - - public void setContextPath(String contextPath) { - contextPathTextField.setText(contextPath); - } - - public String getContextPath() { - return contextPathTextField.getText(); - } - - public void setProtocol(String protocol) { - protocolTextField.setText(protocol); - } - - public String getProtocol() { - return protocolTextField.getText(); - } - - public void setProxyAddress(String proxyAddress) { - proxyAddressTextField.setText(proxyAddress); - } - - public String getProxyAddress() { - return proxyAddressTextField.getText(); - } - - public void setProxyPassword(String proxyPassword) { - proxyPasswordTextField.setText(proxyPassword); - } - - public String getProxyPassword() { - return proxyPasswordTextField.getText(); - } - - public void setProxyPort(String proxyPort) { - proxyPortTextField.setText(proxyPort); - } - - public String getProxyPort() { - return proxyPortTextField.getText(); - } - - public void setProxyUsername(String proxyUsername) { - proxyUsernameTextField.setText(proxyUsername); - } - - public String getProxyUsername() { - return proxyUsernameTextField.getText(); - } - - public void setResponsePattern(String responsePattern) { - responsePatternTextField.setText(responsePattern); - } - - public String getResponsePattern() { - return responsePatternTextField.getText(); - } - - public void setResponseTimeout(String responseTimeout) { - responseTimeoutTextField.setText(responseTimeout); - } - - public String getResponseTimeout() { - return responseTimeoutTextField.getText(); - } - - public void setConnectionTimeout(String connectionTimeout) { - connectionTimeoutTextField.setText(connectionTimeout); - } - - public String getConnectionTimeout() { - return connectionTimeoutTextField.getText(); - } - - public void setServerAddress(String serverAddress) { - serverAddressTextField.setText(serverAddress); - } - - public String getServerAddress() { - return serverAddressTextField.getText(); - } - - public void setServerPort(String serverPort) { - serverPortTextField.setText(serverPort); - } - - public String getServerPort() { - return serverPortTextField.getText(); - } - - public void setRequestPayload(String requestPayload) { - requestPayloadEditorPane.setText(requestPayload); - } - - public String getRequestPayload() { - return requestPayloadEditorPane.getText(); - } - - public void setStreamingConnection(Boolean streamingConnection) { - streamingConnectionCheckBox.setSelected(streamingConnection); - } - - public Boolean isStreamingConnection() { - return streamingConnectionCheckBox.isSelected(); - } - - public void setIgnoreSslErrors(Boolean ignoreSslErrors) { - ignoreSslErrorsCheckBox.setSelected(ignoreSslErrors); - } - - public Boolean isIgnoreSslErrors() { - return ignoreSslErrorsCheckBox.isSelected(); - } - - public void setImplementation(String implementation) { - implementationComboBox.setSelectedItem(implementation); - } - - public String getImplementation() { - return (String) implementationComboBox.getSelectedItem(); - } - - public void setMessageBacklog(String messageBacklog) { - messageBacklogTextField.setText(messageBacklog); - } - - public String getMessageBacklog() { - return messageBacklogTextField.getText(); - } - - /** - * @return the attributePanel - */ - public ArgumentsPanel getAttributePanel() { - return attributePanel; - } -} diff --git a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationResponse.form b/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationResponse.form deleted file mode 100644 index 25cf601..0000000 --- a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationResponse.form +++ /dev/null @@ -1,150 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> - -<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> - <AuxValues> - <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> - <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> - <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> - <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> - <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> - </AuxValues> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="jPanel5" max="32767" attributes="0"/> - <Component id="jPanel4" alignment="0" max="32767" attributes="0"/> - </Group> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Component id="jPanel5" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="jPanel4" max="32767" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Container class="javax.swing.JPanel" name="jPanel5"> - <Properties> - <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> - <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder title="Server message"/> - </Border> - </Property> - </Properties> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Component id="jLabel7" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="responsePatternTextField" max="32767" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="jLabel7" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="responsePatternTextField" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace max="32767" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Component class="javax.swing.JLabel" name="jLabel7"> - <Properties> - <Property name="text" type="java.lang.String" value="Response pattern:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="responsePatternTextField"> - </Component> - </SubComponents> - </Container> - <Container class="javax.swing.JPanel" name="jPanel4"> - <Properties> - <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> - <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder title="Client response"/> - </Border> - </Property> - </Properties> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="jScrollPane1" pref="493" max="32767" attributes="0"/> - <Component id="jPanel1" max="32767" attributes="0"/> - </Group> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="1" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Component id="jPanel1" max="32767" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="jScrollPane1" min="-2" pref="88" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Container class="javax.swing.JScrollPane" name="jScrollPane1"> - <AuxValues> - <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> - </AuxValues> - - <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> - <SubComponents> - <Component class="javax.swing.JEditorPane" name="requestPayloadEditorPane"> - </Component> - </SubComponents> - </Container> - <Container class="javax.swing.JPanel" name="jPanel1"> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <EmptySpace min="0" pref="0" max="32767" attributes="0"/> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <EmptySpace min="0" pref="130" max="32767" attributes="0"/> - </Group> - </DimensionLayout> - </Layout> - </Container> - </SubComponents> - </Container> - </SubComponents> -</Form> diff --git a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationResponse.java b/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationResponse.java deleted file mode 100644 index d8a3226..0000000 --- a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketApplicationResponse.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package JMeter.plugins.functional.controler.websocketapp; - -import JMeter.plugins.functional.samplers.websocket.*; -import java.awt.Color; -import org.apache.jmeter.config.gui.ArgumentsPanel; -import org.apache.jmeter.protocol.http.gui.HTTPArgumentsPanel; -import org.apache.jorphan.logging.LoggingManager; -import org.apache.log.Logger; - -/** - * - * @author Maciej Zaleski - */ -public class WebSocketApplicationResponse extends javax.swing.JPanel { - private static final Logger log = LoggingManager.getLoggerForClass(); - private HTTPArgumentsPanel attributePanel; - - /** - * Creates new form WebSocketSamplerPanel - */ - public WebSocketApplicationResponse() { - initComponents(); - - attributePanel = new HTTPArgumentsPanel(); - querystringAttributesPanel.add(attributePanel); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents - private void initComponents() { - - jPanel5 = new javax.swing.JPanel(); - jLabel7 = new javax.swing.JLabel(); - responsePatternTextField = new javax.swing.JTextField(); - jPanel4 = new javax.swing.JPanel(); - jScrollPane1 = new javax.swing.JScrollPane(); - requestPayloadEditorPane = new javax.swing.JEditorPane(); - jPanel1 = new javax.swing.JPanel(); - - jPanel5.setBorder(javax.swing.BorderFactory.createTitledBorder("Server message")); - - jLabel7.setText("Response pattern:"); - - javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5); - jPanel5.setLayout(jPanel5Layout); - jPanel5Layout.setHorizontalGroup( - jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel5Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabel7) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(responsePatternTextField) - .addContainerGap()) - ); - jPanel5Layout.setVerticalGroup( - jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel5Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel7) - .addComponent(responsePatternTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - jPanel4.setBorder(javax.swing.BorderFactory.createTitledBorder("Client response")); - - jScrollPane1.setViewportView(requestPayloadEditorPane); - - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); - jPanel1.setLayout(jPanel1Layout); - jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 0, Short.MAX_VALUE) - ); - jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 130, Short.MAX_VALUE) - ); - - javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4); - jPanel4.setLayout(jPanel4Layout); - jPanel4Layout.setHorizontalGroup( - jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel4Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 493, Short.MAX_VALUE) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) - ); - jPanel4Layout.setVerticalGroup( - jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) - ); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel5, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(jPanel5, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - ); - }// </editor-fold>//GEN-END:initComponents - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel jLabel7; - private javax.swing.JPanel jPanel1; - private javax.swing.JPanel jPanel4; - private javax.swing.JPanel jPanel5; - private javax.swing.JScrollPane jScrollPane1; - private javax.swing.JEditorPane requestPayloadEditorPane; - private javax.swing.JTextField responsePatternTextField; - // End of variables declaration//GEN-END:variables - - public void initFields() { - } - - public void setCloseConncectionPattern(String closeConncectionPattern) { - closeConncectionPatternTextField.setText(closeConncectionPattern); - } - - public String getCloseConncectionPattern() { - return closeConncectionPatternTextField.getText(); - } - - public void setConnectionId(String connectionId) { - connectionIdTextField.setText(connectionId); - } - - public String getConnectionId() { - return connectionIdTextField.getText(); - } - - public void setContentEncoding(String contentEncoding) { - contentEncodingTextField.setText(contentEncoding); - } - - public String getContentEncoding() { - return contentEncodingTextField.getText(); - } - - public void setContextPath(String contextPath) { - contextPathTextField.setText(contextPath); - } - - public String getContextPath() { - return contextPathTextField.getText(); - } - - public void setProtocol(String protocol) { - protocolTextField.setText(protocol); - } - - public String getProtocol() { - return protocolTextField.getText(); - } - - public void setProxyAddress(String proxyAddress) { - proxyAddressTextField.setText(proxyAddress); - } - - public String getProxyAddress() { - return proxyAddressTextField.getText(); - } - - public void setProxyPassword(String proxyPassword) { - proxyPasswordTextField.setText(proxyPassword); - } - - public String getProxyPassword() { - return proxyPasswordTextField.getText(); - } - - public void setProxyPort(String proxyPort) { - proxyPortTextField.setText(proxyPort); - } - - public String getProxyPort() { - return proxyPortTextField.getText(); - } - - public void setProxyUsername(String proxyUsername) { - proxyUsernameTextField.setText(proxyUsername); - } - - public String getProxyUsername() { - return proxyUsernameTextField.getText(); - } - - public void setResponsePattern(String responsePattern) { - responsePatternTextField.setText(responsePattern); - } - - public String getResponsePattern() { - return responsePatternTextField.getText(); - } - - public void setResponseTimeout(String responseTimeout) { - responseTimeoutTextField.setText(responseTimeout); - } - - public String getResponseTimeout() { - return responseTimeoutTextField.getText(); - } - - public void setConnectionTimeout(String connectionTimeout) { - connectionTimeoutTextField.setText(connectionTimeout); - } - - public String getConnectionTimeout() { - return connectionTimeoutTextField.getText(); - } - - public void setServerAddress(String serverAddress) { - serverAddressTextField.setText(serverAddress); - } - - public String getServerAddress() { - return serverAddressTextField.getText(); - } - - public void setServerPort(String serverPort) { - serverPortTextField.setText(serverPort); - } - - public String getServerPort() { - return serverPortTextField.getText(); - } - - public void setRequestPayload(String requestPayload) { - requestPayloadEditorPane.setText(requestPayload); - } - - public String getRequestPayload() { - return requestPayloadEditorPane.getText(); - } - - public void setStreamingConnection(Boolean streamingConnection) { - streamingConnectionCheckBox.setSelected(streamingConnection); - } - - public Boolean isStreamingConnection() { - return streamingConnectionCheckBox.isSelected(); - } - - public void setIgnoreSslErrors(Boolean ignoreSslErrors) { - ignoreSslErrorsCheckBox.setSelected(ignoreSslErrors); - } - - public Boolean isIgnoreSslErrors() { - return ignoreSslErrorsCheckBox.isSelected(); - } - - public void setImplementation(String implementation) { - implementationComboBox.setSelectedItem(implementation); - } - - public String getImplementation() { - return (String) implementationComboBox.getSelectedItem(); - } - - public void setMessageBacklog(String messageBacklog) { - messageBacklogTextField.setText(messageBacklog); - } - - public String getMessageBacklog() { - return messageBacklogTextField.getText(); - } - - /** - * @return the attributePanel - */ - public ArgumentsPanel getAttributePanel() { - return attributePanel; - } -} diff --git a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketSampler.java b/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketSampler.java deleted file mode 100644 index 7a8b429..0000000 --- a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketSampler.java +++ /dev/null @@ -1,468 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package JMeter.plugins.functional.controler.websocketapp; - -import JMeter.plugins.functional.samplers.websocket.*; -import java.io.IOException; -import org.apache.commons.lang3.StringUtils; -import org.apache.jmeter.config.Argument; -import org.apache.jmeter.config.Arguments; -import org.apache.jmeter.protocol.http.util.EncoderCache; -import org.apache.jmeter.protocol.http.util.HTTPArgument; -import org.apache.jmeter.protocol.http.util.HTTPConstants; -import org.apache.jmeter.samplers.AbstractSampler; -import org.apache.jmeter.samplers.Entry; -import org.apache.jmeter.samplers.SampleResult; -import org.apache.jmeter.testelement.TestElement; -import org.apache.jmeter.testelement.property.*; -import org.apache.jorphan.logging.LoggingManager; -import org.apache.jorphan.util.JOrphanUtils; -import org.apache.log.Logger; - - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; -import org.apache.jmeter.testelement.TestStateListener; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; -import org.eclipse.jetty.websocket.client.WebSocketClient; - -/** - * - * @author Maciej Zaleski - */ -public class WebSocketSampler extends AbstractSampler implements TestStateListener { - private static final Logger log = LoggingManager.getLoggerForClass(); - - private static final String ARG_VAL_SEP = "="; // $NON-NLS-1$ - private static final String QRY_SEP = "&"; // $NON-NLS-1$ - private static final String WS_PREFIX = "ws://"; // $NON-NLS-1$ - private static final String WSS_PREFIX = "wss://"; // $NON-NLS-1$ - private static final String DEFAULT_PROTOCOL = "ws"; - - private static Map<String, ServiceSocket> connectionList; - - public WebSocketSampler() { - super(); - setName("WebSocket sampler"); - } - - private ServiceSocket getConnectionSocket() throws URISyntaxException, Exception { - URI uri = getUri(); - - String connectionId = getThreadName() + getConnectionId(); - ServiceSocket socket; - WebSocketClient webSocketClient; - if (isStreamingConnection()) { - if (connectionList.containsKey(connectionId)) { - socket = connectionList.get(connectionId); - socket.initialize(); - return socket; - } else { - socket = new ServiceSocket(this); - connectionList.put(connectionId, socket); - } - } else { - socket = new ServiceSocket(this); - } - - SslContextFactory sslContexFactory = new SslContextFactory(); - sslContexFactory.setTrustAll(isIgnoreSslErrors()); - webSocketClient = new WebSocketClient(sslContexFactory); - - webSocketClient.start(); - ClientUpgradeRequest request = new ClientUpgradeRequest(); - webSocketClient.connect(socket, uri, request); - - int connectionTimeout = Integer.parseInt(getConnectionTimeout()); - socket.awaitOpen(connectionTimeout, TimeUnit.MILLISECONDS); - - return socket; - } - - @Override - public SampleResult sample(Entry entry) { - ServiceSocket socket = null; - SampleResult sampleResult = new SampleResult(); - sampleResult.setSampleLabel(getName()); - sampleResult.setDataEncoding(getContentEncoding()); - - StringBuilder errorList = new StringBuilder(); - errorList.append("\n\n[Problems]\n"); - - boolean isOK = false; - - String payloadMessage = getRequestPayload(); - sampleResult.setSamplerData(payloadMessage); - sampleResult.sampleStart(); - - try { - socket = getConnectionSocket(); - if (socket == null) { - sampleResult.setResponseCode("500"); - sampleResult.setSuccessful(false); - sampleResult.sampleEnd(); - sampleResult.setResponseMessage(errorList.toString()); - errorList.append(" - Connection couldn't be opened").append("\n"); - return sampleResult; - } - - if (!payloadMessage.isEmpty()) { - socket.sendMessage(payloadMessage); - } - - int responseTimeout = Integer.parseInt(getResponseTimeout()); - socket.awaitClose(responseTimeout, TimeUnit.MILLISECONDS); - - - if (socket.getResponseMessage() == null || socket.getResponseMessage().isEmpty()) { - sampleResult.setResponseCode("204"); - } - - if (socket.getError() != 0) { - isOK = false; - sampleResult.setResponseCode(socket.getError().toString()); - } else { - sampleResult.setResponseCodeOK(); - isOK = true; - } - - sampleResult.setResponseData(socket.getResponseMessage(), getContentEncoding()); - - } catch (URISyntaxException e) { - errorList.append(" - Invalid URI syntax: ").append(e.getMessage()).append("\n").append(StringUtils.join(e.getStackTrace(), "\n")).append("\n"); - } catch (IOException e) { - errorList.append(" - IO Exception: ").append(e.getMessage()).append("\n").append(StringUtils.join(e.getStackTrace(), "\n")).append("\n"); - } catch (NumberFormatException e) { - errorList.append(" - Cannot parse number: ").append(e.getMessage()).append("\n").append(StringUtils.join(e.getStackTrace(), "\n")).append("\n"); - } catch (InterruptedException e) { - errorList.append(" - Execution interrupted: ").append(e.getMessage()).append("\n").append(StringUtils.join(e.getStackTrace(), "\n")).append("\n"); - } catch (Exception e) { - errorList.append(" - Unexpected error: ").append(e.getMessage()).append("\n").append(StringUtils.join(e.getStackTrace(), "\n")).append("\n"); - } - - sampleResult.sampleEnd(); - sampleResult.setSuccessful(isOK); - - String logMessage = (socket != null) ? socket.getLogMessage() : ""; - sampleResult.setResponseMessage(logMessage + errorList); - return sampleResult; - } - - @Override - public void setName(String name) { - if (name != null) { - setProperty(TestElement.NAME, name); - } - } - - @Override - public String getName() { - return getPropertyAsString(TestElement.NAME); - } - - @Override - public void setComment(String comment) { - setProperty(new StringProperty(TestElement.COMMENTS, comment)); - } - - @Override - public String getComment() { - return getProperty(TestElement.COMMENTS).getStringValue(); - } - - public URI getUri() throws URISyntaxException { - String path = this.getContextPath(); - // Hack to allow entire URL to be provided in host field - if (path.startsWith(WS_PREFIX) - || path.startsWith(WSS_PREFIX)) { - return new URI(path); - } - String domain = getServerAddress(); - String protocol = getProtocol(); - // HTTP URLs must be absolute, allow file to be relative - if (!path.startsWith("/")) { // $NON-NLS-1$ - path = "/" + path; // $NON-NLS-1$ - } - - String queryString = getQueryString(getContentEncoding()); - if (isProtocolDefaultPort()) { - return new URI(protocol, null, domain, -1, path, queryString, null); - } - return new URI(protocol, null, domain, Integer.parseInt(getServerPort()), path, queryString, null); - } - - /** - * Tell whether the default port for the specified protocol is used - * - * @return true if the default port number for the protocol is used, false - * otherwise - */ - public boolean isProtocolDefaultPort() { - final int port = Integer.parseInt(getServerPort()); - final String protocol = getProtocol(); - return ("ws".equalsIgnoreCase(protocol) && port == HTTPConstants.DEFAULT_HTTP_PORT) - || ("wss".equalsIgnoreCase(protocol) && port == HTTPConstants.DEFAULT_HTTPS_PORT); - } - - public String getServerPort() { - final String port_s = getPropertyAsString("serverPort", "0"); - Integer port; - String protocol = getProtocol(); - - try { - port = Integer.parseInt(port_s); - } catch (Exception ex) { - port = 0; - } - - if (port == 0) { - if ("wss".equalsIgnoreCase(protocol)) { - return String.valueOf(HTTPConstants.DEFAULT_HTTPS_PORT); - } else if ("ws".equalsIgnoreCase(protocol)) { - return String.valueOf(HTTPConstants.DEFAULT_HTTP_PORT); - } - } - return port.toString(); - } - - public void setServerPort(String port) { - setProperty("serverPort", port); - } - - public String getResponseTimeout() { - return getPropertyAsString("responseTimeout", "20000"); - } - - public void setResponseTimeout(String responseTimeout) { - setProperty("responseTimeout", responseTimeout); - } - - - public String getConnectionTimeout() { - return getPropertyAsString("connectionTimeout", "5000"); - } - - public void setConnectionTimeout(String connectionTimeout) { - setProperty("connectionTimeout", connectionTimeout); - } - - public void setProtocol(String protocol) { - setProperty("protocol", protocol); - } - - public String getProtocol() { - String protocol = getPropertyAsString("protocol"); - if (protocol == null || protocol.isEmpty()) { - return DEFAULT_PROTOCOL; - } - return protocol; - } - - public void setServerAddress(String serverAddress) { - setProperty("serverAddress", serverAddress); - } - - public String getServerAddress() { - return getPropertyAsString("serverAddress"); - } - - - public void setImplementation(String implementation) { - setProperty("implementation", implementation); - } - - public String getImplementation() { - return getPropertyAsString("implementation"); - } - - public void setContextPath(String contextPath) { - setProperty("contextPath", contextPath); - } - - public String getContextPath() { - return getPropertyAsString("contextPath"); - } - - public void setContentEncoding(String contentEncoding) { - setProperty("contentEncoding", contentEncoding); - } - - public String getContentEncoding() { - return getPropertyAsString("contentEncoding", "UTF-8"); - } - - public void setRequestPayload(String requestPayload) { - setProperty("requestPayload", requestPayload); - } - - public String getRequestPayload() { - return getPropertyAsString("requestPayload"); - } - - public void setIgnoreSslErrors(Boolean ignoreSslErrors) { - setProperty("ignoreSslErrors", ignoreSslErrors); - } - - public Boolean isIgnoreSslErrors() { - return getPropertyAsBoolean("ignoreSslErrors"); - } - - public void setStreamingConnection(Boolean streamingConnection) { - setProperty("streamingConnection", streamingConnection); - } - - public Boolean isStreamingConnection() { - return getPropertyAsBoolean("streamingConnection"); - } - - public void setConnectionId(String connectionId) { - setProperty("connectionId", connectionId); - } - - public String getConnectionId() { - return getPropertyAsString("connectionId"); - } - - public void setResponsePattern(String responsePattern) { - setProperty("responsePattern", responsePattern); - } - - public String getResponsePattern() { - return getPropertyAsString("responsePattern"); - } - - public void setCloseConncectionPattern(String closeConncectionPattern) { - setProperty("closeConncectionPattern", closeConncectionPattern); - } - - public String getCloseConncectionPattern() { - return getPropertyAsString("closeConncectionPattern"); - } - - public void setProxyAddress(String proxyAddress) { - setProperty("proxyAddress", proxyAddress); - } - - public String getProxyAddress() { - return getPropertyAsString("proxyAddress"); - } - - public void setProxyPassword(String proxyPassword) { - setProperty("proxyPassword", proxyPassword); - } - - public String getProxyPassword() { - return getPropertyAsString("proxyPassword"); - } - - public void setProxyPort(String proxyPort) { - setProperty("proxyPort", proxyPort); - } - - public String getProxyPort() { - return getPropertyAsString("proxyPort"); - } - - public void setProxyUsername(String proxyUsername) { - setProperty("proxyUsername", proxyUsername); - } - - public String getProxyUsername() { - return getPropertyAsString("proxyUsername"); - } - - public void setMessageBacklog(String messageBacklog) { - setProperty("messageBacklog", messageBacklog); - } - - public String getMessageBacklog() { - return getPropertyAsString("messageBacklog", "3"); - } - - - - public String getQueryString(String contentEncoding) { - // Check if the sampler has a specified content encoding - if (JOrphanUtils.isBlank(contentEncoding)) { - // We use the encoding which should be used according to the HTTP spec, which is UTF-8 - contentEncoding = EncoderCache.URL_ARGUMENT_ENCODING; - } - StringBuilder buf = new StringBuilder(); - PropertyIterator iter = getQueryStringParameters().iterator(); - boolean first = true; - while (iter.hasNext()) { - HTTPArgument item = null; - Object objectValue = iter.next().getObjectValue(); - try { - item = (HTTPArgument) objectValue; - } catch (ClassCastException e) { - item = new HTTPArgument((Argument) objectValue); - } - final String encodedName = item.getEncodedName(); - if (encodedName.length() == 0) { - continue; // Skip parameters with a blank name (allows use of optional variables in parameter lists) - } - if (!first) { - buf.append(QRY_SEP); - } else { - first = false; - } - buf.append(encodedName); - if (item.getMetaData() == null) { - buf.append(ARG_VAL_SEP); - } else { - buf.append(item.getMetaData()); - } - - // Encode the parameter value in the specified content encoding - try { - buf.append(item.getEncodedValue(contentEncoding)); - } catch (UnsupportedEncodingException e) { - log.warn("Unable to encode parameter in encoding " + contentEncoding + ", parameter value not included in query string"); - } - } - return buf.toString(); - } - - public void setQueryStringParameters(Arguments queryStringParameters) { - setProperty(new TestElementProperty("queryStringParameters", queryStringParameters)); - } - - public Arguments getQueryStringParameters() { - Arguments args = (Arguments) getProperty("queryStringParameters").getObjectValue(); - return args; - } - - - @Override - public void testStarted() { - testStarted("unknown"); - } - - @Override - public void testStarted(String host) { - connectionList = new ConcurrentHashMap<String, ServiceSocket>(); - } - - @Override - public void testEnded() { - testEnded("unknown"); - } - - @Override - public void testEnded(String host) { - for (ServiceSocket socket : connectionList.values()) { - socket.close(); - } - } - - - -} diff --git a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketSamplerGui.java b/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketSamplerGui.java deleted file mode 100644 index e3801f9..0000000 --- a/src/main/java/JMeter/plugins/controler/websocketapp/WebSocketSamplerGui.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package JMeter.plugins.functional.controler.websocketapp; - -import java.awt.BorderLayout; -import org.apache.jmeter.config.Arguments; -import org.apache.jmeter.config.gui.ArgumentsPanel; -import org.apache.jmeter.control.gui.AbstractControllerGui; -import org.apache.jmeter.testelement.TestElement; -import org.apache.jorphan.logging.LoggingManager; -import org.apache.log.Logger; - -/** - * - * @author Maciej Zaleski - */ -public class WebSocketSamplerGui extends AbstractControllerGui { - - private WebSocketApplicationConfig webSocketSamplerPanel; - private static final Logger log = LoggingManager.getLoggerForClass(); - - public WebSocketSamplerGui() { - super(); - init(); - initFields(); - - setLayout(new BorderLayout(0, 5)); - setBorder(makeBorder()); - - add(makeTitlePanel(), BorderLayout.NORTH); - add(webSocketSamplerPanel, BorderLayout.CENTER); - } - - @Override - public String getStaticLabel() { - return "WebSocket Sampler"; - } - - @Override - public String getLabelResource() { - throw new IllegalStateException("This shouldn't be called"); //$NON-NLS-1$ - } - - @Override - public void configure(TestElement element) { - super.configure(element); - if (element instanceof WebSocketSampler) { - WebSocketSampler webSocketSamplerTestElement = (WebSocketSampler) element; - webSocketSamplerPanel.setServerAddress(webSocketSamplerTestElement.getServerAddress()); - webSocketSamplerPanel.setServerPort(webSocketSamplerTestElement.getServerPort()); - webSocketSamplerPanel.setImplementation(webSocketSamplerTestElement.getImplementation()); - webSocketSamplerPanel.setProtocol(webSocketSamplerTestElement.getProtocol()); - webSocketSamplerPanel.setContextPath(webSocketSamplerTestElement.getContextPath()); - webSocketSamplerPanel.setContentEncoding(webSocketSamplerTestElement.getContentEncoding()); - webSocketSamplerPanel.setRequestPayload(webSocketSamplerTestElement.getRequestPayload()); - webSocketSamplerPanel.setResponseTimeout(webSocketSamplerTestElement.getResponseTimeout()); - webSocketSamplerPanel.setConnectionTimeout(webSocketSamplerTestElement.getConnectionTimeout()); - webSocketSamplerPanel.setIgnoreSslErrors(webSocketSamplerTestElement.isIgnoreSslErrors()); - webSocketSamplerPanel.setStreamingConnection(webSocketSamplerTestElement.isStreamingConnection()); - webSocketSamplerPanel.setConnectionId(webSocketSamplerTestElement.getConnectionId()); - webSocketSamplerPanel.setResponsePattern(webSocketSamplerTestElement.getResponsePattern()); - webSocketSamplerPanel.setCloseConncectionPattern(webSocketSamplerTestElement.getCloseConncectionPattern()); - webSocketSamplerPanel.setProxyAddress(webSocketSamplerTestElement.getProxyAddress()); - webSocketSamplerPanel.setProxyPassword(webSocketSamplerTestElement.getProxyPassword()); - webSocketSamplerPanel.setProxyPort(webSocketSamplerTestElement.getProxyPort()); - webSocketSamplerPanel.setProxyUsername(webSocketSamplerTestElement.getProxyUsername()); - webSocketSamplerPanel.setMessageBacklog(webSocketSamplerTestElement.getMessageBacklog()); - - Arguments queryStringParameters = webSocketSamplerTestElement.getQueryStringParameters(); - if (queryStringParameters != null) { - webSocketSamplerPanel.getAttributePanel().configure(queryStringParameters); - } - } - } - - @Override - public TestElement createTestElement() { - WebSocketSampler preproc = new WebSocketSampler(); - configureTestElement(preproc); - return preproc; - } - - @Override - public void modifyTestElement(TestElement te) { - configureTestElement(te); - if (te instanceof WebSocketSampler) { - WebSocketSampler webSocketSamplerTestElement = (WebSocketSampler) te; - webSocketSamplerTestElement.setServerAddress(webSocketSamplerPanel.getServerAddress()); - webSocketSamplerTestElement.setServerPort(webSocketSamplerPanel.getServerPort()); - webSocketSamplerTestElement.setImplementation(webSocketSamplerPanel.getImplementation()); - webSocketSamplerTestElement.setProtocol(webSocketSamplerPanel.getProtocol()); - webSocketSamplerTestElement.setContextPath(webSocketSamplerPanel.getContextPath()); - webSocketSamplerTestElement.setContentEncoding(webSocketSamplerPanel.getContentEncoding()); - webSocketSamplerTestElement.setRequestPayload(webSocketSamplerPanel.getRequestPayload()); - webSocketSamplerTestElement.setConnectionTimeout(webSocketSamplerPanel.getConnectionTimeout()); - webSocketSamplerTestElement.setResponseTimeout(webSocketSamplerPanel.getResponseTimeout()); - webSocketSamplerTestElement.setIgnoreSslErrors(webSocketSamplerPanel.isIgnoreSslErrors()); - webSocketSamplerTestElement.setStreamingConnection(webSocketSamplerPanel.isStreamingConnection()); - webSocketSamplerTestElement.setConnectionId(webSocketSamplerPanel.getConnectionId()); - webSocketSamplerTestElement.setResponsePattern(webSocketSamplerPanel.getResponsePattern()); - webSocketSamplerTestElement.setCloseConncectionPattern(webSocketSamplerPanel.getCloseConncectionPattern()); - webSocketSamplerTestElement.setProxyAddress(webSocketSamplerPanel.getProxyAddress()); - webSocketSamplerTestElement.setProxyPassword(webSocketSamplerPanel.getProxyPassword()); - webSocketSamplerTestElement.setProxyPort(webSocketSamplerPanel.getProxyPort()); - webSocketSamplerTestElement.setProxyUsername(webSocketSamplerPanel.getProxyUsername()); - webSocketSamplerTestElement.setMessageBacklog(webSocketSamplerPanel.getMessageBacklog()); - - ArgumentsPanel queryStringParameters = webSocketSamplerPanel.getAttributePanel(); - if (queryStringParameters != null) { - webSocketSamplerTestElement.setQueryStringParameters((Arguments)queryStringParameters.createTestElement()); - } - } - } - - @Override - public void clearGui() { - super.clearGui(); - initFields(); - } - - private void init() { - webSocketSamplerPanel = new WebSocketApplicationConfig(); - } - - private void initFields() { - webSocketSamplerPanel.initFields(); - } -} diff --git a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSamplerPanel.form b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSamplerPanel.form deleted file mode 100644 index 2ed45b8..0000000 --- a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSamplerPanel.form +++ /dev/null @@ -1,521 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> - -<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> - <AuxValues> - <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> - <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> - <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> - <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> - <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> - </AuxValues> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="jPanel3" max="32767" attributes="0"/> - <Component id="jPanel5" max="32767" attributes="0"/> - <Group type="102" alignment="0" attributes="0"> - <Component id="jPanel1" max="32767" attributes="0"/> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Component id="jPanel2" max="32767" attributes="0"/> - </Group> - <Component id="jPanel6" max="32767" attributes="0"/> - </Group> - <EmptySpace min="-2" max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="jPanel2" min="-2" max="-2" attributes="0"/> - <Component id="jPanel1" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace max="-2" attributes="0"/> - <Component id="jPanel3" max="32767" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="jPanel5" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="jPanel6" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Container class="javax.swing.JPanel" name="jPanel1"> - <Properties> - <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> - <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder title="Web Server"/> - </Border> - </Property> - </Properties> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Component id="jLabel1" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="serverAddressTextField" max="32767" attributes="0"/> - <EmptySpace type="unrelated" max="-2" attributes="0"/> - <Component id="jLabel2" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="serverPortTextField" min="-2" pref="43" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="serverAddressTextField" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="serverPortTextField" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace max="32767" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Component class="javax.swing.JLabel" name="jLabel1"> - <Properties> - <Property name="text" type="java.lang.String" value="Server Name or IP:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="serverAddressTextField"> - </Component> - <Component class="javax.swing.JLabel" name="jLabel2"> - <Properties> - <Property name="text" type="java.lang.String" value="Port Number:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="serverPortTextField"> - </Component> - </SubComponents> - </Container> - <Container class="javax.swing.JPanel" name="jPanel2"> - <Properties> - <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> - <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder title="Timeout (milliseconds)"/> - </Border> - </Property> - </Properties> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Component id="jLabel3" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Component id="connectionTimeoutTextField" max="32767" attributes="0"/> - <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/> - <Component id="jLabel17" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Component id="responseTimeoutTextField" max="32767" attributes="0"/> - <EmptySpace min="-2" max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="connectionTimeoutTextField" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="jLabel17" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="responseTimeoutTextField" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace max="32767" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Component class="javax.swing.JLabel" name="jLabel3"> - <Properties> - <Property name="text" type="java.lang.String" value="Connection:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="connectionTimeoutTextField"> - </Component> - <Component class="javax.swing.JLabel" name="jLabel17"> - <Properties> - <Property name="text" type="java.lang.String" value="Response:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="responseTimeoutTextField"> - </Component> - </SubComponents> - </Container> - <Container class="javax.swing.JPanel" name="jPanel3"> - <Properties> - <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> - <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder title="WebSocket Request"/> - </Border> - </Property> - </Properties> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="querystringAttributesPanel" max="32767" attributes="0"/> - <Component id="jScrollPane1" max="32767" attributes="0"/> - <Group type="102" alignment="0" attributes="0"> - <Component id="jLabel15" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Component id="implementationComboBox" pref="0" max="32767" attributes="0"/> - <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/> - <Component id="jLabel4" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Component id="protocolTextField" min="-2" pref="40" max="-2" attributes="0"/> - <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/> - <Component id="jLabel6" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Component id="contentEncodingTextField" min="-2" pref="40" max="-2" attributes="0"/> - <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/> - <Component id="jLabel8" min="-2" max="-2" attributes="0"/> - <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/> - <Component id="connectionIdTextField" max="32767" attributes="0"/> - </Group> - <Group type="102" attributes="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="jLabel14" min="-2" max="-2" attributes="0"/> - <Group type="102" alignment="0" attributes="0"> - <Component id="ignoreSslErrorsCheckBox" min="-2" max="-2" attributes="0"/> - <EmptySpace type="unrelated" max="-2" attributes="0"/> - <Component id="streamingConnectionCheckBox" min="-2" max="-2" attributes="0"/> - </Group> - </Group> - <EmptySpace min="0" pref="0" max="32767" attributes="0"/> - </Group> - <Group type="102" alignment="0" attributes="0"> - <Component id="jLabel5" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="contextPathTextField" max="32767" attributes="0"/> - </Group> - </Group> - <EmptySpace min="-2" max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace min="-2" pref="10" max="-2" attributes="0"/> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="jLabel4" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="protocolTextField" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="jLabel6" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="contentEncodingTextField" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="jLabel8" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="connectionIdTextField" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="jLabel15" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="implementationComboBox" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="jLabel5" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="contextPathTextField" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="ignoreSslErrorsCheckBox" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="streamingConnectionCheckBox" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Component id="querystringAttributesPanel" pref="102" max="32767" attributes="0"/> - <EmptySpace min="-2" pref="8" max="-2" attributes="0"/> - <Component id="jLabel14" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Component id="jScrollPane1" pref="118" max="32767" attributes="0"/> - <EmptySpace min="-2" max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Component class="javax.swing.JLabel" name="jLabel4"> - <Properties> - <Property name="text" type="java.lang.String" value="Protocol [ws/wss]:"/> - </Properties> - </Component> - <Component class="javax.swing.JLabel" name="jLabel5"> - <Properties> - <Property name="text" type="java.lang.String" value="Path:"/> - </Properties> - </Component> - <Component class="javax.swing.JLabel" name="jLabel6"> - <Properties> - <Property name="text" type="java.lang.String" value="Content encoding:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="contextPathTextField"> - </Component> - <Component class="javax.swing.JTextField" name="protocolTextField"> - <Properties> - <Property name="toolTipText" type="java.lang.String" value=""/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="contentEncodingTextField"> - </Component> - <Component class="javax.swing.JLabel" name="jLabel8"> - <Properties> - <Property name="text" type="java.lang.String" value="Connection Id:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="connectionIdTextField"> - </Component> - <Container class="javax.swing.JPanel" name="querystringAttributesPanel"> - - <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/> - </Container> - <Component class="javax.swing.JCheckBox" name="ignoreSslErrorsCheckBox"> - <Properties> - <Property name="text" type="java.lang.String" value="Ignore SSL certificate errors"/> - </Properties> - </Component> - <Container class="javax.swing.JScrollPane" name="jScrollPane1"> - <AuxValues> - <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> - </AuxValues> - - <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> - <SubComponents> - <Component class="javax.swing.JEditorPane" name="requestPayloadEditorPane"> - </Component> - </SubComponents> - </Container> - <Component class="javax.swing.JLabel" name="jLabel14"> - <Properties> - <Property name="text" type="java.lang.String" value="Request data"/> - </Properties> - </Component> - <Component class="javax.swing.JLabel" name="jLabel15"> - <Properties> - <Property name="text" type="java.lang.String" value="Implementation:"/> - </Properties> - </Component> - <Component class="javax.swing.JComboBox" name="implementationComboBox"> - <Properties> - <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor"> - <StringArray count="1"> - <StringItem index="0" value="RFC6455 (v13)"/> - </StringArray> - </Property> - </Properties> - </Component> - <Component class="javax.swing.JCheckBox" name="streamingConnectionCheckBox"> - <Properties> - <Property name="text" type="java.lang.String" value="Streaming connection"/> - </Properties> - </Component> - </SubComponents> - </Container> - <Container class="javax.swing.JPanel" name="jPanel5"> - <Properties> - <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> - <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder title="WebSocket Response"/> - </Border> - </Property> - </Properties> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <Component id="jLabel7" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="responsePatternTextField" max="32767" attributes="0"/> - <EmptySpace type="separate" max="-2" attributes="0"/> - <Component id="jLabel16" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Component id="messageBacklogTextField" min="-2" pref="40" max="-2" attributes="0"/> - </Group> - <Group type="102" alignment="1" attributes="0"> - <Component id="jLabel9" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="closeConncectionPatternTextField" max="32767" attributes="0"/> - </Group> - </Group> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="103" alignment="0" groupAlignment="3" attributes="0"> - <Component id="jLabel16" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="messageBacklogTextField" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="jLabel7" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="responsePatternTextField" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - </Group> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="jLabel9" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="closeConncectionPatternTextField" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace max="32767" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Component class="javax.swing.JLabel" name="jLabel7"> - <Properties> - <Property name="text" type="java.lang.String" value="Response pattern:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="responsePatternTextField"> - </Component> - <Component class="javax.swing.JLabel" name="jLabel9"> - <Properties> - <Property name="text" type="java.lang.String" value="Close connection pattern:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="closeConncectionPatternTextField"> - </Component> - <Component class="javax.swing.JLabel" name="jLabel16"> - <Properties> - <Property name="text" type="java.lang.String" value="Message backlog:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="messageBacklogTextField"> - </Component> - </SubComponents> - </Container> - <Container class="javax.swing.JPanel" name="jPanel6"> - <Properties> - <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> - <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder title="Proxy Server (currently not supported by Jetty)"/> - </Border> - </Property> - </Properties> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Component id="jLabel10" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="proxyAddressTextField" max="32767" attributes="0"/> - <EmptySpace type="unrelated" max="-2" attributes="0"/> - <Component id="jLabel11" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="proxyPortTextField" min="-2" pref="39" max="-2" attributes="0"/> - <EmptySpace type="separate" max="-2" attributes="0"/> - <Component id="jLabel12" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="proxyUsernameTextField" min="-2" pref="64" max="-2" attributes="0"/> - <EmptySpace min="-2" pref="18" max="-2" attributes="0"/> - <Component id="jLabel13" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="proxyPasswordTextField" min="-2" pref="64" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="103" alignment="0" groupAlignment="3" attributes="0"> - <Component id="proxyUsernameTextField" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="jLabel12" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="jLabel11" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="proxyPortTextField" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="jLabel10" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="proxyAddressTextField" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="jLabel13" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="proxyPasswordTextField" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - </Group> - <EmptySpace max="32767" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Component class="javax.swing.JLabel" name="jLabel10"> - <Properties> - <Property name="text" type="java.lang.String" value="Server Name or IP:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="proxyAddressTextField"> - <Properties> - <Property name="enabled" type="boolean" value="false"/> - </Properties> - </Component> - <Component class="javax.swing.JLabel" name="jLabel11"> - <Properties> - <Property name="text" type="java.lang.String" value="Port Number:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="proxyPortTextField"> - <Properties> - <Property name="enabled" type="boolean" value="false"/> - </Properties> - </Component> - <Component class="javax.swing.JLabel" name="jLabel12"> - <Properties> - <Property name="text" type="java.lang.String" value="Username:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="proxyUsernameTextField"> - <Properties> - <Property name="enabled" type="boolean" value="false"/> - </Properties> - </Component> - <Component class="javax.swing.JLabel" name="jLabel13"> - <Properties> - <Property name="text" type="java.lang.String" value="Password:"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="proxyPasswordTextField"> - <Properties> - <Property name="enabled" type="boolean" value="false"/> - </Properties> - </Component> - </SubComponents> - </Container> - </SubComponents> -</Form> From 77d70c7bced0c49c1f5e2a75f5168bb8fd353595 Mon Sep 17 00:00:00 2001 From: Vadim Elkin <Vadim.Elkin@tradingscreen.com> Date: Thu, 4 Sep 2014 11:57:35 -0400 Subject: [PATCH 6/8] Some cleanup If a sampler reuses a streaming websocket created by some earlier sampler, the new sampler's parameters are picked up --- .../samplers/websocket/ServiceSocket.java | 71 +++++++++---------- .../samplers/websocket/WebSocketSampler.java | 2 +- 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/main/java/JMeter/plugins/functional/samplers/websocket/ServiceSocket.java b/src/main/java/JMeter/plugins/functional/samplers/websocket/ServiceSocket.java index bd2e219..0f4491e 100644 --- a/src/main/java/JMeter/plugins/functional/samplers/websocket/ServiceSocket.java +++ b/src/main/java/JMeter/plugins/functional/samplers/websocket/ServiceSocket.java @@ -6,7 +6,6 @@ import java.io.IOException; import java.util.Deque; -import java.util.Iterator; import java.util.LinkedList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -29,29 +28,24 @@ @WebSocket(maxTextMessageSize = 256 * 1024 * 1024) public class ServiceSocket { - protected final WebSocketSampler parent; + protected WebSocketSampler sampler; protected WebSocketClient client; private static final Logger log = LoggingManager.getLoggerForClass(); - protected Deque<String> responeBacklog = new LinkedList<String>(); + protected Deque<String> responeBacklog = new LinkedList<>(); protected Integer error = 0; protected StringBuffer logMessage = new StringBuffer(); protected CountDownLatch openLatch = new CountDownLatch(1); protected CountDownLatch closeLatch = new CountDownLatch(1); protected Session session = null; - protected String responsePattern; - protected String disconnectPattern; protected int messageCounter = 1; protected Pattern responseExpression; protected Pattern disconnectExpression; protected boolean connected = false; - public ServiceSocket(WebSocketSampler parent, WebSocketClient client) { - this.parent = parent; + public ServiceSocket(WebSocketSampler sampler, WebSocketClient client) { + this.sampler = sampler; this.client = client; - //Evaluate response matching patterns in case thay contain JMeter variables (i.e. ${var}) - responsePattern = new CompoundVariable(parent.getResponsePattern()).execute(); - disconnectPattern = new CompoundVariable(parent.getCloseConncectionPattern()).execute(); logMessage.append("\n\n[Execution Flow]\n"); logMessage.append(" - Opening new connection\n"); initializePatterns(); @@ -59,22 +53,20 @@ public ServiceSocket(WebSocketSampler parent, WebSocketClient client) { @OnWebSocketMessage public void onMessage(String msg) { - synchronized (parent) { - log.debug("Received message: " + msg); - String length = " (" + msg.length() + " bytes)"; - logMessage.append(" - Received message #").append(messageCounter).append(length); - addResponseMessage("[Message " + (messageCounter++) + "]\n" + msg + "\n\n"); - - if (responseExpression == null || responseExpression.matcher(msg).find()) { - logMessage.append("; matched response pattern").append("\n"); - closeLatch.countDown(); - } else if (!disconnectPattern.isEmpty() && disconnectExpression.matcher(msg).find()) { - logMessage.append("; matched connection close pattern").append("\n"); - closeLatch.countDown(); - close(StatusCode.NORMAL, "JMeter closed session."); - } else { - logMessage.append("; didn't match any pattern").append("\n"); - } + log.debug("Received message: " + msg); + String length = " (" + msg.length() + " bytes)"; + logMessage.append(" - Received message #").append(messageCounter).append(length); + addResponseMessage("[Message " + (messageCounter++) + "]\n" + msg + "\n\n"); + + if (responseExpression == null || responseExpression.matcher(msg).find()) { + logMessage.append("; matched response pattern").append("\n"); + closeLatch.countDown(); + } else if (disconnectExpression != null && disconnectExpression.matcher(msg).find()) { + logMessage.append("; matched connection close pattern").append("\n"); + closeLatch.countDown(); + close(StatusCode.NORMAL, "JMeter closed session."); + } else { + logMessage.append("; didn't match any pattern").append("\n"); } } @@ -111,9 +103,8 @@ public String getResponseMessage() { String responseMessage = ""; //Iterate through response messages saved in the responeBacklog cache - Iterator<String> iterator = responeBacklog.iterator(); - while (iterator.hasNext()) { - responseMessage += iterator.next(); + for (String aResponseBacklog : responeBacklog) { + responseMessage += aResponseBacklog; } return responseMessage; @@ -127,7 +118,7 @@ public boolean awaitClose(int duration, TimeUnit unit) throws InterruptedExcepti logMessage.append(" - Waiting for messages for ").append(duration).append(" ").append(unit.toString()).append("\n"); boolean res = this.closeLatch.await(duration, unit); - if (!parent.isStreamingConnection()) { + if (!sampler.isStreamingConnection()) { close(StatusCode.NORMAL, "JMeter closed session."); } else { logMessage.append(" - Leaving streaming connection open").append("\n"); @@ -200,14 +191,14 @@ public String getLogMessage() { return logMessage.toString(); } - public void log(String message) { - logMessage.append(message); - } - protected void initializePatterns() { + //Evaluate response matching patterns in case thay contain JMeter variables (i.e. ${var}) + String responsePattern = new CompoundVariable(sampler.getResponsePattern()).execute(); + String disconnectPattern = new CompoundVariable(sampler.getCloseConncectionPattern()).execute(); + try { logMessage.append(" - Using response message pattern \"").append(responsePattern).append("\"\n"); - responseExpression = (responsePattern != null || !responsePattern.isEmpty()) ? Pattern.compile(responsePattern) : null; + responseExpression = (responsePattern != null && !responsePattern.isEmpty()) ? Pattern.compile(responsePattern) : null; } catch (Exception ex) { logMessage.append(" - Invalid response message regular expression pattern: ").append(ex.getLocalizedMessage()).append("\n"); log.error("Invalid response message regular expression pattern: " + ex.getLocalizedMessage()); @@ -216,7 +207,7 @@ protected void initializePatterns() { try { logMessage.append(" - Using disconnect pattern \"").append(disconnectPattern).append("\"\n"); - disconnectExpression = (disconnectPattern != null || !disconnectPattern.isEmpty()) ? Pattern.compile(disconnectPattern) : null; + disconnectExpression = (disconnectPattern != null && !disconnectPattern.isEmpty()) ? Pattern.compile(disconnectPattern) : null; } catch (Exception ex) { logMessage.append(" - Invalid disconnect regular expression pattern: ").append(ex.getLocalizedMessage()).append("\n"); log.error("Invalid disconnect regular regular expression pattern: " + ex.getLocalizedMessage()); @@ -232,19 +223,23 @@ public boolean isConnected() { return connected; } - public void initialize() { + public void initialize(WebSocketSampler sampler) { + this.sampler = sampler; + logMessage = new StringBuffer(); logMessage.append("\n\n[Execution Flow]\n"); logMessage.append(" - Reusing exising connection\n"); error = 0; + initializePatterns(); + this.closeLatch = new CountDownLatch(1); } private void addResponseMessage(String message) { int messageBacklog; try { - messageBacklog = Integer.parseInt(parent.getMessageBacklog()); + messageBacklog = Integer.parseInt(sampler.getMessageBacklog()); } catch (Exception ex) { logMessage.append(" - Message backlog value not set; using default ").append(WebSocketSampler.MESSAGE_BACKLOG_COUNT).append("\n"); messageBacklog = WebSocketSampler.MESSAGE_BACKLOG_COUNT; diff --git a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java index 0a616b3..99ac4e8 100644 --- a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java +++ b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java @@ -83,7 +83,7 @@ private ServiceSocket getConnectionSocket() throws Exception { if (isStreamingConnection()) { if (connectionList.containsKey(connectionId)) { socket = connectionList.get(connectionId); - socket.initialize(); + socket.initialize(this); return socket; } else { socket = new ServiceSocket(this, webSocketClient); From 7e9b9fb265581972bebdda5eb8cf8105b1c5a044 Mon Sep 17 00:00:00 2001 From: Vadim Elkin <Vadim.Elkin@tradingscreen.com> Date: Thu, 4 Sep 2014 15:17:54 -0400 Subject: [PATCH 7/8] Use CachedThreadPool --- .../functional/samplers/websocket/WebSocketSampler.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java index 99ac4e8..7e76adf 100644 --- a/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java +++ b/src/main/java/JMeter/plugins/functional/samplers/websocket/WebSocketSampler.java @@ -34,6 +34,8 @@ import java.net.URL; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.apache.jmeter.testelement.TestStateListener; import org.eclipse.jetty.util.HttpCookieStore; @@ -59,6 +61,7 @@ public class WebSocketSampler extends AbstractSampler implements TestStateListen private static final String DEFAULT_PROTOCOL = "ws"; private static Map<String, ServiceSocket> connectionList; + private static ExecutorService executor = Executors.newCachedThreadPool(); private HeaderManager headerManager; private CookieManager cookieManager; @@ -78,7 +81,7 @@ private ServiceSocket getConnectionSocket() throws Exception { //Create WebSocket client SslContextFactory sslContexFactory = new SslContextFactory(); sslContexFactory.setTrustAll(isIgnoreSslErrors()); - WebSocketClient webSocketClient = new WebSocketClient(sslContexFactory); + WebSocketClient webSocketClient = new WebSocketClient(sslContexFactory, executor); if (isStreamingConnection()) { if (connectionList.containsKey(connectionId)) { From a14a5cbc88e9244458343be7ad14159045027c17 Mon Sep 17 00:00:00 2001 From: Vadim Elkin <vadim.elkin@tradingscreen.com> Date: Fri, 13 Feb 2015 09:37:53 -0500 Subject: [PATCH 8/8] Added JAR --- JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar.zip | Bin 0 -> 21955 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar.zip diff --git a/JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar.zip b/JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar.zip new file mode 100644 index 0000000000000000000000000000000000000000..5ebf173b82885ac1003239c6429891e68bbf2d38 GIT binary patch literal 21955 zcmV(tK<vLzO9KQH000080MtV|Mx}9*HS1IW0GeC?04V?f07^||bY*f^WnxorV{2t} zQ(<jzY-MsSF)lDJGA&b1K~PgjPgE{yVRD>UV{k3(5suaH#<p$Sww)8+*iK`g*t$2i zZQFKka$?*0l6u-sr=7Mtvor6$`|R%Q?Ect!ROBI{5WxN<OX7S|VE-WSe^f<D4N*o} zB`M~=!Qj9a{|Fn#G3jymqZRT;#rQ{<qNtLrl%%=_lcLnU;?$&qJR{RQk~|~b%+ze7 z8p{&<?x73a^c3y9dqtBPjr{cZ%v4BZ(TPv7d5A{FIqpz4{+$aib}?02QAr>s9~K3b zRT13_Ra)^8EzUXaY33iDSd>=gX~kHi3MgZ;)ijJ+fwDI)w=Upde{bVT?4R3!{iDh$ zTDV!bF#mfH%HKgwcJ5X-4zB+JjQ6i#OLqr=n~kG`soj5wBma+auBP@*b`~!GsW9Vz zm%!7)%+(QKYvJ|}Q=8QflGNCe){;d90}G-60~7gQQ>k0Hc-R0e)c<TT0qjg&U8{BB z{V-O&zl1Ie2!Sy0Y42>ds3eSHF}#RU1Tds^H*y0qf#8!~P5enPTKwm^hNL<CJ;4Be z>Zr>i#jO&p&9$gY2?#TO>Fl<sTq<BPkKzV_BHpMHdgt^q1y%mn^U+#r(^%m9eyO+P zPS<np*R}7jR)PEDS--SMt@}=miG_R8w>UYA2S4a-g|CVQ&r@HsCr8pZ&s4FQyJztS z$W)EDe6QC;ua5|?4;_I3GNLb9B4NyUY>c-|p63EF=5nvEcAbw})ZfI4*B`pXdNKAV zLATLzUy5IabF~^9a=lpey{adz2)`*2d>MxY)XouOycLq%Rgk!76${V*(BvB}Vxc#H ziQ)-lCeZLo8aP}VCk?|4qsP#qZ%^V>IUGmOrZqrv5Rlv}M~J}8E4g`)%j;*S_r{vV zisvQGqt`m36)@g|rZc93((uloK<hC$l<d;k!wXBN>C)J<2==k3Ty@r%>T_=&c%-Y{ zg$V<Y8kOH*BGjsRHLDz@qSm6BuT;1N)?&oFgWS6Zv}wD*&s@pf_JIhFYURn?^j(sB zm6$sfH(X)aLpzsFh=2Skgka_m`?(q^9piPO_No^b(Z)GsuRyAQJzEsZu$cBzqeX6I z4#?E#SykAq&-3F;WUp?@i*C=pSYs{RZ22Y)G_dQP-zK#poN1LRxs#aSSl}(;bf(|L zXTQm+2d<%!r}G=REv##j%u)Pu7D{OF$+R3F^pR42z-6r(0%<wc78$2<Uc{zywVXy3 zx|}b)p!ti$AG%u7wQRTXI-00UMyzMAxV~2PH<@2N182nKl%GfVTy)vDH`{QnsBqV- zpwSiR-?oxwaFO*fyY!GYSA0cXo_G*8?*s*1jKfk{7n}vtPw=OCO^eZA?X*s|%nuja zFIQNtvVZ2v=(g+;A*}C0gs?9wT8jt*M)-272k3r_vrB4mqG)9aBUE3Px;LRZSIt$Y z(7>8N8u2*iB|y_Cp;p8XE&)o^yvT%gT2hEUlNfZ(D`dA%D?m2aqBEsKBzE{K^i$Ep z3u}x{H_fMAUvo9&`gkJH@3p1QslPu|(e7*yo7BuUWpWwi)DcQ~^eNyVJD#pLp#<VK z@3T@IAUte#i$yvUn>M8+UQPG+C-b`mI#lK*E|7-xQTy(4HvU?(+Mrr#DOuD~!cG!B zt29Q3_A&LX61>cw#MG*5S-2FTRQJDx7MHVj9k0qJ=n8ZnljDYWVxO+Er?qEah6(Gs z^lB2YJ!$FNI+8zPTnln-TOGS}zP*08_pvvm{iQJ9og1J<%WhlOO{1k3NFZnxg;P5d zSAq}npkhp9d#L)okP5x~V*IJ)Omm;vECc{ujM|_V8*N!9VplEcwQ32WZ5ohhvuB$F z!43yyIUNE|PLA{qv<+5ee&uBp#>v;^Wn|>bT3)=swIKT|I6px7_&k9PJ<gIrtYECJ zhXmN;%Ma`)xZ*j1mCedk;0L5|BeZ+4wG729*y|MGt1D-=;yBa<w^)prBvNm=Z^49N z9Mz1=JD@zUT$YFth5X*cu3040X7ha7a$w(7Fp~h5pPB#tM1^bMK?zxtzsirx^n%6W z4KLLVFVs0>#ZZIhMJ)>FWED1S&rp=_r=<zP1P|~kUmENhq9#Em9&fzO=9q&|sWr4s zd|zp&az6WHI&ynqHCM_pzZGH?+i5b0{Ce@k{=oz2fEmAe;sLz+$<OISy<MHCXp&P3 zZqQrdQ|3J<a}dUtNJx9GlU{Kf(35B5U@j@qhYKOGFj60RZgru~`9>yKFwY7>V+l-O zQJ@?y#@PW-AiDO+NEt-fMZzt>atO(wguNt;aL>t#(5qF>`)^V9Y{QL7cf=nfb|MFc zfdOPCuwv{Z&>SKR*ri4C<%h+?bc_p=@w!8lz=H994f#ZNaw^R=&Xuq(Fe^Z+5k-^Z zqKqKsCW{qzo<J=Y46FptpyB$3k+T!t@J)_K>PvB0KTrtLv{O!-`{>T(W6Up({!Thw zjG34_IBYUsxs`l7JTWe^KuQ7#l2V}<3Lg=CsG1}6s@b}d&YdH&gmy9+AGt^Mu$U?Z z_QxWQEji=xCY`gBczX1WIYbhC(}Jq6uBFV*Ri^l9t1JXf#<Zu}ltDA(kC*KSm8rL1 zD0YGIOnx0N89icyhI0?Ce4qs0L_~kyzLCc4guK+sF>^CbI`iF*olW0pAAD~aj{u1O z7RdAc*eUxlMmKSlAv6Ab#EC{mziZW$8`d`)AqM8#ch8BY_fYZB<1F(R-(xafd9_Kr z-?V1PD{fhd5O1A<j%W_$_!jEev;e!~)Z0q=E5VXY2zgY>-(5?7$H&8S@%M4aB&<&w z??CMp-RDM-Ux|ClEAl3iT9n%&R;ZLi%gErrV|0nshTI^-82ky6v=XBzL8`MASB-Hl zGNuYhu`Z*@HCQo!w5sDgMO%1Ld`K9}q2>%=xBS5Jfg49jdEOWR2B7*z^&{1ek&$?# zfnKX2JRSF2*{etM(;mRCat~erG!yr<g7~Z-2wQ~|4a?QRryKHoQ%!x?El%=SG3^yH zH3fv|=!V?=QBlf9REsu72<C`cPbV@#!w%?{J-OE=db$UF4#!x)K--;2xRcGcOETo# zqWQvObzYq_B?G1p<iufRr`{3ITYhoB){*C%ZUua%ZgiYf&W+A^5uIIIzg)OSsa39Z zJ0Zv>EYnTVE}LP!jTkMf+)`n2d-fWgfkTSwxgGM~T`U}Gpc1QOrkvvz<rQ5(j9`O~ zudTHWc0IgD&3cm>b11jcDYLznfU<@B*BIm0>c{a|ehl5-#loEnVL35q65804>r16p z{1S~nlyLHzB&qD(kvY@qJSwG`*8m8%niO4P;Wq2gTGK2oHvD1F9~&X)wAzA4t?(JM z58xb)Ej4bC-v$m>!#j}0N)A~%YMoWqY0h0AC?enC@!>9#bAwM*JPbu58cy9c$3?<y zJiWL9dq()1$aakkaLjy><@;Fk_U`<R{t&-8CD}a<g+)+!fNujETX}P*bV@#!%lAM^ zku5Ow2YY_Y!(XxBtLwb<>>bLF<bvj72sj&4m+ty{rsbi4iUF=ghpX9xI6zvTJ*9pm z{6O=8qtK#xV`_q+O8#{A#`#yEinSh_&kC1b=mq8PzeH$et?jQ));bzrZ(6DqS4TEI zi5$NF+FYS^OC{7|0Tipj`98=1tlJVWZz||}(yHxBl$B!+z{_~yp#YV6D;8v#XKv9M z*L4kwwA)eup3%pz7h;rCmyXPaliyRRtGE$lKuazLIoDVd9`JV%oB2Q<Sv*K}6@n+7 zTe}}bVoAldc97%Y@)o2gl7IK--8qc2c4Se4oc29268II?N(>MTWW^MeB=8TOK+Y-X zV}ULVTI8_Fn5f4XNMcjK%&343E-iD(XexL;pg~dB<ls?QR?W%zW+<efUidhO5f_j} zH?SyW{T9HRO=?BXanD*l-+8;Gu<TV6h#147uh3Wq(@41_B5wo9Sjea$ziGqUY*Gv~ zTN2e)!LBYa(o>YSLF$GrC6D`fF!CWz%z^i9$bpYZGyM$Ui$Z&I5l)@_jagW!G4JQP zioKH872LFbTrXOdu-NaqmM3$T!^kn<jj#OdQ+*hMi83_e=RiK?NuC8TodvKrhbA{A zrniFMj6g}q%<eQf1r|Jd?;H%F;KpZCG(N)9>7loLf(F+cws&yVI0aZ!czGquW;dS9 ziJbs|r*tWd5n?StK7F{sV(pzLTnuc{a4i%la%GXABYI_Eq_Yf-XA?@muB11xJL2TK zn~nad?uOK?D*A7MS*PhujbjVU?`Z*<LL$VW?yC#99Vm@#9mJKX7y|Oo;U_`s+FJ7w zbt-X;#3N%SH|cTsU~^!W68c3yEB!@dx*DW1t`Ms&@bc*iSK+K>ixm4=k?61!II!&^ zYoMb+ed_cq3sUE0gnE~04YO`*uMLig^8-DB#EB3ADMW70-+l%zJsk+>Jd$HDf3qWm z%BIfgBue%{;ntQ_<Pw4JVn*gRQ!~Dq6QIrtw+3#t)Tay-pE5aVKISlpRqf8ulzVxo zMLww!UWPP2iSI$WWgwFYZbf1^;hb%Sg3ZMkcr9=b%D&OR1Rq}1`eUc5uU9tt7CYv| z%kF<52_8@Z<4uiK`e?dnk=ui<tl8CVf5Y7v;OWIluFMot*55Q(mVl~q!iYx6ec!p0 z_J6fnpb+rA^?+(1l+-B&n{P_tL?A*dsw5r51hYFoaXh^)!e8yYg9YpEO-IF0(^g&o zVa*nZT@e3;78P=8>NAw;B`B3&d=}XWEC(ahT$oaW{x<4+pseOnIvH|`{veCptSm~F z?^)_*mVA7E8CRPv4SmqH$+}&SyI4-%<QiJz4fg767uxb7jU{lgITUmU#yBL2D(O@+ z$T=7KI}?;|y;j(JuCo!j4`t_rO4g4&=0MP|(u51h1twBDetAU$$scL0V2dnK8FbZ4 zHBl)G2y%+;KP<-}SKsgjib2QPXIeDw_@SMU-XBUd?hta@zkQW1(ehos@gKeUexs=H zS@LvmH}Eq~%%*;I5Zd2Hb3>8>hflPqm{Flezf;j)=Na=uT|eq6xL_Mj4?ysj8dyNT zg8vZIg&GO`ofHZRfcE!rCLd0+EJ9I;hbpgVWpLT<@U%ZlB5{sLA2uK<w(ERz05$Ya z7G9xGW6N;`{)-z23p)idklTngzj(G(a-4+_U<G7M&ExURLzW{4kRF^b-l05%Vjte& zw!s3u<Ltxo^9p7swiXZZ%O__A4Ig-gpEXqKO3vO;{d@3!^oV?^4CEgI2>A>a^1n`w zEAb6Nq>DY?KcdZheUo96A#U?5=%h~GAR_2!ACu?aXj7<u(1S4Cd7+0<dXT9D`rRk! zmFI#Wl`e<{BqO9w!o5t3Cv}}GqVW4QjXokM-w$b!ZhRIYi<pEJ-%z1d4VRHs3->b} z?8K-PQ#yo`l+qM294MSMh}gR}$4u2ws2-7%eSXM>%obTeP<0n)a0tKvmUl<Gky&_y zXb5lj8bV4yuaY8%@@uyi6pghezgFw+afdz|m!yp)rCzLZ-e6F_2xbCcOM9bKKC!fV z6`AMn%h-G9r+Z*#wjmLWlT`Q)XH6VdF-_lu1R2R|VVb_iVKw<_k5$f~#2zfXg#|=n zPk9q_5#%jg-cl`19CKN3tysKZ5J$vaCk6pOUk8)sKIq(Bk$*w9MMnNQNST&gemViQ zE6;Ql5J<W?LmSBu$H?^GQ=2@hQ{-bOc>Eqly-Vit!BtPT_a~6%2m#(UnK&kUtDs%s zgE@$PV|81<XIiw{J1fo(uK*fZDo!kKl=g5G=_os=v-yY3X9$}o2s(G~GvAdt3j08% zGS*xQP0}nCC9yctyTI7=(o^R*PM2Xvl6yzzkT0U=cVd;uo@hjum07A~8Y98c)>piy zcG}i&s}rk<+FfQGb1)IP#k>NrC9l}Ru*@lDyF|Q-nacB3qec1%4xI$Yy`<G|IaR@Q z^>2zF{*_@pzy1E7X^Ppw&{qryFtAFfKT;I`D@~zoVW$4)m+YTh_7)Cqrhfwem9S9P zS4J1b_$)D8^XSAViiCI!FSA$WmZ(IrhbvK2SEsDkb5ve*FN@jKZNUD}hls)fhFkqU z<#wup)n4KUUv^G=&b|M!pOsa>=i3`(AK})7*dQk4WLpJ!Enqk>$acbDmc%OIK0KP{ zl!pCeHVf$MS*aOr`F@LzhVW~{y|9NI(w0BT<HReeQ>zcQv*rf!yzm4%?>EuV75Vw| zp~^HDq)^0mgc`I%xo6S$VatfU`AuhMr7LIdZ{XsU8btWzD>pmv;ioO+!;98)=%21T zuBQ_5jrR8JU9`=fFGQ^dOz&FM4}|NrsiUdCZ@FCGx^(%aYLmQ`bpV;~_xr<QrX|AD z&~wE5(v)R7Pk6!}&ocS-xW#mVSU)ql^b~US)@`Vd?{J;8g`)lfJ}c!Sh5M2{j9GDN zY9G=E_NhBVDIM9~=$KV(0tC|VR0wT0AOWmz$sywj#F~>Vrk#03Z%1;6`AT+=9-)Lu z;b%^c_)I9l8#bOMDa|eQQpyuQpVK#VRJ?;SB`Fh?ILujrxGXvO+icU{abQh;B=SkU zp<kXvB<IHZ^F}k9Fh$jpxx45EYP|+W0jv=c@W68@ZK=+^b7Fp50&j>mL$Y}T>u%5! z7&!R+{VpGt=A}+FAbM;UVm(>zD)}2{T92r&U}b510<VPDyHe)^xM90^-EYEbh{5y= zv<1qPZrIMWdCXrh|GazMU+kXU#9&}fieO;k|M%{x|Hb#0r7JdoH%S?O{Jmq3Vh?jR z^Qu^&Q+r@&LI_FvHxYQ!pcI1yD5&N(JFe{1X@|9K)EhcYf#~WDAIzp<HCw&&pr5~s zY{k@{UHSf-c6GDfx&KmU^wHOj-!BKQ$yU_5tk)y2`y+1l>uzsH%gg;=JFdcD3fh)y zd*pr^gODCCsKomR@pPZ#$TlxD*hI%$=sCVguFB;vO@wT~7ORUFtB>Dd|Ioax#nrga zA#}O*c6i6fHXa-L8tiqwD~M)ZH|6P>8W(Om!lZgBjjr7=<!JOJ{3-_7e)w<4eT{JQ zyv7s84RZ57V;%2k-4Zf&O^*9|&<s7d-@^)=MCAAtfqs9f5+2WX9e;U)7cekh>hTea z8!&=6dE-j;Td-(=&FI&jHeJB<11#r9c<-+}fp-pYk03E~ILS4*CYeI6#2H>rb!#$l zbdSz4j1Ia6xTvuei8#Z9XaPkY4%X1haF?Xnah8#{JgV@`e5u&6P;SW}I;oBPb)8Xe z8fqz3rP!k_9L3nf0cQgz7q+;VeNNV(-;KJmB_@k0QP~v8peK7@m`Q05G!<vj0J_xM zN^+9Rvv`7f7p*7E_-5Z}uLMJqGq)_TTJy@HlQ~#7k<nE9#|b(!=#R=l=88FH5kP}> z)v5U*KmMGdu;d{EO^xqnL4;h+-stI-9QAX^+3j7KJgA%B6_@5Jq9wC*rU1(>cY>M> z^Afp)Or?w^E`roZnFXpG&JN{NX}3jLobv;=YZIxHyt?^O>aU$i$(mapc*jbsL%3Nl zJycq*rwVzcF}PLpPAybhcuFf0+2N(OYvrct;igEdwgZKGQb@D=OqV%cvL%uc;n>zZ zMuYMkTLpW{99?RIl^k7KgVk9#HeQg)c^25VVLx1RJ-kGr*d$floEze((bOb$Fwr#K zHuqTT^OA|e8%5Fa+y7W-X79Saf=3zs*cJp^u~xLl#4kV{P!|0=4rkKFovP@Vi<<%r z3};r_xHbxP1G<0|+Ljv={UM94K4Gn4WesOuoA|ciWco``Dafj#O%7Ar7KE2}U@JR2 z?9PB8+!|ADmThRj?4UBttZ^%^X(x@-Ue{65&|G8Tt_ctqch{7+2MnI2ZM>b0tYAS^ zN#dZ9>u7CnEv?NNZ2!tJHs0PcXfN}544$Z<bO**nO4~v%(|`WNHuW-OIbi(b*|bHN z=Tbpi`#YcRyg7o<sR@f1E#}%P{cVHo(A_fr$>tr+D^KXI!|B8X=3UC9stOYl0%vHl zNyASEl;94xb-54$faLvIiN!K!b1B)HHperz3qT}0jkASAi*tq4yfY*yaFp;C8q&ST z35s+Sr;;CZpT64JVf{1K@(1^Bv|EIA!ZM`(F%d%5mG5I-B(=uQ;q}uS#NOT0Rp7zZ zU3!FJu3>;Ojls^oE;@3@st?)Wbl#lLkIh8}c~_;9d5&3__)h+Bh@==)h*B)u+xZF9 zsI;|Q@KZfq7=%RH+0+`>2yND{s7eY3tBrg}0{JEsC&+J;{A7ttme}yBrp{*4M+e9- zt8W6MedToZ0O8W%8j<WT9iB|WDD^i3<34QO%+M0+I~OQ@&AREq_k-Vg;dSt@dWkXC za0Z~r%g$ZiF?)vj8F10tCn6i;?4=ZLreWrBj-+wm+lQJ(uA-MmPe#v2JGsmsTsQ1- zwAYQ>TzMV<7`Sb6NIAd@bQLPUGf<)ZjBlDC`A)S*IziS>PSpBq6|;o#R)P#4N%#Dk znl`hO)C5jFUag_5_Qp;GC;cbQNXaskcy5i%BTQ>)jFoICuc?t~`}2{toM)tp)$?qb zyDlTz*>8OMn^Jm&$nQ2*WO+!OOx)l*kt~$UOOZ`oyi!E0r`{KNYjN7I{zc|+><l^& z%)R<*kCRdJF*xO<vmFj7_(|&_rX~-zmv`aTBa^W;LzK0@4`=LAQm)H>vEY<8xN0_c zD>85NAMw<1CT}-9FiS+2L`LW3J!p{G58%!0c>#s%&J-b%E@A81nHuy}*xYl?Wcu-Z z6Q@k`9@q{D&qBWo?X-qdCZJiM0l-}7-j9e3HIq8mD$+hePuk+6pXb86sLA_cAh>%< z3fN;AQp%e7XGPSL#|qzl$b=5SH;V9N!CRr0nT+u;ARyO&{jS45K>W(S$7%nY9#E5_ z->?Sw`LnWm2OT-tyQn&UaE74_q<wIk2v9`EYF9ttNc<t;A~7+yduATS#P^Vp=)ppg zt?3x+M6*s7<GR4KT+yg5*L)Utc(D_D=0?}lP;)rq^<bM_J&AcrlGI{SI*I)glCI?1 zTv^6Q93PknSH`?$&c*o9)M?$E6`UW*v00e`WH6tXvFj8dEo9BD)J_gWmfi3clGLaV z@d<@}azc%;7-u_%)7L;IG--IR986oz)Yx7U=5#cp<&Mj5s0Km_F_<FJ9Q&Y<ju#p= zGw^qfF%iW|^rvei9ygP)p*BQ)Pm1|*s>ER7o18_+`X*Auw~O2|emUk$y~@*tW$x{A zShQ!uR+It*N2z(>jY0_$we1GyBN_Xt)u=R=5<!V@9&9pq?F?Pibo7!W8=<4JAk%Y0 zs&Eer=OKK_vXd$^wtrTX`EX5BkF39(<fo^0jF<o`r0UW&&KY$lX{+=^nqcw<;*4s* zttA-$_^rP#Lbn4c?{;MGN`sNSJK{7A0Cye^bT(b=gu!s_8i#7HXHu+jYNN&}(6w+! zV)#>I^ZVUJcNT7s$L`mGB|KkR3y6bUxF7G6&Y!<&G6a-R8i<T$BmS;|KbcPFBPr^j zCXpl*#M$91qUrz PTOj>4*(n`qKopR0#Y)eO+fq0{yXyjH^zp4EfgyJF({?)E)X zE=|VzUQ!?zZZZBu8aGczUS8c|Y;)U&2RpN$(<+f916<imV~GYoV`wnMXCszeRCjUP zAr?29mjZG$HbKf4adU9r(_8GIm?JY&ufQoWWGKS6lNqBV;c>O1O?IRPqd!kN(b%gm znyX!mX*_+%J}LEwC{_9PF=M<UErX)?C!a0yC`vfE=}pOyijKK^o&L?(fjh}pv?p+- zl6)+}7e-qPcB4)1C9X7toRlc07DyK$o^<%#*4FepfOZ_bIm;hpMy)a_i37)hb9Uwg z9h(?iN1_@Y8WC5NREQI3=Fiu9oHT0#rS^1W;yHF%ep@e|@q^$(VNdrgBZ|+)sB7Nl zO`MNwPmNG{IMuvM%}cnW4Oic7o<5**Uoz*NP;JWCheN16PPk98qD>OJcXYX<O>--p z<?=+(g%Go8-eBmG&nPn6?S!0IW-C7?7o=o(@vRe$E>7@jVb~Dla745`OjNHejmeqR z(I2MSu||EB-#9^L05E^obgqq??(%t76${y_je#8!?C??%kQiZ_mtPznRCtaQeTFp@ zphG?ZvEE7>enffR4gq2%+!O}g3<YKiuf8dlfn*H@hI#U^W>40F7!Q7)f@VR?aHE8z zJ&Sv;FA(`PUpnqmh_jQYzvGAOk6b)N9E)?!**5(~X;n11Z^!;2Q~Ew<)bCM>Ogu=< zU^$zl<d!7)R>_n%SX|*{g#CMT<`dA@&@cBXkxnKf4CZo>h2e*Imzmd)g%nLy^zY9= znp;9nqUUb6%xOCF;tGyS!?qyz1_Zm<@o#sfy4YVwn7<FvJ`z@lF1=akEstp(+BE-w z!Bsi|5o(nX9X&EJ6{9aY2m_~>p}lhV*f03<rWvo%fL_GzgoHeyv2Ro5>h8DT+5t2U zi^I}OWS^7Wxif550}!1d+n+6cMUk$+QCTd(zVKM=eZWeYve&LhxDnv$Y2HqTraWc~ zsO-%xRLqI}gVoq#V+pt8#lSB=hS@v!bCjo-?6%)HfeM7gkXeX~PL<@J|GEUT()rQD zMcvFlnDld?Jf_y$5INdW<F=aV4I}b&zArH80^8NvZN!!?$Iax1t{p;Pm`R)Fg0*y9 z5r9JMpQJA34}9k~GBFlLdL}YM%SiGsW~v6C4QJZGRL)kHisyia_67zHX`>zBQf8df zUf`Zai_sUa>2O#f-)(WBh&0M1Ta_q=T1DeNhDB8-mC&C?SI}kEnAi13vcxszIZ1lA z*R1I-Ecy;KNJxW?%LGQP$l;b&7=t_rdzB$VGv!L+nA+zBFN`+^;YIP3C@-RG=ym0| zsChYtn#v!97YZ})l2<m=)IGjIPAsPi-14dOmhHRI(TZzWl+_%lGwy_Wo=>n?@VpXr zum!_tA*3XBu*u;9od#6-RpAOzj>k!3`3rjc*oh120XDiR`)k2~{2HFax2eTc=PuJx zlo4DC`gy$FN&+j26OJyfH0eQa(s{Nso!hZo8bxcp*{dH*D#m@6*HmAj<;CcSh}n7e z!z7Yaq8DZ^gZKFHET3a>=!C`FLCrxX$|9pQn?J-R-_I(%JnHGURIkq#oSEU%*hG1a zG^y^6u#(V+-}&^ksp>WBP+vq1jEN<C!PA%dYWBMs3icH;tLTU2##LRTf4L~*6=6rP z<c~;RY2!QgWD~QAZ951ZXJj`Hnn+6(XwWX+8g(g0%<iIVW){#NPH1TIifWh8E}|Xz zm+ISxf(CQcQ*Gfecmd9!J97S<12Jg<KTfF#q{lJECzR7jzJ)`A%xZC_U<H&T9I<q8 zoLG`5h*I%wuYI$MVsZ%xi%_N08YVur(;)_YjfAz|UzbV-*N-0&y4Z>ajNp-5!8rS! zFMT^hmZtmdU}-a2%b8^^<?j2=+vnTOwFFzw7~YM8#STrojAfb^7u7avRy~FB2CY#* z7EROlW(1*20^^sHHlb|GmY*m5J?$(PkH1pK>$gDneR9~p;PcE`??r3EoMlJP3@|T{ zaaMmeW4vH5>kSu0urm$WP0T-%kQU7=!e^V4_O5VG_)&J{tf+5LdnD~c<L6TaBa-P@ z8$sT8H#)z!nX5n|Vugz3yY-F@*W@!2H)ja&e_EUOe8;4CQ1BZv12wTkyl~{!rOXv> z#Ju>f{Cp;RicS?p1$ZyVnxk?RVN}25#6SLK-Owypc6!8Z*P^m;S#6Qu<Yz#_N;oZ_ zyfJd9-?O<m@YMF=;SziJ;<vaX2NP^(;%{$gXz%*RBYtqeGMcdZcI4!BdU$#NP7-gN zWU*gY!xze@#lXXxkeF+zb*Kwgt~sNI$+%rsU{qibR`k2U^T_H>+oMG}-<^qU?omd> zxvCp$3M-SDfc^%e_qd$e?p=24$-#DskC>jt$&H!!DrK{-&z0T<A24T3l-8rVnFxhc zkn5qA3gaRcTyXl#$c{yrMkf^^8n=EF7-af#ZeaV86#GZMtAniO^EfUb36=W>oI!p% z++s|&?U*~jisZ+Sj%|mH`zHrs+s2|=WQuNtp<hoL#%&#qG5gGXn~?C10czogz|X#j zU><1ZZohk(fV;@<2(&2XPv7(|in5Qj47gtzdEH-UTYi4~+6P!J7iAX=S$-RV?m*6A zCS=+a*)^s(vZzLiJclbWdRkIwh?d4+Kbk2fzRNn;qrIy&Tm!=oU5@eV1|FMa`=r+Z ztC1e@uHT9$oTf-Cc@~=Owh}qI;&5PT4KsI!z^jx5D;LdKwqS`tC>PdVxFfqI8f%AW z*hYK%$?fMj%9g)NCAzrvU)b$Jq6b&8Fxgz2sf}!20sU}vXPB1t@!+s6rWSMy#2L!H zF+H%-7pB!?)8kY@fr0S=Hkh1&(|$pmb*6E066sCV`-S6NEXHi?A#f)&&N6@AvHRX! zASbe?rH>3r7X=C9Mf%o;g?M$dDllzU4N;f6^-}MqI<73-Nf?9^PMnsqOXoRK(n>#D zCoxfmr};~$7R;(+KD-0zRkFraDt&fNhKQn=4IKu>tj5siuU(VV6r0vQ5=wJ3anofO zDMX;i$%)2^W5|ZEg{J`o5W^8xqVwPDBA63mVJUtWdyu6%W!`4>0Q{AFfLpRc?|6C$ zwdP1fq6rxQ<bA5UrR+U~6%f?is-1?*&kp{mj4CL=$g{p<#xW)EgChnX_&q5;+lv-) zV9$@NU$Y0E6ul&4*XcLH1;0h#LFDD%t->Fcmie*d`yr+F%F-B1A3CB>#PrWNiUmd* zNP&9<uqC~6D5M)>a=uQB@cYw8a-qA+HI{M2dpXTcfdm7Gk<p+Jm1J`iZMbMsm>{wV zO0ZnZitrCIV!V@Pg2ZVkwOVFLlc|1Z=HiTD=l)J=e@G-#+Jy%V6vBOo3hoXNHdhNV zGNrFmwb#OEC`@Q1cG1RK^AO!3a?&VL{SCF^7lNy2|J;Iq0<#G{BKO@OlmOfy{zRmu z#QMx{EPfWwq8mgs*1Jay{w!)inB57vb1Ht=v3y|I7ZLLuR~gZ67HL_vE*2OgS76Tp zJPwrUckrd`2>aje_MiJg5voPx%lL#4(0{k^EWRhFP?npLz&s$x(jHi%*QGnW({qln zfUr=gqLzRaw(y&Z6i$go5xV~?cm`I88c|p|zX`-~#w0w4HD6=K$oK=zR6>;zjSM}# zsU^Gi+=bO;7`jz?w~9gjW$^lu3qPH8s%L)=&6N8TJC*<fwfZnaGlTIqbg6{tCjvl} zsYv+{oTrrm;df7>n6GZXD^!_Y6a+JJ0I=x?wGe;TN|P|12Oryu2RLJVZw)?rF=8&_ zO;gb%{B3#Bco00pWZ<V7Iq=H5AXFcbqWh=IAdyZ7N?Nh#x>AxT_Zur5br2b}11yHB z9<0qA7{C-)A=oklnNbCP(iFbx=kJxmxOCu!bf9hb+;mW^`Yd_SYkqFn_Cs#w6FR^$ z+i1deAqXYCdw@ET?@43HNrTaU;>VZ@&V&;gz~R?r-qG(7xD8T03|flai5tLT?<((! zbzw1$;P0t*5e9@l4`TU2F`*~#elLe=6(a(cfmA?MsL^)p&xlharaS~3Sy9B&2|Jac zHiB4lC#M`{$Z-SnKTUB{@TxgBBnUzP<yQd%z63TcBXs5!+F3kAxjb<i4pn1Aw@Y-p z2wRqMT(WREfuqSjS|EKMwBL~eCr)|bW2`xZw<3}cafZ!_w8R{U8Ff3NDe2NGLPdsY z>Czx$Psq2gYPFreR~_Ozm3ct~K-=~PKRBASMK6}AEL4CVLR2FCn`Ch#o&a=5$_!Rz zJjwTXLW*BcXmf>yql5F6;}0pPA+!<aNv88*pT(Ip5$Bf5^T5xZ0*f3;d<*ibY}p*; zp=89t@A?x0HuTb@x?PrP(O5Q(dWCg4z4Qf673B<e@PzcTl3Fy4YY){GGRy!*VIar7 z8{4GSQo0b#utnUpw5faMw=nkd9ZfBh<c{v}w+`Lqjf_8z^y*|C2DdoJhT6eMo_(Hl zI+S@`;l;ANxFnOuR?-Gzg(#5W6Lq#aLG|bc9g5CVinI<h{M!~=Ax6=gQ5||6Q?_dR zO2$6lTWArjb~)SD@0hjALff)O7)Zohg~D@wCm7e#T}LXEZnQ>gGs~4dD_bPUo$1k7 zBsgm)B%JsJJKj_(w?UjWjZLv&l%b$cXT!{v&8$?^ZBA0XmFm}UXO%_-#y|a}#+4vk zp)xroc`StIxQPWg9{aQyXm>(0kbAl|KcSfX76f*7H+jfgr<(RUX~8`2yl%T-44rMB z*=rCGD3LJv!Fh3ND*^B3fv_ee7a+*93v)-@G6>a%CO0Of81$<Tu`Sat_!nA)em;Uj z;r=IbSwyb6|20Kr=kK%z9c~5<Q3JcpPoL00@9_77p>N=8Vpg||H>i&<<jn%$@q@`X zR&U3WFTeYM%nS3}<GqW`qmDnhK4|WeczUt86WA%h?Gbyr{87Z<IDcU@?0v&*SJ;JZ zBu?BFr>*u$_rh%i>A2gS@_Vq)5S0Gx7p$(3>;BFc)-GmLAynv_{H9Ui2!a7KJvA{; zcwMg+KW`RzdTXdusogDuiC1$6hQpe~cJCBlnIk1C+i3*bHKUo_;CtEnFq#Cc^sm8o zfvO?sq7C#L`6{v)hY;EqAuRw>t}gqHqJab#Uv3?6XgDRg1^YWmZG4(?DprYBR{C{$ zo5Tjzn4VeIVxkTCVsCITG~G(IW_{jg$)YjjZ=6_2)#iE!KbSHD@UyY|uXNzy_3QW9 z_;h|h6_=f~+vYEKB1De+E><(o5+cOKKfwqPRwL5@W2fDWWu$sXS7=qCTv2@)pJ|iN zV5;m@a)Q=OCO5Ms*e26MB4RA{5;o{raF!e=YGXqXzI<l5+*0Un9Cy5gO-F}K51A}Z zj%g!{vq_7RW%e*Y3;S^yQi+-rm^itKq7V<spBg88S_ook7`M^z6k0E?JeMO_mDt;` zZ;FgNr)k7=^SFS!nDtb9U-6M^;Y{JFNtYM|wA}j)mYWvpYTISB|Dlw#0BWOMqcHAL zAh>IBcPYg!P~1y#m*5mA6bWvH;#MHIL$Cq`f>Yexr4%o&z5ku-(yN=vOum^t=Semz z@9g{SA!nUWeeBgGfng2RXnzFE58yuRsMP~2mj<8p+i#HzfE!U0xF_y#pNFc!B=Owy zNGQ3p#Si2{eON>Q#fh!sLG(L^)+BrpEoe1(dV>uaXl!Tv`*Z*q%p5fla1R7)>{FJi z^Ep}#<+eo|@E!#tR_2gK_?9_3+YHaJ@?^{2y_bvLgk5n8c;o(7>N{n$N+D(%4{MX1 z7?$g@EudauXXA-ns^KzNwZ-!jb7E5dhU@@LS_HAUYbGm5zFs0}nvgbnceEKSn~B`$ zV#@EJ6vvw@*F{KxY^mRdrV>Tj;dU4St3HUSq>J&}DDoAJVs*sWLo+lbkMUmCXX05z z-!!=yQR_D^$ojC<BbSen$fv9yE+w_>qed@+z#fF9+3uKy(G3y>tfO;d6i>VuVMyY^ zEZU6hw0ZL96&4T{`XX6itI(eyweiw1Qe+HE|GmSu8g@v!50glCuzZ%y;m0gj^!Yoq z_o`$VSL2F%N{{!7%_E|OOOP3o6jip3$b%*SDKc9q6^}|niS2o$o>g$ZovYlG?LM}g zLp<A}M<Xg$^So<)L8`8h!B-+CTLXFHuWh;@=f>drwDswt_k2sCQ)b9}O>t`mouy5o zTlK-`Mr^_==%aN25K|^-v~JTYny^WCvr!zmX-d`EVJpeuIav{z+Va5oY^?~_hhyE( z7H6Z00V*4&26SRYiH%~4W9Mfvp;BR)Ateb8Sadrqh&@tQ8(#-NnpsvnA!|k>opK=+ zN<1NI?kMo(1)JC5RD=u=T?M&ujNwXM)6skr2d($}yj>Ob2=3*`Y3~`+5(v|lDmp_; z^n{VqYS5X?k#_|#xeqwHJdA=`RxpMarVp|Jrn8x*z7^1KUj39rh8|xEiJWSJ>!&bA zk&*Ub0FYn?XtdEVGn>f4y>@3YD`YQYr5wne-Ww;TvQ0QyWhrjd8JEhqJ{Yq#*mHjB zAGwFxJZLH0-6Qj5I$LADo%mQe%;PNrgCE5tZY9l1Hp1js$(9Za&1+NX&*K=AE3*kz z4WZBl`>*-BMvbwvS9bs-!PVuu=!!;m`&z3G=x-k@I}d9S>O*`VMUm4~fZVBuK?@e} zyVfe)l6466a~Q)M(+AfqosK+R#@5Kz)yQc}99<9d7{f2vxLZr+jsd0t=D{t?zl|}u zHB`9u^n+UZF@`0k9Re}9^)gHY?2&h=FuAXdf^X9a(;jtAsftYEA#m===)3l8-1i)v z6g5chv4m-Um7U^h?Kz6@yM_eAp1P*T4RGgB#<bkuw&NJaaQ*Z_^>1H6pv$pdl;YTZ z*~L}(VdMv>d3ESUA^~>OuE_Mg5YTsmGIjGv=lo!u5s{XM4@TvvSYsnP!5fe~71T#7 zc11*u*U~?IcCY2#L&Ydu<0p&}&p&UyFm%;L{j3p&GbA2WgNs9>4Izd|qQ&b#E@256 zo|58?iC+U35##kBXA(~Ygsg9N#apl^{qCuTnw&x^H2bysz#5-<zv{A9`|5J<PsO_~ z@yQ$MmR4*c?AT^MIZnSK0SR4KkiHRpBI`&$I1-CB2i&U}Ht(y$pRdP*1RTRDPl>0* zu+)3tZ$zE$$f3h7iQzXyF+ELYSYNt-qDlZ%0^kU5-b4w$2-P~JFX@kGk$*r^>wje? z5P;)!gN$?<ScB6MhVAoAa6_mD`F`ErEaXTUOi73BjK6<cGrq3zfmZKJw%`>YDuy*7 z|3x!;pXRY1U___0uo*E>Rb$+v8Nmg%HXhLM>^k#SI`o?U%UOJ8KosJYITt5nAvQGo z#^{0aXqluL+og+)&&>&b<%y%UPGz3+y32LfNjcp>hM*(aqHyVs=6R`7?@|jMjx?2y zbu=F7CF|-LBSpX3nOfV_=FnzKa@?NERp%N`d)+gG1dci_V}nE3ie}UatW~wBUX^i- z#Y>#4nq9G(DwH^p!C;$F(M`=bvEWSMbNXZB=Fj}oYfE4^?dzBtDDgyddkODW%<$tW zozj9ztC=lt=7cG+g(mYiswvAu)u8<yOY1GPDIXP}-&PuDF%eF}^ONAb`*rFH|7x1) z)Z>uAI{6<CYvs0WS8^L~+TXcczX1)}Dgt1_Jm^eObj<ikJEpzbl5v)OJ~V?&l=BMD ziN>tm`~{O@7Zh8Dw$WHJ)u7eP$MR2wpCgZyzK^B?Vi|F}9E@mNo42KWj+~iKz*;4{ zmzCVv4kjJs@`U8CB7X|La5)736i0Je#ZGQdc=O8e$S0HkI@^SInnB|v5sLR^ftz?$ zxeXp4a2U<9{%l8`rf9OFsLPRuU^i-?`_=G!vZ1*sf;_3=xV7A2dNJdm>#r>WeS5PJ zxa%Qj-^O-NOK%dK=`(+V{I|+>0^ni>9YDunBD|M{Ct=rDu=`fCE0Y^jq3soxCRU>% z=?rn2$wBHFyE*p_*|N-6mGJ`{Kf8Y-{$+N+s8Nud4}_PI1sx8K0RRUl|NqVoQ1G<- z;{<_Jbbsw$%Kktu)K&v3baaO0XC>eSIJQqENYC(tkqEGmG{nbKSIp{9ui8&njijdy z*(8qaDjP1KO@z2~+)@c&5ed(}Tb*>TdY3me6gE8lJW&<Q98s3^zj?X)Zcmc$XG_3& z?gD`eg)o-s7eN68VsE+ib*-#Jtc@u=zy@E|E&KD_t?lzHf7+PV+xuR8<u8D~)b1N) zv^UsW4tO6o4i3NNJo|#z#k@=|h0&UJZ1FjFAHE1R-HY#%SE2_RZpStCf@yHNADX*w zR)h#dO{X#w?eR$4N1M_pvH-^OO7vX_PZ0q7({n6+qxS8J2!LbU*_OU3`yxeq=_aPW zANDhWYf<Y<&EfS=qVK|;uHC$dr``dt`6N0oXr`QtOp3zOuDFk^7W)~}@6vF%DJ>Vr zF1V-Yf#GR5e3WLQLmn~v8b$qSR5rfB`@&O6z*jsHBObx~q(w=<F<y!O3-KvTAlDD* z7jl?N)-Bb^>b1-bJn>rZ;3!%^1ofHjPvOwq&{Hk!<dyt_l{hCnlhzO4dBIcG`mpJm zHY=U-(@=sV-l<5)j=WG|Wm+nfqdVral&X-j)9VhWizt7S?*f1fFX`?yq9rBSSWfy` zmVC>|#`(xlP>KJ1J|y`fMZGs8{XhU9u;`kXSHWl(IkT@F4w@yUWHMkiJWMmI63SxO zORgO_0DdMT8+9&8g(UGOOd^qrcdPUn#^9K|pAg_P5+q-WDY4U!v~AsEs6?6}SGs&4 za{xOOXOmzTFjyO9CPqSK#EY5y$}+W{n#DJKVE`7hw-cT{s_=8?G0(TF0(FtGiE~$` zZQGKKreOQ%VQbdHVUl!)Q1>4(d}#_E=}C(2*PH^lkxzNk*<C&SF`pV@oa_WXPwOW4 zQ<(Xfk8fK~VdO@Rsi)F^rVx`~)$|f?DYdC-YRXZk%ce-v?%>4~C({+S#t0#NX>Lwy zA8~3Ur<vwz2szD9E4?7KyY}{zOSIt=j1Swb(f4pvh>weRcSH5Hy?uvHx?%$D^4f&i z@%SD>`)2}*w)T7s`ngV3C_7-)o)0J;GwN-NUTtcW9o;9MK8jO#b`UenaO>>-21Czs zv!VC0nW|b0SV?m18IAq2#0Q~$pW|?p8kX#eN16q?%a5PUcq9Vx_M{%9`YY%2%+3r3 zf&J93(Q%Tst&)6?;QeY~poK4ZU#F;puf6XAw<wUeee{B>D3CAP{0?_2FnzW2rw4XM zkpnUi43yI@Bh)GtjA7{kShJc%abw#|rpt3D^Ct7eTC&=dnUeMLXGrMP?Xfz=RK?Ep zfuU!g1>wa!{GU-zav%N7C48M(qB`j+=HlDE5I&k9XfRh~J0sedXVg7e9}6Pe#mSZ_ zDh+%oYCOhc9<m6S;}>#IV09JwR_n%MIs>)jr<^y${<>~EDnQR-5se0^GE2nBTPkoC z0_WO>yXZa7djVQ{<Lx$LS5~*DdDX_bpDw+kuJZ_=p)hG{lp~dj(#pZV>59$gP^Y5x zy0KS-ferFzw$`90n8w(EkAJ#8JLFv}s1e=9K>QdjRT`$~9bqS1q)VRtdZ;zzd`EkA zIC@B$Cs@ni7^eZd*w-oUXn`lQNN9Ov^z5?79kA3c*nPkdl4()$t=jCZs&33?fgG_5 zIJ19X%Yf~h38>UA-j4jtRJ^4Tqa#O!ZEq4*9NO_n=uEZs?URejO+E#8>)VkXr6v)x zg*aR95vKmyThTHKk0rr*!CtHK7vG!}cgixvJs;lzKSTXsiWB0fqD3fe^tTv8DA;Z3 zOs{u$4eL^aQZjJj1bj$&`_2wWps%}d%!9&%q_6qGR$a3$Cxa1X!y^qbht*To&CWuU zF)w38m?X5m&gC5A3|addA8U48kPQ6bF*Of@YUX;Bk$)q)&IPe27-x3)`Um0YFB^Z= zFRN$zNnq)_dM`OfAKG6(TyRBcSN-!s;nke*3HXgS%8XKLy28pQy*~YGj$%IgwJDbY zNBttc`hx{Ey<)Soa^bF^YQ~$gG_qj{ACBspZ22iu#u#$(>k3qXqRFMzLh2yoi+B@U z*{xfYJQpM~Nj2v7AUC1BG&FtnCDhm_jBnL7S2R(AfUtXYcAknxT{;H5T^A)eS#uw! zBa?50^bx*~RL&3>6tsf;XvKkxVc98HQAgT(t}0CeKUzRJCPreY?d#eD4I>2%1Vh z3>R^w66$_D9&M)F%`CDJ;27qAr&qN9)^ewAK<cAY3CTkE4|)-*?{(s`yj0%?34F$J zG>+)*h^A*R^YV{L<d1p|JQaA#lJ`Va%%QS{FxE&OjDF=9EnyS$U|1x65<o2_Ex*Rl zybNZC@1o@s*Rw>ZmYSAVBX3?LZFngPz6flDiQsF1_mqcqgkPC|ft@pq>NUUIL;w>j z8$&>OvJ&rzDs$dZ6gnp9iyN6MRd@8Yxe+<hgE-MGIV+dNKU%zCnlv2yG?JxY)J#Hb z%E&1z#tD;Wm&LziXpn;zM!S-ytg9KvwAKPzYq0RKg~Q~tdfeJVnc89qFM!5MTrg{2 z_^L^M=$)9hN~^jWSD*Km1eCt|6V^%Zy{$Nu&weg#H6C~T%ZfZH{s~L0r_2~1W0=aj z5kxCg9(x(;N4K)dBz;4nPo<hy;Q|a(4J1+pdjaLaOl9%h(l^|(?<oTr3O*Dl)At6+ zyrD1lj~&LCbs-(mG%M(F1FPb*0Ziy>HO=aKSiz~vP-e$u{mN6`NI|dz!z`;~s($gQ zTjV81bwab|21;Z(z=Xp!7UsYx$l9j1=?e~%4Tq)48s{a<L%3-tN+BCxEs4+>-U2ci z8@GqHl^3J18IsCv@2i;7jb(USQY`B}^nfUxE-s<tC_AExOgxE7S(bFRm_i?b_zX#E ziAsr<b?KIMU`z8vpe6%BwB@8+2cU713o)GPVV^y{t<3UA23J!29WTr10EC2^oIQzd zXgLSn|B`k2qk1Qw$hXT~G)VYea}We%q5F+lV-@ozHQNoUj!d1MZykkXa}@Goooy5I zz#6Og7UyPyFW`9K#^4hQ07rLu^wO0r(oG>H9wc9pJ8+Y>nF^Qp_-!$yvOVA<c|@?z z$JPDT$L-9&EyluEvRNz%;NYkP;NTSh-(pPN%-PEEFHbdV&&){LFr^ETQZbOyB-F$* zr-8W>5^6#@LgBjJe+Z@dG&8u(g9WtS97c-pEUlc;bvn?ky#I1yiV_-ySvgzSXnzpa zpj+9vcvSz!shlHVug!a}U5L;7=F{5sSFXJrzvGs@rxTIAY(JMD4|(nP@SmuDuEPtZ z_^s1bsDrXlv-C}5v(JD`r}MJN&t3bA*LkQ;NxG8=#b*(_V@F+qMcnB_+dfRmz_K)L zzEU&ZSS606ec%Jonmc_E5~n1QWPl;)(`iHEq77<9jS~=c2V@-tmCD;tB{4Cb6B@4v zk;$|r4AL=0r}Og}z#!m3O{Pj<3Xj34C32D=6I*&#CnS52m8m>EYXH(6`}{2k+pEs# z^Kx^_%EVEhCq~X;kX3We4tW%aJ_oj<mG0jgQoOMbM39>gk=pf5pGsTW?t12I-Ol}L z3AR!Rq!VB4XBaBr5xQzU!xHLSNds9-#v(c|@Ae&0gitzDXrBUcFE;g7e2Dz2G9|nk z$;Vu`S}+1syUv$yJaHX+U1~B%y|;uGE|8tu#$(sqwwhLaK9F-+qotmHUvu5^Uifjn z>{Ck4wY5Fp`RL4)>JIlg-T1hR?Nr(1<Q`bHc|6nBiJNA;)#Y#|dbM<kvHE^Jrbimh zV$tF(L2{fL&3X2L;jF1&nwDcVl$$OA*w-zAs8mV+Y=#ca{jkjF4hkW<zV5de)aNET zb5Ucuf6NQ236#^*Q*amOA1{_mLVw4!@B^8?Hgpz0T0X>(n>0>NY@nGa-pfub@hi*_ zLTu)EpVHabi4$n<CrtLEnqR^8>KlzJ|8B$OVv&_xRZtuNk4B5TySuv-_u?+atvHLj zwz#`f+={z96kXg~V1XjVZI{Kb|INMJ!#!LwlT03xw@fDXb-X3BYI5Rq@9!^0IM52| zN|diftS1%JVLvG0NLtBVvtx{@5?-WG)SOVO6TJS`Tqvp49yf6|i}eb@#i>aP_D>2J zsUnqdhI<E5Yu5<FNzm;sVm^#OWCNJ{v*6sdn{e*jfI*_EscIJtsT&5K9+00Xp82Y? z-ChTfVVoVp40@yxoM`K~^4Ufs-P)Pv6gc%EUyIdKK@x6G`LZc^+gg2|`<)i;AXZta z?=|luoZ49*M#7U;$~Wy3=~I&XST4{T_UGsD3UVzB_jAq7XhU6Tpn`>W2#K(vQzNTf z?=H?M1AYP0y~P<6<DE6Ky`8~VvDM)RuLv7(;}rfSLO8*}a5j#o6C1Zj(zUI%)Mlmq zTXnt)ygz(3H>Ds6?jIZl%#WNrz631bt{fYxg`+P@C8*NW?=g5E{_qbAnZ8>;-o~RA z`aIHA!h5^`!VhksR<|>Wj3OEH#f@@tK0s(oRl}7tY$?K-?`j+t;OC$<;sO&5b}=|1 zFVY-^Lxt9$MZogX840-&MAo9n4;^!i^3+0`Y_ItB>}y+iiS=OaWC7bQ%{+T&lG0&X z&cZ5M%b|8>??5(A;mfZKDQ}z0mtZ;YhA+*G%59BrK+A94TmO3Z`8JZ`tVI`iQtrYl z2`nnmEu;zsm39|}ub;OmXaMbno|?kdqQoWhy!vOWUiQnWD^HG>txi9WA1APY4M~Q- zV4v>WZdm6o?G=ln3_^bvRy~@*Y0Ay~zt%+uyhP<!a%q^R4s_4pGP024DW9pkS7vcT z=Z5l=7mw9ZGg<Iyk(Wzcczl_6=79m$e{JnuH~rQlHzy==t^AorGr3}=t4o8b=Rr`! zPL!Fdr`9!N?Ar5zFiy;l6XRP(dwtDg>>qL7o1M;j61=6`jtf>`yw6N|H2zKr`9%=O zcG}YB=Z>YCgtd!9jDkqHnc7NnY&^67R_rTOi(iYRCp7Gpe5uOf;41I7bTH$fKyR90 zR6)M`W7^k)(+VwfXSe&aj0aqlOmTz&ef;K^b`#b@1n?A*Z>1G22N%0I=M}C!5UPOQ zXG;(G+t80sL~6*)SUXG`u(Xa<*@8bSQg+8Rt|H7mpUH18a#=~pXgJ=i)gJ8TW)CfL z?h`;Bq;B||<IZ6K`1yoQ-D-MuG`bTG*GLNo5fGfr(>cw6Z}Spd$ZsE3Ig5%A$(p#1 znw$%q_&9Sh#gROU3m>yn>?FVl_?{)V(!_tz;PNA5ow+8DM43sX?rlZy5dqy=RM`Si zC%=|-9?qNZ6v^AIaz1*tlNB*iO*BH!a)qG^=0GM#b++DfuI5_b$#DiHS*SA5DQ|Z| zh4l;q|B8PXIkQLCYMo)q8gKn*+IXku9%kL}0j?NWyndpay-*S8a4q57!(v?>6Mxb( z>}hz0KEd>;sLk(Jx9I{svwFiR-)K=$t-`pId&r2pE~nD_^-j`$NwVXy7XZsP_kpQI zzg5d%5aQ8Q4#_?905cA|?bYCVG#uq_%et&=1c;yMoS5CzATMwDGgTf$ky~1<<WvSB zT!lQ+RKjg5R0lo%TO1FJbF+Q2hrc^pQQ{20J3N*xS1-L11Rxg1zpnf>F*1q?VaC9{ z&!JESZ`54>DB>~0C>2Q=;1PAGy<W5dO$HC~qODy+=I11yZevgMa<GNzky}1`52J39 ze{A)r4ej;}1BO*6j?6@jHfzo6)%GJ$$6DmX)g_B!E;H&j99S(#6j}Q=&E%1obD0y? zz2hS8ejhXn`Nnc8uIj7V_*03P*ywe5-z{U^5J$1*O=U<Q;oH;P_Cc6;RWWB_u&Z}y zECakzrWxJ6?N!0#LM?~K#Z5eR*+r?N*`D2vPVGI7x%1|OUK3|S`}M`I!9Pm%ES}{$ zy7u2|o)njD`=OjIT~}ew-t32WJ++^X!>?6_zko@Q_VQMn7u3{OrU+Tj@KVbmEaH|H ze$hKo{(Nbhp!o^j;)g?(hI44H8ZP^UfiE5A<>x6W`8i9A4h?}tGFpBh25t;DZhYO6 zo#}^wQOEC1?s;njP6z6eSgT3CHso6^sEvfr0U1Oow^5p8710S75ZRwc%|0g#W>#9L zmBB0tjh%G$%P1`smY`&+mHlMT7&4-N^TB*?XXA`P#4foXgZS7S$^&`Z9A2y%6;+dB zQ+#}r^GOHh-^b&nDn<_`xz?eU-rZw_yETp0X^Dq!4+>xz_46#Qq?(T>Upo!xd8|*Q zJKqjKH@Pygy!k(qy~Jc$^Co!-Hd#OWXceOnh@!OEEc%qe`|Cn13?dA&OgY3Q^7_Tp zJ_5{4wPXWTx|z_>1LV2*o&FlinjdChvGu>GyVgBq6)`tlDa}c9rGM1Barg0Ai>Io{ zk@@B-!>QlYMoA~t1C^Com2#D*`YNLy`%Z?}cXHkA;!@$b_-iQ2pu0Up`BD%wL}k}o zHkDv0lgK`%`j_6R9vkIPGo~~<E=&SBzE4TP1GW=D&~MjU8drli^uUbW5{ued4^drI zsT*W~@NMJ266jJ-dg*OuVXoQz{i8XSK3{p2pVWa?;J=3t_e0W$pu&o~1++RsD#yF~ zhBi;195%_^3NE$hzqk6EwsT8+2lM12h=DZ}8H&LPBhZnlI;*@t`ae?O$&K*e6ivu( ziKjX#A%3nlDs~6P>Cv+)Pj=!zqK!8spXwb8`x5xE26kK+JW{|%B1z~f`z2=)Ejv!l zxP^6EaxchoDUirxJ})q>XX@`XxhKb+2mMrG=YMCgMf7I7J`OoZJrQMZqM!J-c*%tr z&JwGg^_3c08>flY13zNtkp@TdSdLhosPxX$Scas^9PXcGyBMnlMHKEfz!JpuwR|_M zFy>FYn`!f=ktm%7tbYwqG!xONTjF|}s!6D68w^AlPwXiz^c!|PLHi}SUkB7X!9Y&W zv@tQ6GA}Vd&vseOpLd!z3Lfqb=JKU-%tsSmdU~;k@(x9TaIUnkgVVTw=c^oN`+nbI ziV5^(JN>N$%7ubXU{vch2tr!ast6zTPva=h!?I~TsN-@L_*}gz)g?YqIG5=_kT$!e z<{*ot4PyK-zuC4BugZP#hrNz)#fASMPu-D;yVDOJu|^#!vu64*vVKXCxhxs$Qixe) z&tO8VqyjGTC+{^eldJvJRv8+=&D~Gkz$UHNF#VOhYU@Bb@3*R&&lp_oLa9Mf_o64- zZIC^rbcC&JyflRAEZTQqNK+Vj<Gx|br!Oddx_Kc}m&bTImc`i00Z}BQK0f#Pl(5OE zJoc0h!p9O*SjF10)9r9Hh31QLvJ$gEKj*6_tgW0YSliTp0gUG%7~TuCouUv5IN<`2 z`9A^?Q)c=tc43X;HjgfJzEDm_-$y3wO+%)IBhS!DScc))ccae!Y>5n}^8!~_8K*&i zRE2?Lq9=EgEhkqzDkh<bHhS#2cDV(`U6NG*ret7J_cV{>sTL03iTJ)bdBhetxQKKv zDcn`-b3Mk^4qI9PrivkHxiM9~G$>d?bdS)&i9N^E{oygQJz~8<KOM?rer)K8*Pw1` z+=;?~pp(n@7!?8L2R(82aUr2>%8btzJ);mTO=7}dvWA<kL2O;V@KVIr_g6yJO<S`k zZ+NpVbW}V!{yehdPz6Z{9r9ZGj4k=-UJ6z=%>&b7^-%nppF5;`kDE=!cnZ=`f{Bea z&RbI@lUWHw?zy5KoERKK4S186^RGe&C>~I^0NF~JGz<DjoK#<LICWzitBH8f?BcVo z!S;deefjPj(@bDT22H}ylw1#DqhzAubVG)Kp_IKVtLdghi_a;AC~UcEC9=a$r>kib zGb}nvT-JKoOlq#@Qi4g<rb2$C*tsMz`km5;nho;9T@jf<C2Y6&pcXMPxgOFd=?zbU zC4m?CXaqx0VeTvucg7o`Ka{Td>0EI?d5pfmxL|(uk7skXNi>aPYE8Hy3OJf(V@>W( z)TVh>u|&~l@w<U?wr`bi$h_Mq5?38+QXm2X(q^x5v-ch*8q|t$iA(^hi9jZ2%UaY$ zrb^a7!FAapR_B2kX8L!zOvm{}?8nk?rw3790j|ZEpb5X!Qn16VKOdUKIw+EYTb}nk z+Up|AOMK1VrB-Lv+N%en-Bf~4o)Z?j#zsP-%~WTR`LJ~=TO*Q#13pMtu+}+V9pmP4 zDSV;)`$NYR3S-nEKWi`BGvI=dnkj}PzHPS>>8rQ9eb22R(w}aex}mdsbtjsTM(l2a zKNw7rT>FVl%nyfsEY*OSy-!2A2lOjwb8Q220~VCFEL`nVz0S9yu~)=};?D5sCcG3p zjFnCs1T-4}6ekITfeP2{`lrw=mOWsUEoq-FX^+CE7~N0MZjw|4%FWIm0{Q+s#N=~w zl728D7SvgnljN)5`5i_;aF<EWeIj;m8+PDs^bIi_pO-1i>>_C73%{&^0^~A^G|pfz z0vHibeH-`v&bwT&e4H;Z*bQ%Xhf2L((Mk;2yKtB)*hkz`EUjnx8n(6cBlZzl5;HUF z?iB6>n;2iXy<9jN-nmfjE_PHajsQx1mD^vFn7f_gjb+#GOc-4AJ7@UB<G-=D*$^TN z(gm;vY>juEN4<R{F^OhKzx7kD8dq(lJ5u&W5}Aie6<gVcG=`NpJ1$p9HqxOFqB?GZ z@~sC@e5I}>=Z2tveR@+tVaq%A5f42<R-;6nMgH^rYZ!nmy{qMXLUOV-#&{p0PtspV zEXz9a1M93SKS^GTthx(U_+lq^)&%^xy=g}FUi1B1Jz6RfnCyYQW#*G$;OR*T4ma>G z2aJ!ocZ1{%RxgD92(qM*42RQnLjx%>O1n#HaGXztOKr&n#UtcI3+FYqg%Y`%f(T#4 zD<`_?VGjmG1(46?RGg9fosr2RBt)eY8JSi-h#b@dV0Ya03%6r{V>7_U2>$w9o|9-Q z9Jq|SqTGntaAUb&?(2v=uEuUIJ%lDQ9SA~O_QOHS%z-|`m;7BuGLuGX*x2byJ;LG} zrWB)$#7_6*4p{7%pBdl~xxYS^V?&6ITKZ^;2Zq6d4k=T}`#a<#_O+GQgz%H}C_ZFp z#9$hrqYT-_lbQ_7XSK*w55&R=SOqPC$nAQm+WQfvK<Q(J>p)(1BM#`u$~4&<Iw(Ls zLp&bj$-ugY38x9O4zP~sH^>`VVI_O{cJ?-1T!p@}c#K@Og01-h{$w1G0XM`9=decn z#C-D$j8rlA>uLAri4kw!NH~?nUv_EU*H{&@(U?FAC8I`E>9t<&^)JXLu>^JF_$~5m zzhBGl)(}JH<#jet&2uPk17)>;rf?`&KHbgzT6;L|VmBg%j_Bu&NJ@?vYWFBRM0AGe z5c}>ZTjQV6ZTx{(_()A{%Z807oiz@Kt9-bOBOc#E7PJjp)K%NFDHo4M)FkQo%#JuW za{nRmHp*u)AiwN7gTP))DUqq^{$Ex#uXu-|{Aq{vcUf_bQ<2_mQ5rWxfH?FKdW+F| zln1pAG<IU)R?#J$Hh(?cmh!gCN*nIvQaoAJ+Z~{nGpKrUIjKxCg0iThXlWec9fyhW z<6Cmxh*YDykc=VSrny)+Na)2il?&OV9b_l5rYaj*$QDV3J||%7WVvhqk{G_7-boTL z>b4NP=<bJa4Tk)BF_ppa$TA#-bAKjKJ2l)uV82(}3P^9<T<yrx(FS<9n!sN@?xQg{ z`hjcb7#kZHPf<Rx`Dzt4P{;d6b?rQ-O>_UXmCr_%+}Dkd8Fy=w?)_`6M0X1A`9uq@ zs`5)%mg+K(R^NZ~&MQyP&CcXoZ#1ZUnaJcY5f-Nq28z3g{hpP2mzjRQDi7@{gg!i= zyt8WY%!sQKe!C*pLWae>gl8o$*myrd_Hf_7clRJ))K4th4_PzAc+Gw2-*#$I?$9Nr zy`h|Qpn2pw@)&{DtYt~_kXF0>^wnbC3N<cKf$UU2zt@Lv$>%3GjA?`uYU-4xn6IlV z{_M(Rb(wC&4FuT#Lfk3Yp4lEpbhTW_Osl}F<r&P?d>uD(czqE+K@|Q}St)zFWMfV; zB9x?{y1RVqQdkP9#AB6=tZztn$vryIiP7{H_h>c#;55SkrTbX391t<8;w93n=>}{` z>Q5<KwKh~~E9E7v36wN$9luy1J0uO3JTkkhDVyQAiaO!$T7Z$h$5X^V`igmmw&oXU z-*9HIcynWY%?7tiU|E`YF4re4W5^`I*2AI9!c8G^1?b>#<QBxYspjr|3tQwgwJ~D1 zqWJc8Qn!f)dG*d8K0o<mG-GXpCS;qvr#0NiT2(|c{B1oghbX8W0gw=pgY0MSx8@CC zGno1!V$$g@QAW(p<8vkFpxEgGh5H8gtfp5-Hn70F>$Kj{x8}j@kn!SmA3<NB^c1_b zqM3@c#8;B@HVV*G?B(F_#_9|kw<*~bpe(Qsf}$h}!D_e@?3VnbopL$V%EV*e+uz)h z@1o;KXQ>vvzWFkbf>!%3O^RoGR(rgd6aKjuHWh6sI*Diz*FDQIg|z}8Cw@)*i^c0J zqh{H>y=QIg?<<zTc>pTjBYQ@M8PRarBch$`n1e&US8;6f(6j1E;ve}R6Q8EkIm_wd zkL$Kco|$~n+MBo4kf@&V_)|LamBcRv%#H8xp3ET=$*k@zOv?^A!-I(<A%QCIRL^vi zKt!9vBTKu(B=L<n*n<y4i7NC6g2`O;v-|uB$H6`R=4sgH-|b7ar`u9t{jSr6En=S` zu*jny>EG<R_Zo~_z7r+eL|zD1)oz`(naRGgEIQiIoYIQ_k;~O@u(Z0YIn~qA3@-Qj zZC2mA(($`bnC=Qmf}|IwWrfK%u?>OMSOc3eefgB6%MRAS6p<1(3|bqrCCM=lN-77v zJrTW2Lux0t2H8`Jj|Y*PUcZet%G$oeUB0V4@0rKCy(@S@vBcv;Ss0(mcvxNr?fqU< zsGbII7Q^0?NtxcKQw{*=c<+3plD<}N_OE9tTZ1neZ1448$=JGA_=|NTzR;4${rBuP zbH@3X$mg?y)IqmB<adKhDlAYa%-g|A#UQLU%1e<HqDF71#hZ2XB_QXJ>rLax9DMc$ zdAUBLyFAv=0EX6ayhY~R0>&Qm-aFQy?F8?;hV}Mu0J|ee>=4u77u#nKhgU#^<Qi=# z%<EIjEs<vQ+&kvejJ$#=BFW)Hh~Hp;N6H@P)+<!<i9%Ba7ETi8|H4eA|A(6TAEN$m u`TsyrMg1QaSQug$gUUU5XORWib=|H1r8QL$Kl~>y>^~0tr+M}MWBnJpRmUg* literal 0 HcmV?d00001