wildfire chat server source initial submit

This commit is contained in:
heavyrain2012
2019-03-16 17:04:23 +08:00
parent e59217bd10
commit cab3ca0916
1466 changed files with 528862 additions and 15919 deletions
@@ -0,0 +1,110 @@
/*
* Copyright 2016 ikidou
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ikidou.reflect;
import ikidou.reflect.exception.TypeException;
import ikidou.reflect.typeimpl.ParameterizedTypeImpl;
import ikidou.reflect.typeimpl.WildcardTypeImpl;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public class TypeBuilder {
private final TypeBuilder parent;
private final Class raw;
private final List<Type> args = new ArrayList<>();
private TypeBuilder(Class raw, TypeBuilder parent) {
assert raw != null;
this.raw = raw;
this.parent = parent;
}
public static TypeBuilder newInstance(Class raw) {
return new TypeBuilder(raw, null);
}
private static TypeBuilder newInstance(Class raw, TypeBuilder parent) {
return new TypeBuilder(raw, parent);
}
public TypeBuilder beginSubType(Class raw) {
return newInstance(raw, this);
}
public TypeBuilder endSubType() {
if (parent == null) {
throw new TypeException("expect beginSubType() before endSubType()");
}
parent.addTypeParam(getType());
return parent;
}
public TypeBuilder addTypeParam(Class clazz) {
return addTypeParam((Type) clazz);
}
public TypeBuilder addTypeParamExtends(Class... classes) {
if (classes == null) {
throw new NullPointerException("addTypeParamExtends() expect not null Class");
}
WildcardTypeImpl wildcardType = new WildcardTypeImpl(null, classes);
return addTypeParam(wildcardType);
}
public TypeBuilder addTypeParamSuper(Class... classes) {
if (classes == null) {
throw new NullPointerException("addTypeParamSuper() expect not null Class");
}
WildcardTypeImpl wildcardType = new WildcardTypeImpl(classes, null);
return addTypeParam(wildcardType);
}
public TypeBuilder addTypeParam(Type type) {
if (type == null) {
throw new NullPointerException("addTypeParam expect not null Type");
}
args.add(type);
return this;
}
public Type build() {
if (parent != null) {
throw new TypeException("expect endSubType() before build()");
}
return getType();
}
private Type getType() {
if (args.isEmpty()) {
return raw;
}
return new ParameterizedTypeImpl(raw, args.toArray(new Type[args.size()]), null);
}
}
@@ -0,0 +1,39 @@
/*
* Copyright 2016 ikidou
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ikidou.reflect;
import ikidou.reflect.exception.TypeException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public abstract class TypeToken<T> {
private final Type type;
public TypeToken() {
Type superclass = getClass().getGenericSuperclass();
if (superclass instanceof Class) {
throw new TypeException("No generics found!");
}
ParameterizedType type = (ParameterizedType) superclass;
this.type = type.getActualTypeArguments()[0];
}
public Type getType() {
return type;
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2016 ikidou
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ikidou.reflect.exception;
public class TypeException extends RuntimeException {
public TypeException() {
}
public TypeException(String message) {
super(message);
}
public TypeException(String message, Throwable cause) {
super(message, cause);
}
public TypeException(Throwable cause) {
super(cause);
}
public TypeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
@@ -0,0 +1,123 @@
/*
* Copyright 2016 ikidou
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ikidou.reflect.typeimpl;
import ikidou.reflect.exception.TypeException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
@SuppressWarnings("SpellCheckingInspection")
public class ParameterizedTypeImpl implements ParameterizedType {
private final Class raw;
private final Type[] args;
private final Type owner;
public ParameterizedTypeImpl(Class raw, Type[] args, Type owner) {
this.raw = raw;
this.args = args != null ? args : new Type[0];
this.owner = owner;
checkArgs();
}
private void checkArgs() {
if (raw == null) {
throw new TypeException("raw class can't be null");
}
TypeVariable[] typeParameters = raw.getTypeParameters();
if (args.length != 0 && typeParameters.length != args.length) {
throw new TypeException(raw.getName() + " expect " + typeParameters.length + " arg(s), got " + args.length);
}
}
@Override
public Type[] getActualTypeArguments() {
return args;
}
@Override
public Type getRawType() {
return raw;
}
@Override
public Type getOwnerType() {
return owner;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(raw.getName());
if (args.length != 0) {
sb.append('<');
for (int i = 0; i < args.length; i++) {
if (i != 0) {
sb.append(", ");
}
Type type = args[i];
if (type instanceof Class) {
Class clazz = (Class) type;
if (clazz.isArray()) {
int count = 0;
do {
count++;
clazz = clazz.getComponentType();
} while (clazz.isArray());
sb.append(clazz.getName());
for (int j = count; j > 0; j--) {
sb.append("[]");
}
} else {
sb.append(clazz.getName());
}
} else {
sb.append(args[i].toString());
}
}
sb.append('>');
}
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ParameterizedTypeImpl that = (ParameterizedTypeImpl) o;
if (!raw.equals(that.raw)) return false;
// Probably incorrect - comparing Object[] arrays with Arrays.equals
if (!Arrays.equals(args, that.args)) return false;
return owner != null ? owner.equals(that.owner) : that.owner == null;
}
@Override
public int hashCode() {
int result = raw.hashCode();
result = 31 * result + Arrays.hashCode(args);
result = 31 * result + (owner != null ? owner.hashCode() : 0);
return result;
}
}
@@ -0,0 +1,106 @@
/*
* Copyright 2016 ikidou
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ikidou.reflect.typeimpl;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
public class WildcardTypeImpl implements WildcardType {
private final Class[] upper;
private final Class[] lower;
public WildcardTypeImpl(Class[] lower, Class[] upper) {
this.lower = lower != null ? lower : new Class[0];
this.upper = upper != null ? upper : new Class[0];
checkArgs();
}
private void checkArgs() {
if (lower.length == 0 && upper.length == 0) {
throw new IllegalArgumentException("lower or upper can't be null");
}
checkArgs(lower);
checkArgs(upper);
}
private void checkArgs(Class[] args) {
for (int i = 1; i < args.length; i++) {
Class clazz = args[i];
if (!clazz.isInterface()) {
throw new IllegalArgumentException(clazz.getName() + " not a interface!");
}
}
}
@Override
public Type[] getUpperBounds() {
return upper;
}
@Override
public Type[] getLowerBounds() {
return lower;
}
@Override
public String toString() {
if (upper.length > 0) {
if (upper[0] == Object.class) {
return "?";
}
return getTypeString("? extends ", upper);
} else {
return getTypeString("? super ", lower);
}
}
private String getTypeString(String prefix, Class[] type) {
StringBuilder sb = new StringBuilder();
sb.append(prefix);
for (int i = 0; i < type.length; i++) {
if (i != 0) {
sb.append(" & ");
}
sb.append(type[i].getName());
}
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WildcardTypeImpl that = (WildcardTypeImpl) o;
return Arrays.equals(upper, that.upper) && Arrays.equals(lower, that.lower);
}
@Override
public int hashCode() {
int result = Arrays.hashCode(upper);
result = 31 * result + Arrays.hashCode(lower);
return result;
}
}
+89
View File
@@ -0,0 +1,89 @@
package net.xmeter;
public interface Constants {
public static final String SERVER = "mqtt.server";
public static final String MQTT_VERSION = "mqtt.version";
public static final String PORT = "mqtt.port";
public static final String CONN_TIMEOUT = "mqtt.conn_timeout";
public static final String PROTOCOL = "mqtt.protocol";
public static final String USER_NAME_AUTH = "mqtt.user_name";
public static final String USER_NAME_PREFIX = "mqtt.user_name_prefix";
public static final String CONN_KEEP_TIME = "mqtt.keep_time";
public static final String CONN_CLIENT_ID_PREFIX = "mqtt.client_id_prefix";
public static final String CONN_CLIENT_ID_SUFFIX = "mqtt.client_id_suffix";
public static final String CONN_ATTAMPT_MAX = "mqtt.conn_attampt_max";
public static final String CONN_KEEP_ALIVE = "mqtt.conn_keep_alive";
public static final String CONN_RECONN_ATTAMPT_MAX = "mqtt.reconn_attampt_max";
public static final String CONN_SHARE_CONNECTION = "mqtt.conn_share";
public static final String MESSAGE_TYPE = "mqtt.message_type";
public static final String MESSAGE_FIX_LENGTH = "mqtt.message_type_fixed_length";
public static final String MESSAGE_TO_BE_SENT = "mqtt.message_to_sent";
public static final String TOPIC_NAME = "mqtt.topic_name";
public static final String QOS_LEVEL = "mqtt.qos_level";
public static final String ADD_TIMESTAMP = "mqtt.add_timestamp";
public static final String SAMPLE_CONDITION_VALUE = "mqtt.sample_condition_value";
public static final String SAMPLE_CONDITION = "mqtt.sample_condition";
public static final String TIME_STAMP_SEP_FLAG = "ts_sep_flag";
public static final String DEBUG_RESPONSE = "mqtt.debug_response";
public static final int QOS_0 = 0;
public static final int QOS_1 = 1;
public static final int QOS_2 = 2;
public static final String MESSAGE_TYPE_RANDOM_STR_WITH_FIX_LEN = "Random string with fixed length";
public static final String MESSAGE_TYPE_HEX_STRING = "Hex string";
public static final String MESSAGE_TYPE_STRING = "String";
public static final String MQTT_VERSION_3_1_1 = "3.1.1";
public static final String MQTT_VERSION_3_1 = "3.1";
public static final String SAMPLE_ON_CONDITION_OPTION1 = "specified elapsed time (ms)";
public static final String SAMPLE_ON_CONDITION_OPTION2 = "number of received messages";
public static final int MAX_CLIENT_ID_LENGTH = 23;
public static final String DEFAULT_SERVER = "127.0.0.1";
public static final String DEFAULT_MQTT_VERSION = "3.1";
public static final String DEFAULT_PORT = "8080";
public static final String DEFAULT_CONN_TIME_OUT = "10";
public static final String DEFAULT_PROTOCOL = "TCP";
public static final boolean DEFAULT_CONNECTION_SHARE = true;
public static final String JMETER_VARIABLE_PREFIX = "${";
public static final String DEFAULT_TOPIC_NAME = "test_topic";
public static final String DEFAULT_TARGET = "test_user";
public static final String CONV_TYPE_SINGLE = "Single";
public static final String CONV_TYPE_GROUP = "Group";
public static final String DEFAULT_CONN_PREFIX_FOR_CONN = "conn_";
public static final String DEFAULT_CONN_PREFIX_FOR_PUB = "pub_";
public static final String DEFAULT_CONN_KEEP_ALIVE = "300";
public static final String DEFAULT_CONN_KEEP_TIME = "1800";
public static final String DEFAULT_CONN_ATTAMPT_MAX = "0";
public static final String DEFAULT_CONN_RECONN_ATTAMPT_MAX = "0";
public static final String DEFAULT_SAMPLE_VALUE_COUNT = "1";
public static final String DEFAULT_SAMPLE_VALUE_ELAPSED_TIME_SEC = "1000";
public static final boolean DEFAULT_ADD_TIMESTAMP = false;
public static final String DEFAULT_MESSAGE_FIX_LENGTH = "1024";
public static final boolean DEFAULT_ADD_CLIENT_ID_SUFFIX = true;
public static final String TARGET = "wildfire.target";
public static final String CONV_TYPE = "wildfire.conv_type";
}
+102
View File
@@ -0,0 +1,102 @@
package net.xmeter;
public class IMResult<T> {
public enum IMResultCode {
//General error
IMRESULT_CODE_SUCCESS(0, "success"),
IMRESULT_CODE_SECRECT_KEY_MISMATCH(1, "secrect key mismatch"),
IMRESULT_CODE_INVALID_DATA(2, "invalid data"),
IMRESULT_CODE_NODE_NOT_EXIST(3, "node not exist"),
IMRESULT_CODE_SERVER_ERROR(4, "server error"),
IMRESULT_CODE_NOT_MODIFIED(5, "not modified"),
//Auth error
IMRESULT_CODE_TOKEN_ERROR(6, "token error"),
IMRESULT_CODE_USER_FORBIDDEN(8, "user forbidden"),
//Message error
IMRESULT_CODE_NOT_IN_GROUP(9, "not in group"),
IMRESULT_CODE_INVALID_MESSAGE(10, "invalid message"),
//Group error
IMRESULT_CODE_GROUP_ALREADY_EXIST(11, "group aleady exist"),
//user error
IMRESULT_CODE_PASSWORD_INCORRECT(15, "password incorrect"),
//user error
IMRESULT_CODE_FRIEND_ALREADY_REQUEST(16, "already send request"),
IMRESULT_CODE_FRIEND_REQUEST_BLOCKED(18, "friend request blocked"),
IMRESULT_CODE_FRIEND_REQUEST_OVERTIME(19, "friend request overtime"),
IMRESULT_CODE_NOT_IN_CHATROOM(20, "not in chatroom"),
IMRESULT_CODE_CLIENT_COUNT_OUT_OF_LIMIT(245, "client count out of limit"),
IMRESULT_CODE_IN_BLACK_LIST(246, "user in balck list"),
IMRESULT_CODE_FORBIDDEN_SEND_MSG(247, "forbidden send msg globally"),
IMRESULT_CODE_NOT_RIGHT(248, "no right to operate"),
IMRESULT_CODE_TIMEOUT(249, "timeout"),
IMRESULT_CODE_OVER_FREQUENCY(250, "over frequency"),
INVALID_PARAMETER(251, "Invalid parameter"),
IMRESULT_CODE_NOT_EXIST(253, "not exist"),
IMRESULT_CODE_NOT_IMPLEMENT(254, "not implement"),
IMRESULT_CODE_ASYNC_HANDLER(255, "异步执行,服务器内部逻辑需要此代码,为正常情况,不能返回客户端"),;
public int code;
public String msg;
IMResultCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
public static IMResultCode fromCode(int code) {
for (IMResultCode errorCode : IMResultCode.values()) {
if(errorCode.code == code) {
return errorCode;
}
}
return IMRESULT_CODE_SERVER_ERROR;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
public int code;
public String msg;
public T result;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
}
+44
View File
@@ -0,0 +1,44 @@
package net.xmeter;
import java.util.ArrayList;
import java.util.List;
public class SubBean {
private int receivedMessageSize = 0;
private int receivedCount = 0;
private double avgElapsedTime = 0f;
private List<String> contents = new ArrayList<String>();
public int getReceivedMessageSize() {
return receivedMessageSize;
}
public void setReceivedMessageSize(int receivedMessageSize) {
this.receivedMessageSize = receivedMessageSize;
}
public int getReceivedCount() {
return receivedCount;
}
public void setReceivedCount(int receivedCount) {
this.receivedCount = receivedCount;
}
public double getAvgElapsedTime() {
return avgElapsedTime;
}
public void setAvgElapsedTime(double avgElapsedTime) {
this.avgElapsedTime = avgElapsedTime;
}
public List<String> getContents() {
return contents;
}
public void setContents(List<String> contents) {
this.contents = contents;
}
}
+46
View File
@@ -0,0 +1,46 @@
package net.xmeter;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.UUID;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.ssl.SSLContexts;
import org.apache.jmeter.services.FileServer;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import net.xmeter.samplers.AbstractMQTTSampler;
public class Util implements Constants {
private static SecureRandom random = new SecureRandom();
private static char[] seeds = "abcdefghijklmnopqrstuvwxmy0123456789".toCharArray();
private transient static Logger logger = LoggingManager.getLoggerForClass();
public static String generateClientId(String prefix) {
int leng = prefix.length();
int postLeng = MAX_CLIENT_ID_LENGTH - leng;
UUID uuid = UUID.randomUUID();
String string = uuid.toString().replace("-", "");
String post = string.substring(0, postLeng);
return prefix + post;
}
public static String generatePayload(int size) {
StringBuffer res = new StringBuffer();
for(int i = 0; i < size; i++) {
res.append(seeds[random.nextInt(seeds.length - 1)]);
}
return res.toString();
}
}
@@ -0,0 +1,173 @@
package net.xmeter.gui;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.apache.jmeter.gui.util.HorizontalPanel;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jorphan.gui.JLabeledTextField;
import net.xmeter.Constants;
import net.xmeter.samplers.AbstractMQTTSampler;
public class CommonConnUI implements ChangeListener, ActionListener, Constants{
private final JLabeledTextField serverAddr = new JLabeledTextField("Server name or IP:");
private final JLabeledTextField serverPort = new JLabeledTextField("Port number:", 5);
private JCheckBox connShared = new JCheckBox("Share conn in thread");
private final JLabeledTextField timeout = new JLabeledTextField("Timeout(s):", 5);
private final JLabeledTextField userNameAuth = new JLabeledTextField("User name:");
private JCheckBox userNameSuffix = new JCheckBox("Add random suffix for user name");
public final JLabeledTextField connNamePrefix = new JLabeledTextField("ClientId:", 8);
private JCheckBox connNameSuffix = new JCheckBox("Add random suffix for ClientId");
private final JLabeledTextField connKeepAlive = new JLabeledTextField("Keep alive(s):", 4);
private final JLabeledTextField connKeeptime = new JLabeledTextField("Connection keep time(s):", 4);
private final JLabeledTextField connAttmptMax = new JLabeledTextField("Connect attampt max:", 0);
private final JLabeledTextField reconnAttmptMax = new JLabeledTextField("Reconnect attampt max:", 0);
public JPanel createConnPanel() {
JPanel con = new HorizontalPanel();
JPanel connPanel = new HorizontalPanel();
connPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "MQTT connection"));
connPanel.add(serverAddr);
connPanel.add(serverPort);
connPanel.add(connShared);
JPanel timeoutPannel = new HorizontalPanel();
timeoutPannel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Timeout"));
timeoutPannel.add(timeout);
con.add(connPanel);
con.add(timeoutPannel);
return con;
}
public JPanel createConnOptions() {
JPanel optsPanelCon = new VerticalPanel();
optsPanelCon.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Connection options"));
JPanel optsPanel0 = new HorizontalPanel();
optsPanel0.add(connNamePrefix);
optsPanel0.add(connNameSuffix);
connNameSuffix.setSelected(true);
optsPanelCon.add(optsPanel0);
JPanel optsPanel1 = new HorizontalPanel();
optsPanel1.add(connKeepAlive);
optsPanel1.add(connKeeptime);
optsPanelCon.add(optsPanel1);
optsPanel1.add(connAttmptMax);
optsPanel1.add(reconnAttmptMax);
optsPanelCon.add(optsPanel1);
return optsPanelCon;
}
public JPanel createAuthentication() {
JPanel optsPanelCon = new VerticalPanel();
optsPanelCon.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "User authentication"));
JPanel optsPanel = new HorizontalPanel();
optsPanel.add(userNameAuth);
optsPanel.add(userNameSuffix);
optsPanelCon.add(optsPanel);
return optsPanelCon;
}
@Override
public void actionPerformed(ActionEvent e) {
String action = e.getActionCommand();
}
@Override
public void stateChanged(ChangeEvent e) {
}
public void configure(AbstractMQTTSampler sampler) {
serverAddr.setText(sampler.getServer());
serverPort.setText(sampler.getPort());
connShared.setSelected(sampler.isConnectionShare());
if(!sampler.isConnectionShareShow()) {
connShared.setVisible(false);
}
timeout.setText(sampler.getConnTimeout());
userNameAuth.setText(sampler.getUserNameProperty());
userNameSuffix.setSelected(sampler.isUserNamePrefix());
connNamePrefix.setText(sampler.getConnPrefix());
if(sampler.isClientIdSuffix()) {
connNameSuffix.setSelected(true);
} else {
connNameSuffix.setSelected(false);
}
connKeepAlive.setText(sampler.getConnKeepAlive());
connKeeptime.setText(sampler.getConnKeepTime());
if(!sampler.isKeepTimeShow()) {
connKeeptime.setVisible(false);
}
connAttmptMax.setText(sampler.getConnAttamptMax());
reconnAttmptMax.setText(sampler.getConnReconnAttamptMax());
}
public void setupSamplerProperties(AbstractMQTTSampler sampler) {
sampler.setServer(serverAddr.getText());
sampler.setPort(serverPort.getText());
sampler.setConnectionShare(connShared.isSelected());
sampler.setConnTimeout(timeout.getText());
sampler.setConnectionShare(connShared.isSelected());
sampler.setUserNameAuth(userNameAuth.getText());
sampler.setUserNamePrefix(userNameSuffix.isSelected());
sampler.setConnPrefix(connNamePrefix.getText());
sampler.setClientIdSuffix(connNameSuffix.isSelected());
sampler.setConnKeepAlive(connKeepAlive.getText());
sampler.setConnKeepTime(connKeeptime.getText());
sampler.setConnAttamptMax(connAttmptMax.getText());
sampler.setConnReconnAttamptMax(reconnAttmptMax.getText());
}
public static int parseInt(String value) {
if(value == null || "".equals(value.trim())) {
return 0;
}
return Integer.parseInt(value);
}
public void clearUI() {
serverAddr.setText(DEFAULT_SERVER);
serverPort.setText(DEFAULT_PORT);
connShared.setSelected(DEFAULT_CONNECTION_SHARE);
timeout.setText(DEFAULT_CONN_TIME_OUT);
userNameAuth.setText("");
userNameSuffix.setSelected(true);
connNamePrefix.setText(DEFAULT_CONN_PREFIX_FOR_CONN);
connNameSuffix.setSelected(true);
connKeepAlive.setText(DEFAULT_CONN_KEEP_ALIVE);
connKeeptime.setText(DEFAULT_CONN_KEEP_TIME);
connAttmptMax.setText(DEFAULT_CONN_ATTAMPT_MAX);
reconnAttmptMax.setText(DEFAULT_CONN_RECONN_ATTAMPT_MAX);
}
}
@@ -0,0 +1,81 @@
package net.xmeter.gui;
import java.awt.BorderLayout;
import javax.swing.JPanel;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import net.xmeter.Constants;
import net.xmeter.samplers.ConnectionSampler;
public class ConnectionSamplerUI extends AbstractSamplerGui implements Constants {
private static final Logger logger = LoggingManager.getLoggerForClass();
private CommonConnUI connUI = new CommonConnUI();
/**
*
*/
private static final long serialVersionUID = 1666890646673145131L;
public ConnectionSamplerUI() {
this.init();
}
private void init() {
logger.info("Initializing the UI.");
logger.info("Initializing the UI2.");
setLayout(new BorderLayout());
setBorder(makeBorder());
add(makeTitlePanel(), BorderLayout.NORTH);
JPanel mainPanel = new VerticalPanel();
add(mainPanel, BorderLayout.CENTER);
mainPanel.add(connUI.createConnPanel());
mainPanel.add(connUI.createAuthentication());
mainPanel.add(connUI.createConnOptions());
}
@Override
public void configure(TestElement element) {
super.configure(element);
ConnectionSampler sampler = (ConnectionSampler)element;
connUI.configure(sampler);
}
@Override
public TestElement createTestElement() {
ConnectionSampler sampler = new ConnectionSampler();
this.configureTestElement(sampler);
connUI.setupSamplerProperties(sampler);
return sampler;
}
@Override
public String getLabelResource() {
throw new RuntimeException();
}
@Override
public String getStaticLabel() {
return "Wildfire Connection Sampler";
}
@Override
public void modifyTestElement(TestElement arg0) {
ConnectionSampler sampler = (ConnectionSampler)arg0;
this.configureTestElement(sampler);
connUI.setupSamplerProperties(sampler);
}
@Override
public void clearGui() {
super.clearGui();
connUI.clearUI();
}
}
@@ -0,0 +1,209 @@
package net.xmeter.gui;
import java.awt.BorderLayout;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import net.xmeter.samplers.SendMessageSampler;
import org.apache.jmeter.gui.util.HorizontalPanel;
import org.apache.jmeter.gui.util.JSyntaxTextArea;
import org.apache.jmeter.gui.util.JTextScrollPane;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.gui.JLabeledChoice;
import org.apache.jorphan.gui.JLabeledTextField;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import net.xmeter.Constants;
public class SendMessageSamplerUI extends AbstractSamplerGui implements Constants, ChangeListener {
private static final Logger logger = LoggingManager.getLoggerForClass();
private CommonConnUI connUI = new CommonConnUI();
/**
*
*/
private static final long serialVersionUID = 2479085966683186422L;
private JLabeledChoice conversationTypeChoice;
private final JLabeledTextField target = new JLabeledTextField("Target:");
// private JCheckBox timestamp = new JCheckBox("Add timestamp in payload");
private final JSyntaxTextArea sendMessage = JSyntaxTextArea.getInstance(10, 50);
private final JTextScrollPane messagePanel = JTextScrollPane.getInstance(sendMessage);
// private JLabeledTextField stringLength = new JLabeledTextField("Length:");
public SendMessageSamplerUI() {
init();
}
private void init() {
logger.info("Initializing the UI.");
setLayout(new BorderLayout());
setBorder(makeBorder());
add(makeTitlePanel(), BorderLayout.NORTH);
JPanel mainPanel = new VerticalPanel();
add(mainPanel, BorderLayout.CENTER);
mainPanel.add(connUI.createConnPanel());
mainPanel.add(connUI.createAuthentication());
mainPanel.add(connUI.createConnOptions());
mainPanel.add(createPubOption());
mainPanel.add(createPayload());
}
private JPanel createPubOption() {
JPanel optsPanelCon = new VerticalPanel();
optsPanelCon.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Send message options"));
conversationTypeChoice = new JLabeledChoice("ConversationType:", new String[] { CONV_TYPE_SINGLE, CONV_TYPE_GROUP }, true, false);
conversationTypeChoice.addChangeListener(this);
JPanel optsPanel = new HorizontalPanel();
optsPanel.add(conversationTypeChoice);
optsPanel.add(target);
// optsPanel.add(timestamp);
optsPanelCon.add(optsPanel);
return optsPanelCon;
}
private JPanel createPayload() {
JPanel optsPanelCon = new VerticalPanel();
optsPanelCon.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Message Content"));
// JPanel horizon1 = new HorizontalPanel();
//
// stringLength.setVisible(true);
// horizon1.add(stringLength);
JPanel horizon2 = new VerticalPanel();
messagePanel.setVisible(true);
horizon2.add(messagePanel);
// optsPanelCon.add(horizon1);
optsPanelCon.add(horizon2);
return optsPanelCon;
}
@Override
public String getStaticLabel() {
return "Wildfire Send Message Sampler";
}
@Override
public void stateChanged(ChangeEvent e) {
// if(e.getSource() == this.messageTypes) {
// int selectedIndex = this.messageTypes.getSelectedIndex();
// if(selectedIndex == 0 || selectedIndex == 1) {
// stringLength.setVisible(false);
// messagePanel.setVisible(true);
// } else if(selectedIndex == 2) {
// messagePanel.setVisible(false);
// stringLength.setVisible(true);
// } else {
// logger.info("Unknown message type.");
// }
// }
}
@Override
public String getLabelResource() {
return "";
}
@Override
public TestElement createTestElement() {
logger.info("createTestElement called.");
SendMessageSampler sampler = new SendMessageSampler();
this.setupSamplerProperties(sampler);
connUI.setupSamplerProperties(sampler);
return sampler;
}
@Override
public void configure(TestElement element) {
logger.info("configure called.");
super.configure(element);
SendMessageSampler sampler = (SendMessageSampler) element;
connUI.configure(sampler);
// if(sampler.getQOS().trim().indexOf(JMETER_VARIABLE_PREFIX) == -1){
this.conversationTypeChoice.setSelectedIndex(0);
// } else {
// this.conversationTypeChoice.setText(sampler.getQOS());
// }
this.target.setText(sampler.getTopic());
// this.timestamp.setSelected(sampler.isAddTimestamp());
// if(MESSAGE_TYPE_STRING.equalsIgnoreCase(sampler.getMessageType())) {
// this.messageTypes.setSelectedIndex(0);
// this.messagePanel.setVisible(true);
// } else if(MESSAGE_TYPE_HEX_STRING.equalsIgnoreCase(sampler.getMessageType())) {
// this.messageTypes.setSelectedIndex(1);
// } else if(MESSAGE_TYPE_RANDOM_STR_WITH_FIX_LEN.equalsIgnoreCase(sampler.getMessageType())) {
// this.messageTypes.setSelectedIndex(2);
// }
//
// stringLength.setText(String.valueOf(sampler.getMessageLength()));
sendMessage.setText(sampler.getMessage());
}
@Override
public void modifyTestElement(TestElement arg0) {
logger.info("modifyTestElement called.");
SendMessageSampler sampler = (SendMessageSampler) arg0;
this.setupSamplerProperties(sampler);
connUI.setupSamplerProperties(sampler);
}
private void setupSamplerProperties(SendMessageSampler sampler) {
this.configureTestElement(sampler);
connUI.setupSamplerProperties(sampler);
sampler.setTarget(this.target.getText());
// if(this.conversationTypeChoice.getText().indexOf(JMETER_VARIABLE_PREFIX) == -1) {
// int qos = QOS_0;
// try {
// qos = Integer.parseInt(this.conversationTypeChoice.getText());
// if (qos < QOS_0 || qos > QOS_2) {
// qos = QOS_0;
// logger.info("Invalid QoS value, set to default QoS value 0.");
// }
// } catch (Exception ex) {
// logger.info("Invalid QoS value, set to default QoS value 0.");
// qos = QOS_0;
// }
// sampler.setQOS(String.valueOf(qos));
// } else {
// sampler.setQOS(this.conversationTypeChoice.getText());
// }
// sampler.setAddTimestamp(this.timestamp.isSelected());
// sampler.setMessageType(this.messageTypes.getText());
// sampler.setMessageLength(this.stringLength.getText());
sampler.setMessage(this.sendMessage.getText());
}
@Override
public void clearGui() {
logger.info("clearGui called.");
super.clearGui();
connUI.clearUI();
connUI.connNamePrefix.setText(DEFAULT_CONN_PREFIX_FOR_PUB);
this.target.setText(DEFAULT_TARGET);
this.conversationTypeChoice.setText(CONV_TYPE_SINGLE);
// this.timestamp.setSelected(false);
// this.messageTypes.setSelectedIndex(0);
// this.stringLength.setText(String.valueOf(DEFAULT_MESSAGE_FIX_LENGTH));
this.sendMessage.setText("");
}
}
@@ -0,0 +1,361 @@
package net.xmeter.samplers;
import cn.wildfirechat.proto.WFCMessage;
import com.google.gson.Gson;
import com.xiaoleilu.loServer.pojos.InputRoute;
import com.xiaoleilu.loServer.pojos.InputGetToken;
import com.xiaoleilu.loServer.pojos.OutputGetIMTokenData;
import io.moquette.spi.impl.security.AES;
import net.xmeter.IMResult;
import net.xmeter.Util;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.jmeter.samplers.AbstractSampler;
import net.xmeter.Constants;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.Base64;
public abstract class AbstractMQTTSampler extends AbstractSampler implements Constants {
private transient static Logger logger = LoggingManager.getLoggerForClass();
/**
*
*/
private static final long serialVersionUID = 7163793218595455807L;
public String getServer() {
return getPropertyAsString(SERVER, DEFAULT_SERVER);
}
public void setServer(String server) {
setProperty(SERVER, server);
}
public String getMqttVersion() {
return getPropertyAsString(MQTT_VERSION, DEFAULT_MQTT_VERSION);
}
public String getPort() {
return getPropertyAsString(PORT, DEFAULT_PORT);
}
public void setPort(String port) {
setProperty(PORT, port);
}
public boolean isConnectionShare() {
return getPropertyAsBoolean(CONN_SHARE_CONNECTION, DEFAULT_CONNECTION_SHARE);
}
public void setConnectionShare(boolean shared) {
setProperty(CONN_SHARE_CONNECTION, shared);
}
public String getConnTimeout() {
return getPropertyAsString(CONN_TIMEOUT, DEFAULT_CONN_TIME_OUT);
}
public void setConnTimeout(String connTimeout) {
setProperty(CONN_TIMEOUT, connTimeout);
}
public String getProtocol() {
return getPropertyAsString(PROTOCOL, DEFAULT_PROTOCOL);
}
public String getConnPrefix() {
return getPropertyAsString(CONN_CLIENT_ID_PREFIX, DEFAULT_CONN_PREFIX_FOR_CONN);
}
public void setConnPrefix(String connPrefix) {
logger.info("set connprefix:" + connPrefix);
setProperty(CONN_CLIENT_ID_PREFIX, connPrefix);
}
public String getConnKeepAlive() {
return getPropertyAsString(CONN_KEEP_ALIVE, DEFAULT_CONN_KEEP_ALIVE);
}
public void setConnKeepAlive(String connKeepAlive) {
setProperty(CONN_KEEP_ALIVE, connKeepAlive);
}
public boolean isClientIdSuffix() {
return getPropertyAsBoolean(CONN_CLIENT_ID_SUFFIX, DEFAULT_ADD_CLIENT_ID_SUFFIX);
}
public void setClientIdSuffix(boolean clientIdSuffix) {
setProperty(CONN_CLIENT_ID_SUFFIX, clientIdSuffix);
}
public String getConnKeepTime() {
return getPropertyAsString(CONN_KEEP_TIME, DEFAULT_CONN_KEEP_TIME);
}
public void setConnKeepTime(String connKeepTime) {
setProperty(CONN_KEEP_TIME, connKeepTime);
}
public String getConnAttamptMax() {
return getPropertyAsString(CONN_ATTAMPT_MAX, DEFAULT_CONN_ATTAMPT_MAX);
}
public void setConnAttamptMax(String connAttamptMax) {
setProperty(CONN_ATTAMPT_MAX, connAttamptMax);
}
public String getConnReconnAttamptMax() {
return getPropertyAsString(CONN_RECONN_ATTAMPT_MAX, DEFAULT_CONN_RECONN_ATTAMPT_MAX);
}
public void setConnReconnAttamptMax(String connReconnAttamptMax) {
setProperty(CONN_RECONN_ATTAMPT_MAX, connReconnAttamptMax);
}
public String getUserNameProperty() {
return getPropertyAsString(USER_NAME_AUTH, "").trim();
}
private String userName;
public String getUserNameAuth() {
if (userName == null) {
String prefix = getUserNameProperty();
if (isUserNamePrefix()) {
userName = Util.generateClientId(prefix);
} else {
userName = prefix;
}
}
return userName;
}
public void setUserNameAuth(String userName) {
setProperty(USER_NAME_AUTH, userName);
}
public void setUserName(String userName) {
this.userName = userName;
}
public boolean isUserNamePrefix() {
return getPropertyAsBoolean(USER_NAME_PREFIX);
}
public void setUserNamePrefix(boolean prefix) {
setProperty(USER_NAME_PREFIX, prefix);
}
public boolean isKeepTimeShow() {
return false;
}
public boolean isConnectionShareShow() {
return false;
}
private String clientId;
protected String getClientId() {
if (clientId == null) {
if (isClientIdSuffix()) {
clientId = Util.generateClientId(getConnPrefix());
} else {
clientId = getConnPrefix();
}
}
return clientId;
}
protected String mqttServerIp;
protected long mqttServerPort;
private static byte[] commonSecret= {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F};
protected String privateSecret;
protected String token;
protected boolean getToken(String userId) {
String url = "http://" + getServer() + ":18080/admin/user/token";
String adminSecret = "123456";
HttpPost post = null;
try {
HttpClient httpClient = HttpClientBuilder.create().build();
int nonce = (int)(Math.random() * 100000 + 3);
long timestamp = System.currentTimeMillis();
String str = nonce + "|" + adminSecret + "|" + timestamp;
String sign = DigestUtils.sha1Hex(str);
post = new HttpPost(url);
post.setHeader("Content-type", "application/json; charset=utf-8");
post.setHeader("Connection", "Keep-Alive");
post.setHeader("nonce", nonce + "");
post.setHeader("timestamp", "" + timestamp);
post.setHeader("sign", sign);
String jsonStr = new Gson().toJson(new InputGetToken(userId, getClientId()));
logger.info("http request content: " + jsonStr);
StringEntity entity = new StringEntity(jsonStr, Charset.forName("UTF-8"));
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
post.setEntity(entity);
HttpResponse response = httpClient.execute(post);
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode != HttpStatus.SC_OK){
logger.info("Request error: " + statusCode);
throw new Exception("Http request error with code:" + statusCode);
}else{
BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity()
.getContent(),"utf-8"));
StringBuffer sb = new StringBuffer();
String line;
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
String content = sb.toString();
logger.info("http request response content: " + content);
IMResult<OutputGetIMTokenData> result = fromJsonObject(content, OutputGetIMTokenData.class);
if (result == null || result.getCode() != IMResult.IMResultCode.IMRESULT_CODE_SUCCESS.code) {
logger.error("get token result failure");
return false;
}
OutputGetIMTokenData out = result.getResult();
if (out != null && out.getToken() != null) {
byte[] data = Base64.getDecoder().decode(out.getToken());
if (data != null) {
data = AES.AESDecrypt(data, null, true);
if (data != null) {
String tokensecrets = new String(data);
String[] keys = tokensecrets.split("\\|");
if (keys.length == 3) {
token = keys[0];
privateSecret = keys[1];
return true;
} else {
logger.info("get token keys not correct (" + tokensecrets + ")");
}
} else {
logger.info("get token decode token failure");
}
} else {
logger.info("get token decode base64 failure");
}
} else {
logger.info("get token data invalide");
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(post != null){
post.releaseConnection();
}
}
return false;
}
private static <T> IMResult<T> fromJsonObject(String content, Class<T> clazz) {
Type type = ikidou.reflect.TypeBuilder
.newInstance(IMResult.class)
.addTypeParam(clazz)
.build();
return new Gson().fromJson(content, type);
}
protected boolean route(String userId, String token) {
HttpPost httpPost;
try{
HttpClient httpClient = new DefaultHttpClient();
httpPost = new HttpPost("http://" + getServer() + ":" + getPort() + "/route");
String cid = Base64.getEncoder().encodeToString(AES.AESEncrypt(getClientId().getBytes(), commonSecret));
httpPost.setHeader("cid", cid);
String uid = Base64.getEncoder().encodeToString(AES.AESEncrypt(userId.getBytes(), commonSecret));
httpPost.setHeader("uid", uid);
InputRoute inputRoute = new InputRoute();
inputRoute.setUserId(userId);
inputRoute.setClientId(getClientId());
inputRoute.setToken(token);
WFCMessage.RouteRequest routeRequest = WFCMessage.RouteRequest.newBuilder().setApp("jmeter.test").setSdkVersion("0.1").build();
WFCMessage.IMHttpWrapper request = WFCMessage.IMHttpWrapper.newBuilder().setClientId(getClientId()).setToken(token).setRequest("ROUTE").setData(routeRequest.toByteString()).build();
byte[] data = AES.AESEncrypt(request.toByteArray(), privateSecret );
data = Base64.getEncoder().encode(data);
StringEntity entity = new StringEntity(new String(data), Charset.forName("UTF-8"));
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost);
if(response != null){
if (response.getStatusLine().getStatusCode() != 200) {
logger.error("Http response error {" + response.getStatusLine().getStatusCode() + "}");
return false;
}
HttpEntity resEntity = response.getEntity();
if(resEntity != null){
try {
byte[] contentbyte = new byte[(int)response.getEntity().getContentLength()];
int readLen = response.getEntity().getContent().read(contentbyte);
data = new byte[contentbyte.length - 1];
for (int i = 0; i < data.length; i++) {
data[i] = contentbyte[i+1];
}
data = AES.AESDecrypt(data, privateSecret, true);
WFCMessage.RouteResponse routeResponse = WFCMessage.RouteResponse.parseFrom(data);
mqttServerIp = routeResponse.getHost();
mqttServerPort = routeResponse.getLongPort();
routeResponse.getShortPort();
return true;
} catch (IOException e) {
e.printStackTrace();
logger.error(e.toString());
} catch (UnsupportedOperationException e) {
e.printStackTrace();
logger.error(e.toString());
}
} else {
logger.error("route response entry is nil");
}
} else {
logger.error("Http response nil");
}
}catch(IOException ex){
ex.printStackTrace();
logger.error(ex.toString());
}
return false;
}
}
@@ -0,0 +1,42 @@
package net.xmeter.samplers;
import java.text.MessageFormat;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import org.apache.log.Priority;
import org.fusesource.mqtt.client.Callback;
import org.fusesource.mqtt.client.CallbackConnection;
public class ConnectionCallback implements Callback<byte[]>{
private static Logger logger = LoggingManager.getLoggerForClass();
private Object connLock;
private CallbackConnection connection;
private boolean connectionSucc = false;
public ConnectionCallback(CallbackConnection connection, Object connLock) {
this.connection = connection;
this.connLock = connLock;
}
@Override
public void onSuccess(byte[] value) {
synchronized (connLock) {
logger.info(MessageFormat.format("The connection {0} is established successfully.", this.connection + Thread.currentThread().getName()));
connectionSucc = true;
this.connLock.notify();
}
}
@Override
public void onFailure(Throwable value) {
synchronized (connLock) {
connectionSucc = false;
logger.log(Priority.ERROR, value.getMessage(), value);
this.connLock.notify();
}
}
public boolean isConnectionSucc() {
return connectionSucc;
}
}
@@ -0,0 +1,222 @@
package net.xmeter.samplers;
import java.text.MessageFormat;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import io.moquette.spi.impl.security.AES;
import org.apache.jmeter.JMeter;
import org.apache.jmeter.samplers.Entry;
import org.apache.jmeter.samplers.Interruptible;
import org.apache.jmeter.samplers.SampleEvent;
import org.apache.jmeter.samplers.SampleListener;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.TestStateListener;
import org.apache.jmeter.testelement.ThreadListener;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import org.apache.log.Priority;
import org.fusesource.hawtbuf.UTF8Buffer;
import org.fusesource.mqtt.client.Future;
import org.fusesource.mqtt.client.FutureConnection;
import org.fusesource.mqtt.client.MQTT;
public class ConnectionSampler extends AbstractMQTTSampler
implements TestStateListener, ThreadListener, Interruptible, SampleListener {
private transient static Logger logger = LoggingManager.getLoggerForClass();
private transient MQTT mqtt = new MQTT();
private transient FutureConnection connection = null;
private boolean interrupt = false;
//Declare it as static, for the instance variable will be set to initial value 0 in testEnded method.
//The static value will not be reset.
private static int keepTime = 0;
private static AtomicBoolean sleepFlag = new AtomicBoolean(false);
/**
*
*/
private static final long serialVersionUID = 1859006013465470528L;
@Override
public boolean isKeepTimeShow() {
return true;
}
@Override
public SampleResult sample(Entry entry) {
SampleResult result = new SampleResult();
result.setSampleLabel(getName());
try {
result.sampleStart();
if (!getToken(getUserNameAuth())) {
throw new Exception("get token failure!!!");
}
if (!route(getUserNameAuth(), token)) {
throw new Exception("route failure!!!");
}
mqtt.setHost("tcp://" + mqttServerIp + ":" + mqttServerPort);
mqtt.setVersion(getMqttVersion());
mqtt.setKeepAlive((short) Integer.parseInt(getConnKeepAlive()));
mqtt.setClientId(getClientId());
mqtt.setConnectAttemptsMax(Integer.parseInt(getConnAttamptMax()));
mqtt.setReconnectAttemptsMax(Integer.parseInt(getConnReconnAttamptMax()));
mqtt.setUserName(getUserNameAuth());
byte[] password = AES.AESEncrypt(token, privateSecret);
mqtt.setPassword(new UTF8Buffer(password));
connection = mqtt.futureConnection();
Future<byte[]> f1 = connection.connect();
f1.await(Integer.parseInt(getConnTimeout()), TimeUnit.SECONDS);
result.sampleEnd();
result.setSuccessful(true);
result.setResponseData("Successful.".getBytes());
result.setResponseMessage(MessageFormat.format("Connection {0} connected successfully.", connection));
result.setResponseCodeOK();
} catch (Exception e) {
logger.log(Priority.ERROR, e.getMessage(), e);
result.sampleEnd();
result.setSuccessful(false);
result.setResponseMessage(MessageFormat.format("Connection {0} connected failed.", connection));
result.setResponseData("Failed.".getBytes());
result.setResponseCode("500");
}
return result;
}
@Override
public void testEnded() {
this.testEnded("local");
}
@Override
public void testEnded(String arg0) {
logger.info("in testEnded, isNonGUI=" + JMeter.isNonGUI() + ", sleepFlag=" + sleepFlag.get());
this.interrupt = true;
try {
if (JMeter.isNonGUI()) {
if(!sleepFlag.get()) {
//The keepTime is saved as static variable, because keepTime variable in testEnded()
//returns with initial value.
logger.info("The work has been done, will keep connection for " + keepTime + " sceconds.");
TimeUnit.SECONDS.sleep(keepTime);
sleepFlag.set(true);
}
//The following code does not make sense, because the connection variable was already reset.
//But it makes sense in threadFinished method.
//The reason for not sleeping and then disconnecting in threadFinished is to avoid maintain too much of threads.
//Otherwise each thread (for a thread-group) will be kept open before sleeping.
/*if(this.connection != null) {
this.connection.disconnect();
logger.info(MessageFormat.format("The connection {0} disconneted successfully.", connection));
}*/
}
} catch(Exception ex) {
logger.error(ex.getMessage(), ex);
}
}
@Override
public void testStarted() {
this.testStarted("local");
}
@Override
public void testStarted(String arg0) {
sleepFlag.set(false);
keepTime = Integer.parseInt(getConnKeepTime());
logger.info("*** Keeptime is: " + keepTime);
}
@Override
public void threadFinished() {
}
private void sleepCurrentThreadAndDisconnect() {
try {
//If the connection is null or does not connect successfully, then not necessary to keep the connection.
if(connection == null || (!connection.isConnected())) {
if(connection == null) {
logger.info("Connection is null.");
} else if(!connection.isConnected()) {
logger.info("Connection is created, but is not connected.");
}
return;
}
long start = System.currentTimeMillis();
while ((System.currentTimeMillis() - start) <= TimeUnit.SECONDS.toMillis(keepTime)) {
if (this.interrupt) {
logger.info("interrupted flag is true, and stop the sleep.");
break;
}
TimeUnit.SECONDS.sleep(1);
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
if (connection != null) {
try {
connection.kill().await();
} catch (Exception e) {
e.printStackTrace();
}
logger.log(Priority.INFO, MessageFormat.format("The connection {0} disconneted successfully.", connection));
}
}
}
@Override
public void threadStarted() {
}
@Override
public boolean interrupt() {
this.interrupt = true;
if (!JMeter.isNonGUI()) {
logger.info("In GUI mode, received the interrupt request from user.");
}
return true;
}
// Note: JMeter.isNonGUI() only valid when you specify "-n" option from command line,
// other cases (such as JMeter GUI, remote engine) all treat isNonGUI() as "false"
// So, if you use remote engine, it's actually follow isNonGUI()=false path in this sampler code,
// and you can control the test and stop it in JMeter GUI via say "Remote Stop All" button.
//
// You can also start remote agent with say "jmeter-server -DJMeter.NonGui=true",
// in order to fool JMeter to treat isNonGUI() as "true".
// However, the interrupt mechanism may not work well with remote engine when stop the remote test from JMeter GUI,
// you may need to manually kill remote jmeter process to clean it up.
//
/**
* In this listener, it can receive the interrupt event trigger by user.
*/
@Override
public void sampleOccurred(SampleEvent event) {
if (!JMeter.isNonGUI() && "Wildfire Connection Sampler".equals(event.getResult().getSampleLabel() )) {
logger.info("Created the sampler results, will sleep current thread for " + getConnKeepTime() + " sceconds");
sleepCurrentThreadAndDisconnect();
}
}
@Override
public void sampleStarted(SampleEvent arg0) {
}
@Override
public void sampleStopped(SampleEvent arg0) {
}
}
@@ -0,0 +1,72 @@
package net.xmeter.samplers;
import java.util.concurrent.ConcurrentHashMap;
import org.fusesource.mqtt.client.CallbackConnection;
import org.fusesource.mqtt.client.MQTT;
public class ConnectionsManager {
public static class ConnectionInfo {
public String userName;
public String token;
public String privateSecrect;
public String serverAddress;
public long serverPort;
public ConnectionInfo(String userName, String token, String privateSecrect, String serverAddress, long serverPort) {
this.userName = userName;
this.token = token;
this.privateSecrect = privateSecrect;
this.serverAddress = serverAddress;
this.serverPort = serverPort;
}
}
private ConcurrentHashMap<String, CallbackConnection> connections = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, Boolean> connectionsStatus = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, ConnectionInfo> connectionInfos = new ConcurrentHashMap<>();
private static ConnectionsManager connectionsManager = new ConnectionsManager();
private ConnectionsManager() {
}
public static synchronized ConnectionsManager getInstance() {
return connectionsManager;
}
public CallbackConnection createConnection(String key, MQTT mqtt, ConnectionInfo connectionInfo) {
CallbackConnection conn = mqtt.callbackConnection();
connections.put(key, conn);
connectionInfos.put(key, connectionInfo);
return conn;
}
public CallbackConnection getConnection(String key) {
return this.connections.get(key);
}
public ConnectionInfo getConnectionInfo(String key) {
return this.connectionInfos.get(key);
}
public boolean containsConnection(String key) {
return connections.containsKey(key);
}
public void removeConnection(String key) {
this.connections.remove(key);
this.connectionInfos.remove(key);
}
public void setConnectionStatus(String key, Boolean status) {
connectionsStatus.put(key, status);
}
public boolean getConnectionStatus(String key) {
if(!connectionsStatus.containsKey(key)) {
throw new RuntimeException("Cannot find conn status for key: " + key);
}
return connectionsStatus.get(key);
}
}
@@ -0,0 +1,54 @@
package net.xmeter.samplers;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import org.apache.log.Priority;
import org.fusesource.mqtt.client.Callback;
public class SendMessageCallback implements Callback<byte[]>{
private static Logger logger = LoggingManager.getLoggerForClass();
private boolean successful = false;
private Object connLock;
private int errorCode;
public SendMessageCallback(Object connLock) {
this.connLock = connLock;
}
@Override
public void onSuccess(byte[] value) {
//If QoS == 0, then the current thread is the same thread of caller thread.
//Else if QoS == 1 | 2, then the current thread is hawtdispatch-DEFAULT-x
if (value != null && value.length > 0) {
errorCode = value[0]&0xff;
} else {
onFailure(new Throwable("Send message with invalid data back"));
return;
}
if (errorCode != 0) {
onFailure(new Throwable("Send message failure with error code(" + errorCode + ")"));
return;
}
synchronized (connLock) {
this.successful = true;
connLock.notify();
}
}
@Override
public void onFailure(Throwable value) {
synchronized (connLock) {
this.successful = false;
logger.log(Priority.ERROR, value.getMessage(), value);
connLock.notify();
}
}
public boolean isSuccessful() {
return successful;
}
public int getErrorCode() {
return errorCode;
}
}
@@ -0,0 +1,317 @@
package net.xmeter.samplers;
import java.text.MessageFormat;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.xml.bind.DatatypeConverter;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import io.moquette.spi.impl.security.AES;
import org.fusesource.mqtt.client.MQTT;
import org.apache.jmeter.samplers.Entry;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.ThreadListener;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import org.apache.log.Priority;
import org.fusesource.hawtbuf.Buffer;
import org.fusesource.hawtbuf.UTF8Buffer;
import net.xmeter.Util;
import org.fusesource.mqtt.client.Callback;
import org.fusesource.mqtt.client.CallbackConnection;
import org.fusesource.mqtt.client.Listener;
import org.fusesource.mqtt.client.QoS;
public class SendMessageSampler extends AbstractMQTTSampler implements ThreadListener {
/**
*
*/
private static final long serialVersionUID = -4312341622759500786L;
private transient static Logger logger = LoggingManager.getLoggerForClass();
private transient MQTT mqtt = new MQTT();
private transient CallbackConnection connection = null;
private String payload = null;
private QoS qos_enum = QoS.AT_MOST_ONCE;
private String topicName = "";
private String connKey = "";
public String getQOS() {
return getPropertyAsString(QOS_LEVEL, String.valueOf(QOS_0));
}
public void setQOS(String qos) {
setProperty(QOS_LEVEL, qos);
}
public String getTopic() {
return getPropertyAsString(TOPIC_NAME, DEFAULT_TOPIC_NAME);
}
public void setTopic(String topicName) {
setProperty(TOPIC_NAME, topicName);
}
public void setTarget(String target) {
setProperty(TARGET, target);
}
public String getTarget() {
return getPropertyAsString(TARGET, DEFAULT_TARGET);
}
public void setConvType(String type) {
setProperty(CONV_TYPE, type);
}
public String getConvType() {
return getPropertyAsString(CONV_TYPE, CONV_TYPE_SINGLE);
}
public boolean isAddTimestamp() {
return getPropertyAsBoolean(ADD_TIMESTAMP);
}
public void setAddTimestamp(boolean addTimestamp) {
setProperty(ADD_TIMESTAMP, addTimestamp);
}
public String getMessageType() {
return getPropertyAsString(MESSAGE_TYPE, MESSAGE_TYPE_RANDOM_STR_WITH_FIX_LEN);
}
public void setMessageType(String messageType) {
setProperty(MESSAGE_TYPE, messageType);
}
public String getMessageLength() {
return getPropertyAsString(MESSAGE_FIX_LENGTH, DEFAULT_MESSAGE_FIX_LENGTH);
}
public void setMessageLength(String length) {
setProperty(MESSAGE_FIX_LENGTH, length);
}
public String getMessage() {
return getPropertyAsString(MESSAGE_TO_BE_SENT, "hello");
}
public void setMessage(String message) {
setProperty(MESSAGE_TO_BE_SENT, message);
}
public String getConnPrefix() {
return getPropertyAsString(CONN_CLIENT_ID_PREFIX, DEFAULT_CONN_PREFIX_FOR_PUB);
}
public static byte[] hexToBinary(String hex) {
return DatatypeConverter.parseHexBinary(hex);
}
@Override
public boolean isConnectionShareShow() {
return true;
}
private String getKey() {
String key = getThreadName();
if(!isConnectionShare()) {
key = new String(getThreadName() + this.hashCode());
}
return key;
}
@Override
public SampleResult sample(Entry arg0) {
this.connKey = getKey();
if(connection == null) {
connection = ConnectionsManager.getInstance().getConnection(connKey);
if(connection != null) {
logger.info("Use the shared connection: " + connection);
ConnectionsManager.ConnectionInfo info = ConnectionsManager.getInstance().getConnectionInfo(connKey);
setUserName(info.userName);
token = info.token;
privateSecret = info.privateSecrect;
mqttServerIp = info.serverAddress;
mqttServerPort = info.serverPort;
} else {
try {
if (!getToken(getUserNameAuth())) {
throw new Exception("get token failure!!!");
}
if (!route(getUserNameAuth(), token)) {
throw new Exception("route failure!!!");
}
mqtt.setHost("tcp://" + mqttServerIp + ":" + mqttServerPort);
mqtt.setVersion(getMqttVersion());
mqtt.setKeepAlive((short) Integer.parseInt(getConnKeepAlive()));
mqtt.setClientId(getClientId());
mqtt.setConnectAttemptsMax(Integer.parseInt(getConnAttamptMax()));
mqtt.setReconnectAttemptsMax(Integer.parseInt(getConnReconnAttamptMax()));
mqtt.setUserName(getUserNameAuth());
byte[] password = AES.AESEncrypt(token, privateSecret);
mqtt.setPassword(new UTF8Buffer(password));
Object connLock = new Object();
connection = ConnectionsManager.getInstance().createConnection(connKey, mqtt, new ConnectionsManager.ConnectionInfo(getUserNameAuth(), token, privateSecret, mqttServerIp, mqttServerPort));
connection.listener(new Listener() {
@Override
public void onConnected() {
}
@Override
public void onDisconnected() {
}
@Override
public void onPublish(UTF8Buffer topic, Buffer body, Runnable ack) {
logger.log(Priority.DEBUG, "receive publish with topic:" + topic);
ack.run();
}
@Override
public void onFailure(Throwable value) {
}
});
synchronized (connLock) {
ConnectionCallback callback = new ConnectionCallback(connection, connLock);
connection.connect(callback);
connLock.wait(TimeUnit.SECONDS.toMillis(Integer.parseInt(getConnTimeout())));
ConnectionsManager.getInstance().setConnectionStatus(connKey, callback.isConnectionSucc());
}
} catch (Exception e) {
logger.log(Priority.ERROR, e.getMessage(), e);
ConnectionsManager.getInstance().setConnectionStatus(connKey, false);
}
}
}
payload = getMessage();
if(payload == null) {
payload = Util.generatePayload(120);
}
SampleResult result = new SampleResult();
result.setSampleLabel(getName());
if(!ConnectionsManager.getInstance().getConnectionStatus(connKey)) {
result.sampleStart();
result.setSuccessful(false);
result.sampleEnd();
result.setResponseMessage(MessageFormat.format("Publish failed for connection {0}.", connection));
result.setResponseData("Publish failed becasue the connection has not been established.".getBytes());
result.setResponseCode("500");
return result;
}
try {
byte[] toSend;
result.sampleStart();
final Object connLock = new Object();
SendMessageCallback pubCallback = new SendMessageCallback(connLock);
WFCMessage.Message message = WFCMessage.Message.newBuilder()
.setConversation(WFCMessage.Conversation.newBuilder().setType(getConvType().equals(CONV_TYPE_SINGLE) ? ProtoConstants.ConversationType.ConversationType_Private : ProtoConstants.ConversationType.ConversationType_Group).setTarget(getTarget()).setLine(0).build())
.setFromUser("")
.setContent(WFCMessage.MessageContent.newBuilder().setType(1).setSearchableContent(getMessage()).build())
.build();
toSend = message.toByteArray();
toSend = AES.AESEncrypt(toSend, privateSecret);
//wildfire send message use Qos1 and MS topic
topicName = "MS";
synchronized (connLock) {
connection.publish(topicName, toSend, QoS.AT_LEAST_ONCE, false, pubCallback);
connLock.wait();
}
String sendData = "Conversation(" + getConvType() + ":" + getTarget() + "), Message(" + getMessage() + ")";
result.sampleEnd();
result.setSamplerData(sendData);
result.setSentBytes(sendData.length());
result.setLatency(result.getEndTime() - result.getStartTime());
result.setSuccessful(pubCallback.isSuccessful());
if(pubCallback.isSuccessful()) {
result.setResponseData("Publish successfuly.".getBytes());
result.setResponseMessage(MessageFormat.format("publish successfully for Connection {0}.", connection));
result.setResponseCodeOK();
} else {
result.setSuccessful(false);
result.setResponseMessage(MessageFormat.format("Publish failed for connection {0}.", connection));
result.setResponseData(("Publish failed with error code " + pubCallback.getErrorCode()).getBytes());
result.setResponseCode("500");
}
} catch (Exception ex) {
logger.log(Priority.ERROR, ex.getMessage(), ex);
result.sampleEnd();
result.setLatency(result.getEndTime() - result.getStartTime());
result.setSuccessful(false);
result.setResponseMessage(MessageFormat.format("Publish failed for connection {0}.", connection));
result.setResponseData(ex.getMessage().getBytes());
result.setResponseCode("500");
}
return result;
}
@Override
public void threadStarted() {
}
@Override
public void threadFinished() {
if (!isConnectionShare()) {
if (this.connection != null) {
final CountDownLatch cdl = new CountDownLatch(1);
Callback<Void> cb = new Callback<Void>() {
@Override
public void onSuccess(Void value) {
logger.info(MessageFormat.format("The connection {0} disconneted successfully.", connection));
cdl.countDown();
}
@Override
public void onFailure(Throwable value) {
logger.log(Priority.ERROR, value.getMessage(), value);
cdl.countDown();
}
};
logger.info("before disconnection");
this.connection.disconnect(cb);
logger.info("after disconnection");
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (ConnectionsManager.getInstance().containsConnection(connKey)) {
ConnectionsManager.getInstance().removeConnection(connKey);
}
} else {
logger.info("share connection, not disconnect the connection");
}
}
public static String getUUID() {
UUID uuid = UUID.randomUUID();
String str = uuid.toString();
str = str.replace("-", "");
return str;
}
}