├── settings.gradle ├── res ├── step1.png ├── step2.png ├── step3.png ├── step4.png ├── step5.png ├── step6.png ├── step7.png └── network.png ├── .gitignore ├── dist └── TarsJMeter-1.7.1.jar ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ ├── java │ └── com │ │ └── tencent │ │ └── tars │ │ ├── tup │ │ ├── session │ │ │ ├── INetListener.java │ │ │ ├── Session.java │ │ │ ├── UdpSession.java │ │ │ └── TcpSession.java │ │ ├── IPEndPoint.java │ │ ├── ServantInvokeContext.java │ │ ├── TupUtil.java │ │ └── TupClient.java │ │ ├── protocol │ │ ├── exceptions │ │ │ ├── JsonEncodeException.java │ │ │ ├── TarsEncodeException.java │ │ │ ├── JsonDecodeException.java │ │ │ └── TarsDecodeException.java │ │ ├── parse │ │ │ ├── TarsContent.java │ │ │ └── ast │ │ │ │ ├── TarsInclude.java │ │ │ │ ├── TarsMapType.java │ │ │ │ ├── TarsCustomType.java │ │ │ │ ├── TarsVectorType.java │ │ │ │ ├── TarsStruct.java │ │ │ │ ├── TarsInterface.java │ │ │ │ ├── TarsConst.java │ │ │ │ ├── TarsKey.java │ │ │ │ ├── TarsOperation.java │ │ │ │ ├── TarsParam.java │ │ │ │ ├── TarsType.java │ │ │ │ ├── TarsEnum.java │ │ │ │ ├── TarsRoot.java │ │ │ │ ├── TarsStructMember.java │ │ │ │ ├── TarsNamespace.java │ │ │ │ └── TarsPrimitiveType.java │ │ ├── JsonConst.java │ │ ├── TarsStructUtil.java │ │ ├── packet │ │ │ ├── ResponsePacket.java │ │ │ └── RequestPacket.java │ │ ├── tars │ │ │ ├── TarsStructBase.java │ │ │ └── TarsOutputStream.java │ │ └── json │ │ │ ├── JsonOutputStream.java │ │ │ └── JsonStreamUtil.java │ │ ├── jmeter │ │ ├── gui │ │ │ ├── widgets │ │ │ │ ├── MapArgPanel.java │ │ │ │ ├── JTypeComboBox.java │ │ │ │ ├── TarsStructPanel.java │ │ │ │ ├── ExtraArgumentsPanel.java │ │ │ │ ├── ArgumentsPanelBase.java │ │ │ │ └── Tars2JsonDialog.java │ │ │ ├── GeneralTarsSamplerGui.java │ │ │ ├── CustomResUtils.java │ │ │ └── GenralTarsConfigGui.java │ │ ├── utils │ │ │ ├── ArgTriple.java │ │ │ ├── TarsParamArgument.java │ │ │ ├── Triple.java │ │ │ └── TarsParamUtil.java │ │ ├── sampler │ │ │ ├── TarsSamplerProxy.java │ │ │ ├── TarsAbstractImpl.java │ │ │ ├── TarsSampleResult.java │ │ │ └── TarsImpl.java │ │ └── constants │ │ │ └── ITarsConst.java │ │ └── utils │ │ ├── TextUtils.java │ │ ├── HexUtil.java │ │ └── ErrorCode.java │ └── resources │ └── com │ └── tencent │ └── tars │ ├── messages.properties │ └── messages_zh_CN.properties ├── Contributing.md ├── assembly.xml ├── LICENSE ├── gradlew.bat ├── pom.xml ├── gradlew └── README.zh.md /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'TarsJMeter' 2 | 3 | -------------------------------------------------------------------------------- /res/step1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarsCloud/TarsJMeter/HEAD/res/step1.png -------------------------------------------------------------------------------- /res/step2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarsCloud/TarsJMeter/HEAD/res/step2.png -------------------------------------------------------------------------------- /res/step3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarsCloud/TarsJMeter/HEAD/res/step3.png -------------------------------------------------------------------------------- /res/step4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarsCloud/TarsJMeter/HEAD/res/step4.png -------------------------------------------------------------------------------- /res/step5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarsCloud/TarsJMeter/HEAD/res/step5.png -------------------------------------------------------------------------------- /res/step6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarsCloud/TarsJMeter/HEAD/res/step6.png -------------------------------------------------------------------------------- /res/step7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarsCloud/TarsJMeter/HEAD/res/step7.png -------------------------------------------------------------------------------- /res/network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarsCloud/TarsJMeter/HEAD/res/network.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/* 2 | .idea/* 3 | build/* 4 | .git/* 5 | target/* 6 | **/.DS_Store 7 | -------------------------------------------------------------------------------- /dist/TarsJMeter-1.7.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarsCloud/TarsJMeter/HEAD/dist/TarsJMeter-1.7.1.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TarsCloud/TarsJMeter/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/tup/session/INetListener.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.tup.session; 2 | 3 | public interface INetListener { 4 | void sentBytesDispatch(int length, final byte[] sentData); 5 | 6 | void handleData(final byte[] data); 7 | } 8 | -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | If you contributed but cannot find your ID here, please submit PR and add your GitHub ID to both [Tars repo](https://github.com/TarsCloud/Tars/pulls) and [here](https://github.com/TarsCloud/TarsJMeter/pulls). 4 | 5 | ## TarsJMeter 6 | 7 | - boycs007 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jun 08 16:22:55 CST 2020 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/exceptions/JsonEncodeException.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.protocol.exceptions; 2 | 3 | @SuppressWarnings("serial") 4 | public class JsonEncodeException extends RuntimeException { 5 | 6 | public JsonEncodeException(String string) { 7 | super(string); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/exceptions/TarsEncodeException.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.protocol.exceptions; 2 | 3 | @SuppressWarnings("serial") 4 | public class TarsEncodeException extends RuntimeException { 5 | 6 | public TarsEncodeException(String string) { 7 | super(string); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/exceptions/JsonDecodeException.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.protocol.exceptions; 2 | 3 | @SuppressWarnings("serial") 4 | public class JsonDecodeException extends RuntimeException { 5 | 6 | public JsonDecodeException(String string) { 7 | super(string); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/exceptions/TarsDecodeException.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.protocol.exceptions; 2 | 3 | @SuppressWarnings("serial") 4 | public class TarsDecodeException extends RuntimeException { 5 | 6 | public TarsDecodeException(String string) { 7 | super(string); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/gui/widgets/MapArgPanel.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.gui.widgets; 2 | 3 | import org.apache.jmeter.config.Arguments; 4 | 5 | /** 6 | * 用于添加 Tup Tars RequestPacket 中的 map context和 map status 7 | */ 8 | public class MapArgPanel extends ArgumentsPanelBase { 9 | 10 | public MapArgPanel(String label) { 11 | super(label,false); 12 | init(); 13 | clearBorderForMainPanel(); 14 | } 15 | 16 | @Override 17 | protected Arguments getDefaultArguments() { 18 | return new Arguments(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/utils/ArgTriple.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.utils; 2 | 3 | public class ArgTriple extends Triple { 4 | private String ml; 5 | private String mm; 6 | private String mr; 7 | 8 | public ArgTriple(String l, String m, String r) { 9 | ml = l; 10 | mm = m; 11 | mr = r; 12 | } 13 | 14 | @Override 15 | public String getLeft() { 16 | return ml; 17 | } 18 | 19 | @Override 20 | public String getMiddle() { 21 | return mm; 22 | } 23 | 24 | @Override 25 | public String getRight() { 26 | return mr; 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/sampler/TarsSamplerProxy.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.sampler; 2 | 3 | import com.tencent.tars.utils.ErrorCode; 4 | 5 | public class TarsSamplerProxy extends TarsSamplerBase { 6 | private transient TarsAbstractImpl impl; 7 | 8 | public TarsSamplerProxy() { 9 | super(); 10 | } 11 | 12 | @Override 13 | protected TarsSampleResult sample(TarsSampleResult result) { 14 | if (impl == null) { // Not called from multiple threads, so this is OK 15 | try { 16 | impl = new TarsImpl(this); 17 | } catch (Exception ex) { 18 | result.setRetCode(result.getRetCode() + ErrorCode.ErrorProxyException); 19 | errorResult(ex, result); 20 | } 21 | } 22 | return impl.sample(result); 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/TarsContent.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.protocol.parse; 2 | 3 | 4 | import com.tencent.tars.protocol.parse.ast.TarsInclude; 5 | import com.tencent.tars.protocol.parse.ast.TarsNamespace; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class TarsContent { 11 | 12 | private List tarsNamespaces; 13 | 14 | private List tarsIncludes; 15 | 16 | public List getNamespaces() { 17 | return new ArrayList<>(tarsNamespaces); 18 | } 19 | 20 | public void setNamespaces(List tarsNamespaces) { 21 | this.tarsNamespaces = tarsNamespaces; 22 | } 23 | 24 | public List getIncludes() { 25 | return new ArrayList<>(tarsIncludes); 26 | } 27 | 28 | public void setIncludes(List tarsIncludes) { 29 | this.tarsIncludes = tarsIncludes; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/JsonConst.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.protocol; 2 | 3 | public interface JsonConst { 4 | String KEY_TYPE = "type"; 5 | String KEY_MAP_KEY = "key"; 6 | String KEY_VALUE = "value"; 7 | String KEY_TAG = "tag"; 8 | 9 | String VOID = "void"; 10 | String BOOLEAN = "boolean"; 11 | String BYTE = "byte"; 12 | String INT = "int"; 13 | String SHORT = "short"; 14 | String LONG = "long"; 15 | String FLOAT = "float"; 16 | String DOUBLE = "double"; 17 | String STRING = "String"; 18 | 19 | String BOOLEAN_VEC = "boolean[]"; 20 | String BYTE_VEC = "byte[]"; 21 | String INT_VEC = "int[]"; 22 | String SHORT_VEC = "short[]"; 23 | String LONG_VEC = "long[]"; 24 | String FLOAT_VEC = "float[]"; 25 | String DOUBLE_VEC = "double[]"; 26 | String STRING_VEC = "String[]"; 27 | 28 | String MAP = "map"; 29 | String VECTOR = "vector"; 30 | String TARS = "tars"; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | fatjar 7 | 8 | 9 | jar 10 | 11 | 12 | false 13 | 14 | 15 | 16 | ${project.build.directory}/classes 17 | / 18 | 19 | 20 | 21 | 22 | 23 | true 24 | 25 | com.google.code.gson:gson 26 | org.antlr:antlr-runtime 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/utils/TarsParamArgument.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.utils; 2 | 3 | import com.tencent.tars.protocol.JsonConst; 4 | import com.tencent.tars.protocol.json.JsonStreamUtil; 5 | import org.apache.jmeter.config.Argument; 6 | import org.apache.jmeter.testelement.property.StringProperty; 7 | 8 | import java.io.Serializable; 9 | 10 | public class TarsParamArgument extends Argument implements Serializable { 11 | 12 | private static final String TYPE = "TarsParamArgument.type"; 13 | 14 | 15 | public TarsParamArgument(){ 16 | } 17 | 18 | public TarsParamArgument(String name, String value, String type) { 19 | super(name, value); 20 | setMetaData("="); 21 | setType(type); 22 | } 23 | 24 | public void setType(String type) { 25 | if (getType().equals(type)) { 26 | return; 27 | } else if (type.equals(JsonConst.TARS)) { 28 | setValue(""); 29 | } else { 30 | setValue(JsonStreamUtil.toPrettyFormat(TarsParamUtil.getValueByType(type))); 31 | } 32 | setProperty(new StringProperty(TYPE, type)); 33 | } 34 | 35 | public String getType() { 36 | return getPropertyAsString(TYPE, JsonConst.TARS); 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsInclude.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.tree.CommonTree; 20 | 21 | public class TarsInclude extends CommonTree { 22 | 23 | private final String fileName; 24 | 25 | public TarsInclude(int tokenType, String identifier) { 26 | super(new CommonToken(tokenType)); 27 | this.fileName = identifier + ".tars"; 28 | } 29 | 30 | public String fileName() { 31 | return fileName; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/utils/Triple.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.utils; 2 | 3 | import java.io.Serializable; 4 | import java.util.Objects; 5 | 6 | public abstract class Triple implements Serializable { 7 | 8 | 9 | public abstract L getLeft(); 10 | 11 | public abstract M getMiddle(); 12 | 13 | public abstract R getRight(); 14 | 15 | @Override 16 | public boolean equals(final Object obj) { 17 | if (obj == this) { 18 | return true; 19 | } 20 | if (obj instanceof Triple) { 21 | final Triple other = (Triple) obj; 22 | return Objects.equals(getLeft(), other.getLeft()) 23 | && Objects.equals(getMiddle(), other.getMiddle()) 24 | && Objects.equals(getRight(), other.getRight()); 25 | } 26 | return false; 27 | } 28 | 29 | @Override 30 | public int hashCode() { 31 | return (getLeft() == null ? 0 : getLeft().hashCode()) ^ 32 | (getMiddle() == null ? 0 : getMiddle().hashCode()) ^ 33 | (getRight() == null ? 0 : getRight().hashCode()); 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "(" + getLeft() + "," + getMiddle() + "," + getRight() + ")"; 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/gui/widgets/JTypeComboBox.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.gui.widgets; 2 | 3 | import com.tencent.tars.protocol.JsonConst; 4 | 5 | import javax.swing.*; 6 | 7 | public class JTypeComboBox extends JComboBox { 8 | public JTypeComboBox() { 9 | this(false); 10 | } 11 | 12 | public JTypeComboBox(boolean isReturnValue){ 13 | super(); 14 | this.addItem(JsonConst.TARS); 15 | this.addItem(JsonConst.STRING); 16 | this.addItem(JsonConst.INT); 17 | this.addItem(JsonConst.BOOLEAN); 18 | this.addItem(JsonConst.LONG); 19 | this.addItem(JsonConst.SHORT); 20 | this.addItem(JsonConst.DOUBLE); 21 | this.addItem(JsonConst.FLOAT); 22 | this.addItem(JsonConst.BYTE); 23 | this.addItem(JsonConst.VOID); 24 | this.addItem(JsonConst.STRING_VEC); 25 | this.addItem(JsonConst.INT_VEC); 26 | this.addItem(JsonConst.BOOLEAN_VEC); 27 | this.addItem(JsonConst.LONG_VEC); 28 | this.addItem(JsonConst.SHORT_VEC); 29 | this.addItem(JsonConst.DOUBLE_VEC); 30 | this.addItem(JsonConst.FLOAT_VEC); 31 | this.addItem(JsonConst.BYTE_VEC); 32 | this.addItem(JsonConst.MAP); 33 | if(isReturnValue){ 34 | this.setSelectedItem(JsonConst.INT); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/utils/TextUtils.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.utils; 2 | 3 | public class TextUtils { 4 | public static boolean isEmpty(String text) { 5 | if (text != null) { 6 | return text.isEmpty(); 7 | } 8 | return true; 9 | } 10 | 11 | public static String byteArrayToHexStr(byte[] byteArray) { 12 | if (byteArray == null){ 13 | return null; 14 | } 15 | char[] hexArray = "0123456789abcdef".toCharArray(); 16 | char[] hexChars = new char[byteArray.length * 2]; 17 | for (int j = 0; j < byteArray.length; j++) { 18 | int v = byteArray[j] & 0xFF; 19 | hexChars[j * 2] = hexArray[v >>> 4]; 20 | hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 21 | } 22 | return new String(hexChars); 23 | } 24 | 25 | public static byte[] hexStrToByteArray(String str) 26 | { 27 | if (str == null) { 28 | return null; 29 | } 30 | if (str.length() == 0) { 31 | return new byte[0]; 32 | } 33 | byte[] byteArray = new byte[str.length() / 2]; 34 | for (int i = 0; i < byteArray.length; i++){ 35 | String subStr = str.substring(2 * i, 2 * i + 2); 36 | byteArray[i] = ((byte)Integer.parseInt(subStr, 16)); 37 | } 38 | return byteArray; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsMapType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.Token; 19 | 20 | public class TarsMapType extends TarsType { 21 | 22 | public TarsMapType(Token token) { 23 | super(token, "map"); 24 | } 25 | 26 | @Override 27 | public boolean isMap() { 28 | return true; 29 | } 30 | 31 | @Override 32 | public TarsMapType asMap() { 33 | return this; 34 | } 35 | 36 | public TarsType keyType() { 37 | return (TarsType) this.getChild(0); 38 | } 39 | 40 | public TarsType valueType() { 41 | return (TarsType) this.getChild(1); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/TarsStructUtil.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.protocol; 2 | 3 | import com.tencent.tars.protocol.tars.TarsInputStream; 4 | import com.tencent.tars.protocol.tars.TarsOutputStream; 5 | import com.tencent.tars.protocol.tars.TarsStructBase; 6 | 7 | public class TarsStructUtil { 8 | private final static String ENCODE_TYPE = "UTF-8"; // 编码 9 | 10 | /** 11 | * 序列化(编码格式:utf-8) 12 | * 13 | * @param base 14 | * @return 15 | */ 16 | public static byte[] tarsStructToUTF8ByteArray(TarsStructBase base) { 17 | TarsOutputStream tos = new TarsOutputStream(); 18 | tos.setServerEncoding(ENCODE_TYPE); 19 | base.writeTo(tos); 20 | return tos.toByteArray(); 21 | } 22 | 23 | /** 24 | * 解析结构 25 | * 26 | * @param data 27 | * @param base 28 | * @return 29 | */ 30 | public static T getTarsStruct(final byte[] data, final T base) { 31 | if (null == base) { 32 | return null; 33 | } 34 | 35 | base.recyle(); 36 | base.readFrom(createUTF8InputStream(data)); 37 | return base; 38 | } 39 | 40 | private static TarsInputStream createUTF8InputStream(byte[] data) { 41 | TarsInputStream tis = new TarsInputStream(data); 42 | tis.setServerEncoding(ENCODE_TYPE); 43 | return tis; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsCustomType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | public class TarsCustomType extends TarsType { 19 | 20 | private final String namespace; 21 | 22 | public TarsCustomType(int tokenType, String typeName) { 23 | super(tokenType, typeName); 24 | this.namespace = null; 25 | } 26 | 27 | public TarsCustomType(int tokenType, String namespace, String typeName) { 28 | super(tokenType, typeName); 29 | this.namespace = namespace; 30 | } 31 | 32 | @Override 33 | public boolean isCustom() { 34 | return true; 35 | } 36 | 37 | @Override 38 | public TarsCustomType asCustom() { 39 | return this; 40 | } 41 | 42 | public String namespace() { 43 | return namespace; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, THE TARS FOUNDATION 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/constants/ITarsConst.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.constants; 2 | 3 | public interface ITarsConst { 4 | 5 | String ARGUMENTS = "TarsSampler.Arguments"; // $NON-NLS-1$ 6 | 7 | String FUNC_ARGUMENTS = "TarsSampler.FuncArguments"; // $NON-NLS-1$ 8 | 9 | String CONTEXT_ARGUMENTS = "TarsSampler.ContextArguments"; // $NON-NLS-1$ 10 | 11 | String STATUS_ARGUMENTS = "TarsSampler.StatusArguments"; // $NON-NLS-1$ 12 | 13 | String SERVANT_IP = "TarsSampler.ip"; 14 | 15 | String SERVANT_PORT = "TarsSampler.port"; 16 | 17 | String SERVANT_PROTOCOL = "TarsSampler.protocol"; 18 | 19 | String SERVANT_PATH = "TarsSampler.servant"; 20 | 21 | String FUNC_NAME = "TarsSampler.funcName"; 22 | 23 | String TARS_RETURN_TYPE = "TarsSampler.returnType"; 24 | 25 | String TARS_RETURN_VALUE = "TarsSampler.returnValue"; 26 | 27 | String RETURN_VALUE_NAME = "returnValue"; 28 | 29 | // http proxy url 30 | String KEY_PROXY_HOST = "proxyHost"; 31 | 32 | String KEY_PROXY_PORT = "proxyPort"; 33 | 34 | // 是否使用长链接 35 | String KEY_KEEP_ALIVE = "isKeepAlive"; 36 | //连接超时值 37 | String KEY_CONNECT_TIMEOUT = "connectTimeout"; 38 | //数据请求超时值 39 | String KEY_READ_TIMEOUT = "readTimeout"; 40 | //成功框架标记 41 | String KEY_RET_CODE = "successRetCode"; 42 | 43 | String KEY_REQ_VERSION = "Tup.iVersion"; 44 | String KEY_REQ_PKT_TYPE = "Tup.cPacketType"; 45 | String KEY_REQ_MSG_TYPE = "Tup.iMessageType"; 46 | String KEY_REQ_I_TIMEOUT = "Tup.iTimeout"; 47 | 48 | String TCP = "TCP"; 49 | String UDP = "UDP"; 50 | } 51 | -------------------------------------------------------------------------------- /src/main/resources/com/tencent/tars/messages.properties: -------------------------------------------------------------------------------- 1 | tars.title.general=General Tars Request 2 | 3 | # tars header panel 4 | tars.header.title=Target Function Config 5 | tars.addressing.ip=Servant IP 6 | tars.addressing.port=Servant Port 7 | tars.addressing.protocol=Protocol 8 | tars.servant.path=Servant Path 9 | tars.func.name=Function Name 10 | tars.retval.type=Return value 11 | tars.retval.content=Return Value JSON Template 12 | 13 | # tars func parameter panel 14 | tars.request.parameter=Function Parameter List 15 | 16 | # tars extra parameter panel 17 | tars.param.extra.title=Tars Extra Parameter 18 | tars.param.extra.keep.alive=if use keep alive connection. 19 | tars.param.extra.proxy.ip=if you need proxy to connect target, host here 20 | tars.param.extra.proxy.port=proxy port here 21 | tars.param.extra.tcp.connect.timeout=Tcp Connect Timeout 22 | tars.param.extra.tcp.read.timeout=Tcp Read Timeout 23 | tars.param.extra.tup.version=RequestPacket.iVersion 24 | tars.param.extra.tup.packettype=RequestPacket.cPacketType 25 | tars.param.extra.tup.messagetype=RequestPacket.iMessageType 26 | tars.param.extra.tup.timeout=RequestPacket.iTimeout 27 | tars.param.extra.retcode=expected ResponsePacket.iRet value. (split by ; ) 28 | 29 | # tars tup request packet context 30 | tars.tup.req.context=RequestPacket.ContextMap 31 | 32 | # tars tup request packet status 33 | tars.tup.req.status=RequestPacket.StatusMap 34 | 35 | # tars2json panel 36 | tars.tars2json.browse=Browse... 37 | tars.tars2json.struct.name=tars struct name: 38 | tars.tars2json.path=tars file path: 39 | tars.tars2json.translate=tars2json 40 | 41 | # right key on table 42 | tars.mouse.transform.into.variable=Replace values with variables 43 | tars.mouse.detail.edit=detail 44 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsVectorType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.Token; 19 | import org.antlr.runtime.tree.Tree; 20 | 21 | public class TarsVectorType extends TarsType { 22 | 23 | private TarsType subType; 24 | 25 | public TarsVectorType(Token token) { 26 | super(token, "vector"); 27 | } 28 | 29 | @Override 30 | public boolean isVector() { 31 | return true; 32 | } 33 | 34 | @Override 35 | public TarsVectorType asVector() { 36 | return this; 37 | } 38 | 39 | @Override 40 | public void addChild(Tree child) { 41 | super.addChild(child); 42 | if (child instanceof TarsType) { 43 | subType = (TarsType) child; 44 | } 45 | } 46 | 47 | public TarsType subType() { 48 | return subType; 49 | } 50 | 51 | public boolean isByteArray() { 52 | return subType.isPrimitive() && subType.asPrimitive().primitiveType() == TarsPrimitiveType.PrimitiveType.BYTE; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsStruct.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.tree.CommonTree; 20 | import org.antlr.runtime.tree.Tree; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | public class TarsStruct extends CommonTree { 26 | 27 | private final String structName; 28 | private final List memberList = new ArrayList(); 29 | 30 | public TarsStruct(int tokenType, String structName) { 31 | super(new CommonToken(tokenType)); 32 | this.structName = structName; 33 | } 34 | 35 | @Override 36 | public void addChild(Tree child) { 37 | super.addChild(child); 38 | if (child instanceof TarsStructMember) { 39 | memberList.add((TarsStructMember) child); 40 | } 41 | } 42 | 43 | public String structName() { 44 | return structName; 45 | } 46 | 47 | public List memberList() { 48 | return memberList; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsInterface.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.tree.CommonTree; 20 | import org.antlr.runtime.tree.Tree; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | public class TarsInterface extends CommonTree { 26 | 27 | private final String interfaceName; 28 | private final List operationList = new ArrayList(); 29 | 30 | public TarsInterface(int tokenType, String interfaceName) { 31 | super(new CommonToken(tokenType)); 32 | this.interfaceName = interfaceName; 33 | } 34 | 35 | @Override 36 | public void addChild(Tree child) { 37 | super.addChild(child); 38 | 39 | if (child instanceof TarsOperation) { 40 | operationList.add((TarsOperation) child); 41 | } 42 | } 43 | 44 | public String interfaceName() { 45 | return interfaceName; 46 | } 47 | 48 | public List operationList() { 49 | return operationList; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsConst.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.tree.CommonTree; 20 | import org.antlr.runtime.tree.Tree; 21 | 22 | public class TarsConst extends CommonTree { 23 | 24 | private final String constName; 25 | private final String constValue; 26 | 27 | private TarsPrimitiveType constType; 28 | 29 | public TarsConst(int tokenType, String constName, String constValue) { 30 | super(new CommonToken(tokenType)); 31 | this.constName = constName; 32 | this.constValue = constValue; 33 | } 34 | 35 | @Override 36 | public void addChild(Tree child) { 37 | super.addChild(child); 38 | if (child instanceof TarsPrimitiveType) { 39 | constType = (TarsPrimitiveType) child; 40 | } 41 | } 42 | 43 | public TarsPrimitiveType constType() { 44 | return constType; 45 | } 46 | 47 | public String constName() { 48 | return constName; 49 | } 50 | 51 | public String constValue() { 52 | return constValue; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/sampler/TarsAbstractImpl.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.sampler; 2 | 3 | import org.apache.jmeter.samplers.Interruptible; 4 | import org.apache.jmeter.samplers.SampleResult; 5 | 6 | import java.net.InetSocketAddress; 7 | import java.net.Proxy; 8 | 9 | public abstract class TarsAbstractImpl implements Interruptible { 10 | 11 | protected final TarsSamplerBase testElement; 12 | 13 | protected int errCode = 0; 14 | protected String errorMessage = ""; 15 | protected Throwable localThrowable = null; 16 | protected String threadName = Thread.currentThread().getName(); 17 | 18 | protected TarsAbstractImpl(TarsSamplerBase testElement) { 19 | this.testElement = testElement; 20 | } 21 | 22 | public abstract TarsSampleResult sample(TarsSampleResult result); 23 | 24 | protected void errorResult(Throwable t, TarsSampleResult res) { 25 | testElement.errorResult(t, res); 26 | } 27 | 28 | protected Proxy getProxy() { 29 | if (testElement.getProxyHost().isEmpty() || testElement.getProxyPort() <= 0) { 30 | return null; 31 | } 32 | return new Proxy(Proxy.Type.HTTP, 33 | new InetSocketAddress(testElement.getProxyHost(), testElement.getProxyPort())); 34 | } 35 | 36 | protected void updateResult(TarsSampleResult result, String resultData) { 37 | result.setRetCode(errCode); 38 | result.setErrorMessage(this.errorMessage); 39 | if (testElement.getSuccessfulStatus(result)) { 40 | testElement.successResult(result, resultData); 41 | } else { 42 | errorResult(this.localThrowable, result); 43 | } 44 | this.reset(); 45 | } 46 | 47 | public void reset(){ 48 | this.localThrowable = null; 49 | this.errCode = 0; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsKey.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.tree.CommonTree; 20 | import org.antlr.runtime.tree.Tree; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | import static com.tencent.tars.protocol.parse.TarsLexer.*; 26 | 27 | public class TarsKey extends CommonTree { 28 | 29 | private final String structName; 30 | private final List keyList = new ArrayList(); 31 | 32 | public TarsKey(int tokenType, String structName) { 33 | super(new CommonToken(tokenType)); 34 | this.structName = structName; 35 | } 36 | 37 | @Override 38 | public void addChild(Tree child) { 39 | super.addChild(child); 40 | if (child.getType() == TARS_IDENTIFIER) { 41 | keyList.add(child.getText()); 42 | } 43 | } 44 | 45 | public String structName() { 46 | return structName; 47 | } 48 | 49 | public List keyList() { 50 | return keyList; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/tup/IPEndPoint.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.tup; 2 | 3 | public class IPEndPoint implements Cloneable { 4 | private int mPort; 5 | private String mIp; 6 | 7 | @Override 8 | protected IPEndPoint clone() throws CloneNotSupportedException { 9 | super.clone(); 10 | return new IPEndPoint(mIp, mPort); 11 | } 12 | 13 | public IPEndPoint(String ip, int port) { 14 | mIp = ip; 15 | mPort = port; 16 | } 17 | 18 | public void setPort(int port) { 19 | mPort = port; 20 | } 21 | 22 | public int getPort() { 23 | return mPort; 24 | } 25 | 26 | public void setIp(long ip) { 27 | String[] temp = new String[4]; 28 | temp[0] = Integer.valueOf((int) ((ip) & 0xff)).toString(); 29 | temp[1] = Integer.valueOf((int) ((ip >> 8) & 0xff)).toString(); 30 | temp[2] = Integer.valueOf((int) ((ip >> 16) & 0xff)).toString(); 31 | temp[3] = Integer.valueOf((int) ((ip >> 24) & 0xff)).toString(); 32 | mIp = temp[0] + "." + temp[1] + "." + temp[2] + "." + temp[3]; 33 | } 34 | 35 | public void setIp(String ip) { 36 | mIp = ip; 37 | } 38 | 39 | public String getIp() { 40 | return mIp; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | if (mPort >= 0) { 46 | return mIp + ":" + mPort; 47 | } else { 48 | return mIp; 49 | } 50 | } 51 | 52 | @Override 53 | public boolean equals(Object o) { 54 | if (o == null) { 55 | return false; 56 | } 57 | if (!(o instanceof IPEndPoint)) { 58 | return false; 59 | } 60 | IPEndPoint ip = (IPEndPoint) o; 61 | return ip.mIp.equals(mIp) && ip.mPort == mPort; 62 | } 63 | 64 | @Override 65 | public int hashCode() { 66 | return super.hashCode(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsOperation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.tree.CommonTree; 20 | import org.antlr.runtime.tree.Tree; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | public class TarsOperation extends CommonTree { 26 | 27 | private TarsType retType; 28 | private final String oprationName; 29 | private final List paramList = new ArrayList(); 30 | 31 | public TarsOperation(int tokenType, String oprationName) { 32 | super(new CommonToken(tokenType)); 33 | this.oprationName = oprationName; 34 | } 35 | 36 | @Override 37 | public void addChild(Tree child) { 38 | super.addChild(child); 39 | 40 | if (child instanceof TarsType) { 41 | retType = (TarsType) child; 42 | } else if (child instanceof TarsParam) { 43 | paramList.add((TarsParam) child); 44 | } 45 | } 46 | 47 | public TarsType retType() { 48 | return retType; 49 | } 50 | 51 | public String oprationName() { 52 | return oprationName; 53 | } 54 | 55 | public List paramList() { 56 | return paramList; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/resources/com/tencent/tars/messages_zh_CN.properties: -------------------------------------------------------------------------------- 1 | tars.title.general=\u901a\u7528Tars\u8bf7\u6c42 2 | 3 | # tars header panel 4 | tars.header.title=Tars\u5168\u5c40\u914d\u7f6e 5 | tars.addressing.ip=\u670d\u52a1\u5730\u5740 6 | tars.addressing.port=\u670d\u52a1\u7aef\u53e3 7 | tars.addressing.protocol=\u534f\u0020\u8bae 8 | tars.servant.path=\u670d\u52a1\u8def\u5f84 9 | tars.func.name=\u65b9\u6cd5\u540d\u79f0 10 | tars.retval.type=\u8fd4\u56de\u503c 11 | tars.retval.content=\u8fd4\u56de\u503cJSON\u6a21\u677f 12 | 13 | # tars func parameter panel 14 | tars.request.parameter=\u65b9\u6cd5\u53c2\u6570\u5217\u8868 15 | 16 | # tars extra parameter panel 17 | tars.param.extra.title=Tars\u6269\u5c55\u53c2\u6570 18 | tars.param.extra.keep.alive=\u662f\u5426\u4f7f\u7528\u957f\u94fe\u63a5 19 | tars.param.extra.proxy.ip=\u4ee3\u7406\u0048\u006f\u0073\u0074\u8bbe\u7f6e 20 | tars.param.extra.proxy.port=\u4ee3\u7406\u7aef\u53e3\u8bbe\u7f6e 21 | tars.param.extra.tcp.connect.timeout=Tcp\u8fde\u63a5\u8d85\u65f6\u503c 22 | tars.param.extra.tcp.read.timeout=Tcp\u63a5\u6536\u8d85\u65f6\u503c 23 | tars.param.extra.tup.version=RequestPacket.iVersion 24 | tars.param.extra.tup.packettype=RequestPacket.cPacketType 25 | tars.param.extra.tup.messagetype=RequestPacket.iMessageType 26 | tars.param.extra.tup.timeout=RequestPacket.iTimeout 27 | tars.param.extra.retcode=\u671f\u671b\u7684ResponsePacket.iRet,\u9ed8\u8ba4\u4e3a0 28 | 29 | # tars tup request packet context 30 | tars.tup.req.context=\u8bf7\u6c42\u4e0a\u4e0b\u6587 31 | 32 | # tars tup request packet status 33 | tars.tup.req.status=\u8bf7\u6c42\u72b6\u6001 34 | 35 | # tars2json panel 36 | tars.tars2json.browse=\u6d4f\u89c8... 37 | tars.tars2json.struct.name=\u76ee\u6807Tars\u7ed3\u6784\u540d\u79f0: 38 | tars.tars2json.path=\u76ee\u6807Tars\u6240\u5728\u8def\u5f84: 39 | tars.tars2json.translate=tars2json 40 | 41 | # right key on table 42 | tars.mouse.transform.into.variable=\u4f7f\u7528\u53ef\u53d8\u53c2\u6570 43 | tars.mouse.detail.edit=\u8be6\u7ec6 -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsParam.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.Token; 20 | import org.antlr.runtime.tree.CommonTree; 21 | import org.antlr.runtime.tree.Tree; 22 | 23 | public class TarsParam extends CommonTree { 24 | 25 | private final boolean isOut; 26 | private final boolean isRouteKey; 27 | private TarsType paramType; 28 | private final String paramName; 29 | 30 | public TarsParam(int tokenType, String paramName, Token isOut, Token isRouteKey) { 31 | super(new CommonToken(tokenType)); 32 | this.isOut = isOut != null; 33 | this.isRouteKey = isRouteKey != null; 34 | this.paramName = paramName; 35 | } 36 | 37 | @Override 38 | public void addChild(Tree child) { 39 | super.addChild(child); 40 | 41 | if (child instanceof TarsType) { 42 | paramType = (TarsType) child; 43 | } 44 | } 45 | 46 | public String paramName() { 47 | return paramName; 48 | } 49 | 50 | public TarsType paramType() { 51 | return paramType; 52 | } 53 | 54 | public boolean isOut() { 55 | return isOut; 56 | } 57 | 58 | public boolean isRouteKey() { 59 | return isRouteKey; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/utils/TarsParamUtil.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.utils; 2 | 3 | import com.google.gson.JsonObject; 4 | import com.tencent.tars.protocol.JsonConst; 5 | 6 | import static com.tencent.tars.protocol.json.JsonStreamUtil.*; 7 | 8 | public class TarsParamUtil { 9 | 10 | public static JsonObject getValueByType(String type) { 11 | switch (type) { 12 | case JsonConst.BOOLEAN: 13 | return getBoolValue(false); 14 | case JsonConst.BYTE: 15 | return getByteValue((byte) 0); 16 | case JsonConst.DOUBLE: 17 | return getDoubleValue(0.0); 18 | case JsonConst.FLOAT: 19 | return getFloatValue(0.0f); 20 | case JsonConst.SHORT: 21 | return getShortValue((short) 0); 22 | case JsonConst.STRING: 23 | return getStringValue(""); 24 | case JsonConst.INT: 25 | return getIntValue(0); 26 | case JsonConst.LONG: 27 | return getLongValue(0); 28 | case JsonConst.BOOLEAN_VEC: 29 | return getBoolVectorValue(new boolean[]{false}); 30 | case JsonConst.BYTE_VEC: 31 | return getByteVectorValue(new byte[]{(byte) 0}); 32 | case JsonConst.DOUBLE_VEC: 33 | return getDoubleVectorValue(new double[]{0}); 34 | case JsonConst.FLOAT_VEC: 35 | return getFloatVectorValue(new float[]{0}); 36 | case JsonConst.SHORT_VEC: 37 | return getShortVectorValue(new short[]{0}); 38 | case JsonConst.STRING_VEC: 39 | return getStringVectorValue(new String[]{""}); 40 | case JsonConst.INT_VEC: 41 | return getIntVectorValue(new int[]{0}); 42 | case JsonConst.LONG_VEC: 43 | return getLongVectorValue(new long[]{0}); 44 | } 45 | return null; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.Token; 20 | import org.antlr.runtime.tree.CommonTree; 21 | 22 | public abstract class TarsType extends CommonTree { 23 | 24 | private final String typeName; 25 | 26 | public TarsType(int tokenType, String typeName) { 27 | super(new CommonToken(tokenType)); 28 | this.typeName = typeName; 29 | } 30 | 31 | public TarsType(Token token, String typeName) { 32 | super(token); 33 | this.typeName = typeName; 34 | } 35 | 36 | public String typeName() { 37 | return typeName; 38 | } 39 | 40 | public boolean isPrimitive() { 41 | return false; 42 | } 43 | 44 | public boolean isVector() { 45 | return false; 46 | } 47 | 48 | public boolean isMap() { 49 | return false; 50 | } 51 | 52 | public boolean isCustom() { 53 | return false; 54 | } 55 | 56 | public TarsPrimitiveType asPrimitive() { 57 | return null; 58 | } 59 | 60 | public TarsVectorType asVector() { 61 | return null; 62 | } 63 | 64 | public TarsMapType asMap() { 65 | return null; 66 | } 67 | 68 | public TarsCustomType asCustom() { 69 | return null; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/tup/session/Session.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.tup.session; 2 | 3 | import com.tencent.tars.tup.ServantInvokeContext; 4 | 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | 8 | public abstract class Session { 9 | 10 | protected INetListener mNetListener; 11 | 12 | protected int connectTimeout = 8 * 1000; 13 | 14 | protected int readTimeout = 8000; 15 | 16 | public void setReadTimeout(int timeout) { 17 | this.readTimeout = timeout; 18 | } 19 | 20 | public void setConnectTimeout(int timeout) { 21 | this.connectTimeout = timeout; 22 | } 23 | 24 | public abstract int start(boolean restart); 25 | 26 | public abstract int sendData(byte[] data); 27 | 28 | public abstract int stop(); 29 | 30 | 31 | public void setNetworkListener(INetListener networkListener) { 32 | mNetListener = networkListener; 33 | } 34 | 35 | public void removeListener() { 36 | mNetListener = null; 37 | } 38 | 39 | protected void handleData(final byte[] data) { 40 | //log.debug("[network]handleData(),rspData.length " + data.length + " at " + Thread.currentThread().getName()); 41 | if (null != mNetListener) { 42 | mNetListener.handleData(data); 43 | } 44 | } 45 | 46 | /** 47 | * 取出bytes数据 48 | */ 49 | protected static byte[] getBytesFromIS(InputStream is, int start, int len) throws IOException { 50 | int pos = start; 51 | byte[] buffer = new byte[len]; 52 | int actualSize = 0; 53 | int tempLen = len; 54 | while (actualSize < len && tempLen > 0) { 55 | int rcvSize = is.read(buffer, pos, tempLen); 56 | if (rcvSize < 0) { 57 | break; 58 | } 59 | actualSize += rcvSize; 60 | pos += rcvSize; 61 | tempLen -= rcvSize; 62 | } 63 | if (actualSize != len) { 64 | return null; 65 | } 66 | return buffer; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/gui/GeneralTarsSamplerGui.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.gui; 2 | 3 | import com.tencent.tars.jmeter.sampler.TarsSamplerProxy; 4 | import org.apache.jmeter.gui.GUIMenuSortOrder; 5 | import org.apache.jmeter.samplers.gui.AbstractSamplerGui; 6 | import org.apache.jmeter.testelement.TestElement; 7 | 8 | import javax.swing.*; 9 | import java.awt.*; 10 | 11 | /** 12 | * @author brookechen 13 | */ 14 | @GUIMenuSortOrder(1) 15 | public class GeneralTarsSamplerGui extends AbstractSamplerGui { 16 | 17 | private GenralTarsConfigGui tarsConfigGui; 18 | 19 | public GeneralTarsSamplerGui() { 20 | super(); 21 | init(); 22 | } 23 | 24 | private void init() { 25 | setLayout(new BorderLayout(0, 5)); 26 | setBorder(makeBorder()); 27 | tarsConfigGui = new GenralTarsConfigGui(); 28 | JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, makeTitlePanel(), tarsConfigGui); 29 | splitPane.setBorder(BorderFactory.createEmptyBorder()); 30 | splitPane.setOneTouchExpandable(true); 31 | add(splitPane); 32 | } 33 | 34 | 35 | @Override 36 | public String getLabelResource() { 37 | return null; 38 | } 39 | 40 | @Override 41 | public String getStaticLabel() { 42 | return CustomResUtils.getResString("tars.title.general"); 43 | } 44 | 45 | @Override 46 | public TestElement createTestElement() { 47 | TarsSamplerProxy sampler = new TarsSamplerProxy(); 48 | modifyTestElement(sampler); 49 | return sampler; 50 | } 51 | 52 | @Override 53 | public void modifyTestElement(TestElement sampler) { 54 | sampler.clear(); 55 | tarsConfigGui.modifyTestElement(sampler); 56 | super.configureTestElement(sampler); 57 | } 58 | 59 | /** 60 | * {@inheritDoc} 61 | */ 62 | @Override 63 | public void configure(TestElement element) { 64 | super.configure(element); 65 | tarsConfigGui.configure(element); 66 | } 67 | 68 | @Override 69 | public void clearGui() { 70 | super.clearGui(); 71 | tarsConfigGui.clear(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.tree.CommonTree; 20 | import org.antlr.runtime.tree.Tree; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | import static com.tencent.tars.protocol.parse.TarsLexer.*; 26 | 27 | public class TarsEnum extends CommonTree { 28 | 29 | private final String enumName; 30 | private final List enumMemberList = new ArrayList(); 31 | private final List enumValueList = new ArrayList(); 32 | 33 | public TarsEnum(int tokenType, String enumName) { 34 | super(new CommonToken(tokenType)); 35 | this.enumName = enumName; 36 | } 37 | 38 | @Override 39 | public void addChild(Tree child) { 40 | super.addChild(child); 41 | 42 | if (child.getType() == TARS_IDENTIFIER) { 43 | enumMemberList.add(child.getText()); 44 | } else if (child.getType() == TARS_INTEGER_LITERAL) { 45 | enumValueList.add(child.getText()); 46 | } 47 | } 48 | 49 | public String enumName() { 50 | return enumName; 51 | } 52 | 53 | public List enumMemberList() { 54 | return enumMemberList; 55 | } 56 | 57 | public List enumValueList() { 58 | return enumValueList; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsRoot.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.CommonTokenStream; 20 | import org.antlr.runtime.tree.CommonTree; 21 | import org.antlr.runtime.tree.Tree; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | public class TarsRoot extends CommonTree { 27 | 28 | public TarsRoot(int tokenType) { 29 | super(new CommonToken(tokenType)); 30 | } 31 | 32 | private final List includeList = new ArrayList(); 33 | private final List namespaceList = new ArrayList(); 34 | 35 | @Override 36 | public void addChild(Tree child) { 37 | super.addChild(child); 38 | 39 | if (child instanceof TarsInclude) { 40 | includeList.add((TarsInclude) child); 41 | } else if (child instanceof TarsNamespace) { 42 | namespaceList.add((TarsNamespace) child); 43 | } 44 | } 45 | 46 | public List includeFileList() { 47 | return includeList; 48 | } 49 | 50 | public List namespaceList() { 51 | return namespaceList; 52 | } 53 | 54 | /* 55 | * just for print doc 56 | */ 57 | 58 | private CommonTokenStream tokenStream; 59 | 60 | public CommonTokenStream getTokenStream() { 61 | return tokenStream; 62 | } 63 | 64 | public void setTokenStream(CommonTokenStream tokenStream) { 65 | this.tokenStream = tokenStream; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/gui/CustomResUtils.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.gui; 2 | 3 | import org.apache.jmeter.util.JMeterUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.Locale; 8 | import java.util.MissingResourceException; 9 | import java.util.ResourceBundle; 10 | 11 | /** 12 | * 这里可以继续优化和改进的是,根据 JmeterUtils 来实现多语种支持 13 | * @author brookechen 14 | */ 15 | public class CustomResUtils { 16 | public static final String PROP_BASENAME = 17 | "com.tencent.tars"; //$NON-NLS-1$ 18 | 19 | private static final Logger log = LoggerFactory.getLogger(CustomResUtils.class); 20 | private static final long serialVersionUID = 1L; 21 | private static ResourceBundle resources; 22 | 23 | static { 24 | Locale loc = JMeterUtils.getLocale(); 25 | resources = ResourceBundle.getBundle(PROP_BASENAME + ".messages", loc); 26 | } 27 | 28 | /** 29 | * Gets the resource string for this key. 30 | *

31 | * If the resource is not found, a warning is logged 32 | * 33 | * @param key the key in the resource file 34 | * @return the resource string if the key is found; otherwise, return 35 | * "[res_key="+key+"]" 36 | */ 37 | public static String getResString(String key) { 38 | return getResStringDefault(key, RES_KEY_PFX + key + "]"); //$NON-NLS-1$ 39 | } 40 | 41 | public static final String RES_KEY_PFX = "[res_key="; //$NON-NLS-1$ 42 | 43 | /* 44 | * Helper method to do the actual work of fetching resources; allows 45 | * getResString(S,S) to be deprecated without affecting getResString(S); 46 | */ 47 | private static String getResStringDefault(String key, String defaultValue) { 48 | if (key == null) { 49 | return null; 50 | } 51 | // Resource keys cannot contain spaces 52 | key = key.replace(' ', '_'); // $NON-NLS-1$ // $NON-NLS-2$ 53 | key = key.toLowerCase(Locale.ENGLISH); 54 | String resString = null; 55 | try { 56 | resString = resources.getString(key); 57 | } catch (MissingResourceException mre) { 58 | resString = defaultValue; 59 | } 60 | return resString; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/tup/ServantInvokeContext.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.tup; 2 | 3 | import com.google.gson.JsonObject; 4 | import com.tencent.tars.protocol.JsonConst; 5 | 6 | import java.util.Map; 7 | 8 | public class ServantInvokeContext { 9 | private Object[] arguments; 10 | private Object[] retArguments = null; 11 | private Object retVal; 12 | private JsonObject jsonRetVal; 13 | private Map status; 14 | private long sendBytes; 15 | 16 | 17 | public ServantInvokeContext(JsonObject retVal, JsonObject[] arguments) { 18 | this.arguments = arguments; 19 | this.jsonRetVal = retVal; 20 | } 21 | 22 | public ServantInvokeContext(Object retVal, Object[] arguments) { 23 | this.arguments = arguments; 24 | this.retVal = retVal; 25 | } 26 | 27 | public long getSendBytes() { 28 | return sendBytes; 29 | } 30 | 31 | public void setSendBytes(long sendBytes) { 32 | this.sendBytes = sendBytes; 33 | } 34 | 35 | public void setStatus(Map status) { 36 | this.status = status; 37 | } 38 | 39 | public Map getStatus() { 40 | return status; 41 | } 42 | 43 | public Object[] getArgumentValues() { 44 | return arguments; 45 | } 46 | 47 | public Object getRetValue() { 48 | return retVal; 49 | } 50 | 51 | public void setArguments(Object[] arguments) { 52 | this.arguments = arguments; 53 | } 54 | 55 | public void setRetVal(Object retVal) { 56 | this.retVal = retVal; 57 | } 58 | 59 | public void setJsonRetVal(JsonObject retVal) { 60 | this.jsonRetVal = retVal; 61 | } 62 | 63 | public JsonObject getJsonRetVal() { 64 | if (this.jsonRetVal == null) { 65 | this.jsonRetVal = new JsonObject(); 66 | this.jsonRetVal.addProperty(JsonConst.KEY_TYPE, JsonConst.VOID); 67 | this.jsonRetVal.addProperty(JsonConst.KEY_TAG, 0); 68 | this.jsonRetVal.addProperty(JsonConst.KEY_VALUE, "null"); 69 | } 70 | if (this.jsonRetVal.get(JsonConst.KEY_TAG) == null) { 71 | this.jsonRetVal.addProperty(JsonConst.KEY_TAG, 0); 72 | } 73 | return this.jsonRetVal; 74 | } 75 | 76 | public Object[] getRetArguments() { 77 | return retArguments; 78 | } 79 | 80 | public void setRetArguments(Object[] retArguments) { 81 | this.retArguments = retArguments; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsStructMember.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.Token; 20 | import org.antlr.runtime.tree.CommonTree; 21 | import org.antlr.runtime.tree.Tree; 22 | 23 | import static com.tencent.tars.protocol.parse.TarsParser.*; 24 | 25 | public class TarsStructMember extends CommonTree { 26 | 27 | private final int tag; 28 | private final boolean isRequire; 29 | private final String memberName; 30 | private final String defaultValue; 31 | 32 | private TarsType memberType; 33 | 34 | public TarsStructMember(int tokenType, String tag, Token isRequire, String memberName, String defaultValue) { 35 | super(new CommonToken(tokenType)); 36 | this.tag = Integer.parseInt(tag); 37 | if (isRequire.getType() == TARS_REQUIRE) { 38 | this.isRequire = true; 39 | } else if (isRequire.getType() == TARS_OPTIONAL) { 40 | this.isRequire = false; 41 | } else { 42 | throw new RuntimeException("Error Struct require/optional"); 43 | } 44 | this.memberName = memberName; 45 | this.defaultValue = defaultValue; 46 | } 47 | 48 | @Override 49 | public void addChild(Tree child) { 50 | super.addChild(child); 51 | 52 | if (child instanceof TarsType) { 53 | memberType = (TarsType) child; 54 | } 55 | } 56 | 57 | public int tag() { 58 | return tag; 59 | } 60 | 61 | public boolean isRequire() { 62 | return isRequire; 63 | } 64 | 65 | public TarsType memberType() { 66 | return memberType; 67 | } 68 | 69 | public String memberName() { 70 | return memberName; 71 | } 72 | 73 | public String defaultValue() { 74 | return defaultValue; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/packet/ResponsePacket.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.protocol.packet; 2 | 3 | 4 | import com.tencent.tars.protocol.tars.TarsInputStream; 5 | import com.tencent.tars.protocol.tars.TarsOutputStream; 6 | import com.tencent.tars.protocol.tars.TarsStructBase; 7 | 8 | public class ResponsePacket extends TarsStructBase { 9 | public short iVersion = 0; 10 | public byte cPacketType = 0; 11 | public int iRequestId = 0; 12 | public int iMessageType = 0; 13 | public int iRet = 0; 14 | public byte [] SBuffer = null; 15 | public java.util.Map status = null; 16 | public String sResultDesc = ""; 17 | public java.util.Map context = null; 18 | 19 | public ResponsePacket(){ 20 | } 21 | 22 | public void writeTo(TarsOutputStream _os){ 23 | _os.write(iVersion, 1); 24 | _os.write(cPacketType, 2); 25 | _os.write(iRequestId, 3); 26 | _os.write(iMessageType, 4); 27 | _os.write(iRet, 5); 28 | if (null != SBuffer){ 29 | _os.write(SBuffer, 6); 30 | } 31 | if (null != status){ 32 | _os.write(status, 7); 33 | } 34 | if (null != sResultDesc){ 35 | _os.write(sResultDesc, 8); 36 | } 37 | if (null != context){ 38 | _os.write(context, 9); 39 | } 40 | } 41 | 42 | static byte [] cache_SBuffer; 43 | static java.util.Map cache_status; 44 | static java.util.Map cache_context; 45 | 46 | static { 47 | cache_SBuffer = (byte[]) new byte[1]; 48 | byte __var_6 = 0; 49 | ((byte[])cache_SBuffer)[0] = __var_6; 50 | 51 | cache_status = new java.util.HashMap(); 52 | String __var_7 = ""; 53 | String __var_8 = ""; 54 | cache_status.put(__var_7, __var_8); 55 | 56 | cache_context = new java.util.HashMap(); 57 | String __var_9 = ""; 58 | String __var_10 = ""; 59 | cache_context.put(__var_9, __var_10); 60 | 61 | } 62 | 63 | public void readFrom(TarsInputStream _is){ 64 | this.iVersion = (short) _is.read(iVersion, 1, true); 65 | this.cPacketType = (byte) _is.read(cPacketType, 2, true); 66 | this.iRequestId = (int) _is.read(iRequestId, 3, true); 67 | this.iMessageType = (int) _is.read(iMessageType, 4, true); 68 | this.iRet = (int) _is.read(iRet, 5, true); 69 | this.SBuffer = (byte []) _is.read(cache_SBuffer, 6, false); 70 | this.status = (java.util.Map) _is.read(cache_status, 7, false); 71 | this.sResultDesc = _is.readString(8, false); 72 | this.context = (java.util.Map) _is.read(cache_context, 9, false); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsNamespace.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.tree.CommonTree; 20 | import org.antlr.runtime.tree.Tree; 21 | 22 | import java.util.ArrayList; 23 | import java.util.HashMap; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | public class TarsNamespace extends CommonTree { 28 | 29 | private final String namespace; 30 | private final List structList = new ArrayList(); 31 | private final List interfaceList = new ArrayList(); 32 | private final List enumList = new ArrayList(); 33 | private final List constList = new ArrayList(); 34 | private final Map keyMap = new HashMap(); 35 | 36 | public TarsNamespace(int tokenType, String identifier) { 37 | super(new CommonToken(tokenType)); 38 | this.namespace = identifier; 39 | } 40 | 41 | public String namespace() { 42 | return namespace; 43 | } 44 | 45 | @Override 46 | public void addChild(Tree child) { 47 | super.addChild(child); 48 | 49 | if (child instanceof TarsStruct) { 50 | structList.add((TarsStruct) child); 51 | } else if (child instanceof TarsInterface) { 52 | interfaceList.add((TarsInterface) child); 53 | } else if (child instanceof TarsEnum) { 54 | enumList.add((TarsEnum) child); 55 | } else if (child instanceof TarsConst) { 56 | constList.add((TarsConst) child); 57 | } else if (child instanceof TarsKey) { 58 | TarsKey jk = (TarsKey) child; 59 | keyMap.put(jk.structName(), jk); 60 | } 61 | } 62 | 63 | public List structList() { 64 | return structList; 65 | } 66 | 67 | public List interfaceList() { 68 | return interfaceList; 69 | } 70 | 71 | public List enumList() { 72 | return enumList; 73 | } 74 | 75 | public List constList() { 76 | return constList; 77 | } 78 | 79 | public Map keyMap() { 80 | return keyMap; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/utils/HexUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | 17 | package com.tencent.tars.utils; 18 | 19 | public class HexUtil { 20 | 21 | private static final char[] digits = new char[] { '0', '1', '2', '3', '4',// 22 | '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 23 | 24 | public static final byte[] emptybytes = new byte[0]; 25 | 26 | public static String byte2HexStr(byte b) { 27 | char[] buf = new char[2]; 28 | buf[1] = digits[b & 0xF]; 29 | b = (byte) (b >>> 4); 30 | buf[0] = digits[b & 0xF]; 31 | return new String(buf); 32 | } 33 | 34 | public static String bytes2HexStr(byte[] bytes) { 35 | if (bytes == null || bytes.length == 0) { 36 | return null; 37 | } 38 | 39 | char[] buf = new char[2 * bytes.length]; 40 | for (int i = 0; i < bytes.length; i++) { 41 | byte b = bytes[i]; 42 | buf[2 * i + 1] = digits[b & 0xF]; 43 | b = (byte) (b >>> 4); 44 | buf[2 * i + 0] = digits[b & 0xF]; 45 | } 46 | return new String(buf); 47 | } 48 | 49 | public static byte hexStr2Byte(String str) { 50 | if (str != null && str.length() == 1) { 51 | return char2Byte(str.charAt(0)); 52 | } else { 53 | return 0; 54 | } 55 | } 56 | 57 | public static byte char2Byte(char ch) { 58 | if (ch >= '0' && ch <= '9') { 59 | return (byte) (ch - '0'); 60 | } else if (ch >= 'a' && ch <= 'f') { 61 | return (byte) (ch - 'a' + 10); 62 | } else if (ch >= 'A' && ch <= 'F') { 63 | return (byte) (ch - 'A' + 10); 64 | } else { 65 | return 0; 66 | } 67 | } 68 | 69 | public static byte[] hexStr2Bytes(String str) { 70 | if (str == null || str.equals("")) { 71 | return emptybytes; 72 | } 73 | 74 | byte[] bytes = new byte[str.length() / 2]; 75 | for (int i = 0; i < bytes.length; i++) { 76 | char high = str.charAt(i * 2); 77 | char low = str.charAt(i * 2 + 1); 78 | bytes[i] = (byte) (char2Byte(high) * 16 + char2Byte(low)); 79 | } 80 | return bytes; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/parse/ast/TarsPrimitiveType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | package com.tencent.tars.protocol.parse.ast; 17 | 18 | import org.antlr.runtime.CommonToken; 19 | import org.antlr.runtime.Token; 20 | 21 | import static com.tencent.tars.protocol.parse.TarsLexer.*; 22 | 23 | public class TarsPrimitiveType extends TarsType { 24 | 25 | public static enum PrimitiveType { 26 | VOID, BOOL, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, STRING 27 | } 28 | 29 | private final PrimitiveType primitiveType; 30 | 31 | public TarsPrimitiveType(Token token) { 32 | super(token, toPrimitiveType(token.getType()).name()); 33 | this.primitiveType = toPrimitiveType(token.getType()); 34 | } 35 | 36 | public TarsPrimitiveType(int type) { 37 | this(new CommonToken(type)); 38 | } 39 | 40 | @Override 41 | public boolean isPrimitive() { 42 | return true; 43 | } 44 | 45 | @Override 46 | public TarsPrimitiveType asPrimitive() { 47 | return this; 48 | } 49 | 50 | public PrimitiveType primitiveType() { 51 | return primitiveType; 52 | } 53 | 54 | public boolean isVoid() { 55 | return primitiveType == PrimitiveType.VOID; 56 | } 57 | 58 | private static PrimitiveType toPrimitiveType(int tokenType) { 59 | PrimitiveType type = null; 60 | switch (tokenType) { 61 | case TARS_VOID: 62 | type = PrimitiveType.VOID; 63 | break; 64 | case TARS_BOOL: 65 | type = PrimitiveType.BOOL; 66 | break; 67 | case TARS_BYTE: 68 | type = PrimitiveType.BYTE; 69 | break; 70 | case TARS_SHORT: 71 | type = PrimitiveType.SHORT; 72 | break; 73 | case TARS_INT: 74 | type = PrimitiveType.INT; 75 | break; 76 | case TARS_LONG: 77 | type = PrimitiveType.LONG; 78 | break; 79 | case TARS_FLOAT: 80 | type = PrimitiveType.FLOAT; 81 | break; 82 | case TARS_DOUBLE: 83 | type = PrimitiveType.DOUBLE; 84 | break; 85 | case TARS_STRING: 86 | type = PrimitiveType.STRING; 87 | break; 88 | } 89 | return type; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/tars/TarsStructBase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | * 4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * https://opensource.org/licenses/BSD-3-Clause 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | 17 | package com.tencent.tars.protocol.tars; 18 | 19 | @SuppressWarnings("serial") 20 | public abstract class TarsStructBase implements java.io.Serializable { 21 | 22 | public static final byte BYTE = 0; 23 | public static final byte SHORT = 1; 24 | public static final byte INT = 2; 25 | public static final byte LONG = 3; 26 | public static final byte FLOAT = 4; 27 | public static final byte DOUBLE = 5; 28 | public static final byte STRING1 = 6; 29 | public static final byte STRING4 = 7; 30 | public static final byte MAP = 8; 31 | public static final byte LIST = 9; 32 | public static final byte STRUCT_BEGIN = 10; 33 | public static final byte STRUCT_END = 11; 34 | public static final byte ZERO_TAG = 12; 35 | public static final byte SIMPLE_LIST = 13; 36 | 37 | public static final int MAX_STRING_LENGTH = 100 * 1024 * 1024; 38 | 39 | public abstract void writeTo(TarsOutputStream os); 40 | 41 | public abstract void readFrom(TarsInputStream is); 42 | 43 | public void display(StringBuilder sb, int level) { 44 | } 45 | 46 | public void displaySimple(StringBuilder sb, int level) { 47 | } 48 | 49 | public TarsStructBase newInit() { 50 | return null; 51 | } 52 | 53 | public void recyle() { 54 | 55 | } 56 | 57 | public boolean containField(String name) { 58 | return false; 59 | } 60 | 61 | public Object getFieldByName(String name) { 62 | return null; 63 | } 64 | 65 | public void setFieldByName(String name, Object value) { 66 | } 67 | 68 | public byte[] toByteArray() { 69 | TarsOutputStream os = new TarsOutputStream(); 70 | writeTo(os); 71 | return os.toByteArray(); 72 | } 73 | 74 | public byte[] toByteArray(String encoding) { 75 | TarsOutputStream os = new TarsOutputStream(); 76 | os.setServerEncoding(encoding); 77 | writeTo(os); 78 | return os.toByteArray(); 79 | } 80 | 81 | public String toString() { 82 | StringBuilder sb = new StringBuilder(); 83 | display(sb, 0); 84 | return sb.toString(); 85 | } 86 | 87 | public static String toDisplaySimpleString(TarsStructBase struct) { 88 | if (struct == null) { 89 | return null; 90 | } 91 | StringBuilder sb = new StringBuilder(); 92 | struct.displaySimple(sb, 0); 93 | return sb.toString(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/sampler/TarsSampleResult.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.sampler; 2 | 3 | import org.apache.jmeter.samplers.SampleResult; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * This is a specialisation of the SampleResult class for the tars protocol. 10 | */ 11 | public class TarsSampleResult extends SampleResult { 12 | 13 | private static final long serialVersionUID = 241L; 14 | 15 | private static final String TYPE_TARS = "Tars"; 16 | 17 | private String requestUrl = ""; 18 | 19 | private String servantId = ""; 20 | 21 | private int retCode = 0; 22 | 23 | private String tarsErrorMessage = ""; 24 | 25 | private String requestBody = ""; 26 | 27 | private Map requestHeaders = new HashMap<>(); 28 | 29 | private Map responseHeaders = new HashMap<>(); 30 | 31 | public TarsSampleResult() { 32 | super(); 33 | } 34 | 35 | public TarsSampleResult(long elapsed) { 36 | super(elapsed, true); 37 | } 38 | 39 | /** 40 | * Construct a 'parent' result for an already-existing result, essentially 41 | * cloning it 42 | * 43 | * @param res existing sample result 44 | */ 45 | public TarsSampleResult(TarsSampleResult res) { 46 | super(res); 47 | this.requestUrl = res.requestUrl; 48 | servantId = res.servantId; 49 | retCode = res.retCode; 50 | tarsErrorMessage = res.tarsErrorMessage; 51 | this.requestBody = res.requestBody; 52 | } 53 | 54 | public String getRequestHeaders() { 55 | this.requestHeaders.put(TYPE_TARS, getRequestUrl()); 56 | StringBuilder builder = new StringBuilder(); 57 | for (String key : this.requestHeaders.keySet()) { 58 | builder.append(key).append("\t: ").append(this.requestHeaders.get(key)).append("\n"); 59 | } 60 | return builder.toString(); 61 | } 62 | 63 | public String getResponseHeaders() { 64 | StringBuilder builder = new StringBuilder(); 65 | for (String key : this.responseHeaders.keySet()) { 66 | builder.append(key).append("\t: ").append(this.responseHeaders.get(key)).append("\n"); 67 | } 68 | return builder.toString(); 69 | 70 | } 71 | 72 | public void addRequestHeader(String key, String value) { 73 | this.requestHeaders.put(key, value); 74 | } 75 | 76 | public void addResponseHeader(String key, String value) { 77 | this.responseHeaders.put(key, value); 78 | } 79 | 80 | public String getErrorMessage() { 81 | return tarsErrorMessage; 82 | } 83 | 84 | public void setErrorMessage(String tarsErrorMessage) { 85 | this.tarsErrorMessage = tarsErrorMessage; 86 | } 87 | 88 | public String getRequestUrl() { 89 | return requestUrl; 90 | } 91 | 92 | public void setRequestUrl(String requestUrl) { 93 | this.requestUrl = requestUrl; 94 | } 95 | 96 | public String getServantId() { 97 | return servantId; 98 | } 99 | 100 | public void setServantId(String servantId) { 101 | this.servantId = servantId; 102 | } 103 | 104 | public int getRetCode() { 105 | return retCode; 106 | } 107 | 108 | public void setRetCode(int retCode) { 109 | this.retCode = retCode; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/gui/widgets/TarsStructPanel.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.gui.widgets; 2 | 3 | import com.tencent.tars.jmeter.gui.CustomResUtils; 4 | import com.tencent.tars.protocol.Tars2JsonMojo; 5 | import org.apache.jmeter.gui.util.JSyntaxTextArea; 6 | import org.apache.jmeter.util.JMeterUtils; 7 | import org.apache.jorphan.gui.JLabeledTextField; 8 | 9 | import javax.swing.*; 10 | import javax.swing.filechooser.FileFilter; 11 | import java.awt.*; 12 | import java.awt.event.ActionEvent; 13 | import java.awt.event.ActionListener; 14 | import java.io.File; 15 | 16 | public class TarsStructPanel extends JPanel implements ActionListener { 17 | 18 | private static final String LOAD = "load"; 19 | 20 | private static final String FILE_CHOOSE = "choose"; 21 | 22 | 23 | // tars名称 24 | private JLabeledTextField tarsStructName; 25 | 26 | // tars文件所在路径 27 | private JLabeledTextField tarsFileDirTV; 28 | 29 | //弹出文件夹选择对话框 30 | private JButton dirChooseButton; 31 | 32 | private JSyntaxTextArea valueTA; 33 | 34 | 35 | public TarsStructPanel(JSyntaxTextArea valueTA) { 36 | super(); 37 | this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 38 | this.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); 39 | this.valueTA = valueTA; 40 | tarsStructName = new JLabeledTextField(CustomResUtils.getResString("tars.tars2json.struct.name"), 5); 41 | tarsFileDirTV = new JLabeledTextField(CustomResUtils.getResString("tars.tars2json.path"), 25); 42 | dirChooseButton = new JButton(CustomResUtils.getResString("tars.tars2json.browse")); 43 | dirChooseButton.setActionCommand(FILE_CHOOSE); 44 | dirChooseButton.addActionListener(this); 45 | JButton loadButton = new JButton(CustomResUtils.getResString("tars.tars2json.translate")); 46 | loadButton.setActionCommand(LOAD); 47 | loadButton.addActionListener(this); 48 | this.add(tarsStructName, BorderLayout.WEST); 49 | this.add(tarsFileDirTV, BorderLayout.CENTER); 50 | this.add(dirChooseButton, BorderLayout.EAST); 51 | this.add(loadButton, BorderLayout.EAST); 52 | } 53 | 54 | @Override 55 | public void actionPerformed(ActionEvent e) { 56 | String action = e.getActionCommand(); 57 | if (action.equals(LOAD)) { 58 | doLoad(); 59 | } else if (action.equals(FILE_CHOOSE)) { 60 | doFileChoose(); 61 | } 62 | } 63 | 64 | private void doFileChoose() { 65 | JFileChooser chooser = new JFileChooser("."); 66 | chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); 67 | chooser.addChoosableFileFilter(new FileFilter() { 68 | @Override 69 | public boolean accept(File f) { 70 | String name = f.getName(); 71 | return f.isDirectory() || name.toLowerCase().endsWith(".tars") || name.toLowerCase().endsWith(".jce"); 72 | } 73 | 74 | @Override 75 | public String getDescription() { 76 | return "*.tars;*.jce;dir include tars or jce"; 77 | } 78 | }); 79 | chooser.setMultiSelectionEnabled(false); 80 | int returnVal = chooser.showOpenDialog(dirChooseButton); 81 | 82 | if (returnVal == JFileChooser.APPROVE_OPTION) { 83 | String filepath = chooser.getSelectedFile().getAbsolutePath(); 84 | tarsFileDirTV.setText(filepath); 85 | } 86 | } 87 | 88 | private void doLoad() { 89 | new Thread(() -> { 90 | String text = Tars2JsonMojo.getJsonStr(tarsStructName.getText(), tarsFileDirTV.getText()); 91 | SwingUtilities.invokeLater(() -> valueTA.setText(text)); 92 | }).start(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.tencent.tars 8 | tars-jmeter 9 | 1.0 10 | 11 | jar 12 | 13 | 14 | 1.8 15 | 1.8 16 | UTF-8 17 | 18 | 3.7.0 19 | 3.0.1 20 | 3.1.0 21 | 22 | 2.8.9 23 | 3.5.2 24 | 5.3 25 | 26 | 27 | 28 | 29 | com.google.code.gson 30 | gson 31 | ${gson.version} 32 | 33 | 34 | 35 | org.antlr 36 | antlr 37 | ${antlr.version} 38 | 39 | 40 | 41 | org.apache.jmeter 42 | ApacheJMeter_core 43 | ${jmter.version} 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-compiler-plugin 52 | ${maven_compiler_plugin_version} 53 | 54 | ${java_source_version} 55 | ${java_target_version} 56 | ${file_encoding} 57 | 58 | 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-jar-plugin 63 | ${maven_jar_plugin_version} 64 | 65 | 66 | 67 | mvn 68 | ${maven.build.timestamp} 69 | 70 | false 71 | 72 | true 73 | lib/ 74 | 75 | 76 | 77 | ${project.basedir}/xml/* 78 | 79 | 80 | 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-assembly-plugin 85 | 86 | 87 | ${project.basedir}/assembly.xml 88 | 89 | 90 | 91 | 92 | make-assemble 93 | package 94 | 95 | single 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/gui/widgets/ExtraArgumentsPanel.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.gui.widgets; 2 | 3 | import com.tencent.tars.jmeter.constants.ITarsConst; 4 | import com.tencent.tars.jmeter.gui.CustomResUtils; 5 | import com.tencent.tars.jmeter.utils.ArgTriple; 6 | import com.tencent.tars.jmeter.utils.Triple; 7 | import org.apache.jmeter.config.Argument; 8 | import org.apache.jmeter.config.Arguments; 9 | import org.apache.jorphan.gui.ObjectTableModel; 10 | import org.apache.jorphan.reflect.Functor; 11 | 12 | import javax.swing.*; 13 | import javax.swing.table.TableColumn; 14 | import java.util.LinkedList; 15 | 16 | public class ExtraArgumentsPanel extends ArgumentsPanelBase { 17 | private static final LinkedList> DEFAULT_ARGS = new LinkedList<>(); 18 | 19 | static { 20 | DEFAULT_ARGS.add(new ArgTriple(ITarsConst.KEY_KEEP_ALIVE, 21 | CustomResUtils.getResString("tars.param.extra.keep.alive"), "true")); 22 | DEFAULT_ARGS.add(new ArgTriple(ITarsConst.KEY_PROXY_HOST, 23 | CustomResUtils.getResString("tars.param.extra.proxy.ip"), "")); 24 | DEFAULT_ARGS.add(new ArgTriple(ITarsConst.KEY_PROXY_PORT, 25 | CustomResUtils.getResString("tars.param.extra.proxy.port"), "")); 26 | DEFAULT_ARGS.add(new ArgTriple(ITarsConst.KEY_CONNECT_TIMEOUT, 27 | CustomResUtils.getResString("tars.param.extra.tcp.connect.timeout"), "8000")); 28 | DEFAULT_ARGS.add(new ArgTriple(ITarsConst.KEY_READ_TIMEOUT, 29 | CustomResUtils.getResString("tars.param.extra.tcp.read.timeout"), "8000")); 30 | DEFAULT_ARGS.add(new ArgTriple(ITarsConst.KEY_REQ_VERSION, 31 | CustomResUtils.getResString("tars.param.extra.tup.version"), "1")); 32 | DEFAULT_ARGS.add(new ArgTriple(ITarsConst.KEY_REQ_PKT_TYPE, 33 | CustomResUtils.getResString("tars.param.extra.tup.packettype"), "0")); 34 | DEFAULT_ARGS.add(new ArgTriple(ITarsConst.KEY_REQ_MSG_TYPE, 35 | CustomResUtils.getResString("tars.param.extra.tup.messagetype"), "0")); 36 | DEFAULT_ARGS.add(new ArgTriple(ITarsConst.KEY_REQ_I_TIMEOUT, 37 | CustomResUtils.getResString("tars.param.extra.tup.timeout"), "0")); 38 | DEFAULT_ARGS.add(new ArgTriple(ITarsConst.KEY_RET_CODE, 39 | CustomResUtils.getResString("tars.param.extra.retcode"), "0")); 40 | } 41 | 42 | protected Arguments getDefaultArguments() { 43 | Arguments newArgs = new Arguments(); 44 | for (Triple triple : DEFAULT_ARGS) { 45 | newArgs.addArgument(triple.getLeft(), triple.getRight(), null, triple.getMiddle()); 46 | } 47 | return newArgs; 48 | } 49 | 50 | public ExtraArgumentsPanel() { 51 | super(CustomResUtils.getResString("tars.param.extra.title")); //$NON-NLS-1$ 52 | init(); 53 | clearBorderForMainPanel(); 54 | } 55 | 56 | @Override 57 | protected void initializeTableModel() { 58 | if (tableModel == null) { 59 | tableModel = new ObjectTableModel(new String[]{COLUMN_RESOURCE_NAMES_0, COLUMN_RESOURCE_NAMES_1, COLUMN_RESOURCE_NAMES_2}, 60 | Argument.class, 61 | new Functor[]{ 62 | new Functor("getName"), // $NON-NLS-1$ 63 | new Functor("getValue"), // $NON-NLS-1$ 64 | new Functor("getDescription")}, // $NON-NLS-1$ 65 | new Functor[]{ 66 | new Functor("setName"), // $NON-NLS-1$ 67 | new Functor("setValue"), // $NON-NLS-1$ 68 | new Functor("setDescription")}, // $NON-NLS-1$ 69 | new Class[]{String.class, String.class, String.class}); 70 | } 71 | } 72 | 73 | @Override 74 | protected void sizeColumns(JTable _table) { 75 | super.sizeColumns(_table); 76 | TableColumn firstColumn = _table.getColumnModel().getColumn(0); 77 | TableColumn middleColumn = _table.getColumnModel().getColumn(1); 78 | TableColumn lastColumn = _table.getColumnModel().getColumn(2); 79 | firstColumn.setPreferredWidth(150); 80 | firstColumn.setMinWidth(150); 81 | firstColumn.setMaxWidth(150); 82 | middleColumn.setPreferredWidth(250); 83 | lastColumn.setPreferredWidth(250); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/tup/TupUtil.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.tup; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonObject; 5 | import com.tencent.tars.protocol.JsonConst; 6 | import com.tencent.tars.protocol.json.JsonInputStream; 7 | import com.tencent.tars.protocol.json.JsonOutputStream; 8 | import com.tencent.tars.protocol.exceptions.JsonEncodeException; 9 | import com.tencent.tars.protocol.tars.TarsInputStream; 10 | import com.tencent.tars.protocol.tars.TarsOutputStream; 11 | 12 | import java.nio.ByteBuffer; 13 | 14 | 15 | public class TupUtil { 16 | 17 | private static boolean isTarsStruct(JsonObject jsonObject) { 18 | try { 19 | jsonObjectToTarsStream(jsonObject); 20 | return true; 21 | } catch (JsonEncodeException e) { 22 | return false; 23 | } 24 | } 25 | 26 | private static JsonObject generateFullJsonObject(Object[] objs) { 27 | JsonObject rootObj = new JsonObject(); 28 | int tag = 1; 29 | for (Object obj : objs) { 30 | JsonObject jo = (JsonObject) obj; 31 | if (isTarsStruct(jo)) { 32 | JsonObject wapper = new JsonObject(); 33 | wapper.addProperty(JsonConst.KEY_TYPE, JsonConst.TARS); 34 | wapper.addProperty(JsonConst.KEY_TAG, tag); 35 | wapper.add(JsonConst.KEY_VALUE, jo); 36 | rootObj.add(String.valueOf(tag), wapper); 37 | } else { 38 | /* 39 | 如果是基础类型,数据是如下这样的。 40 | { 41 | "type" : "string" 42 | "value" : "testString" 43 | } 44 | */ 45 | jo.addProperty(JsonConst.KEY_TAG, tag); 46 | rootObj.add(String.valueOf(tag), jo); 47 | } 48 | tag++; 49 | } 50 | return rootObj; 51 | } 52 | 53 | /** 54 | * 55 | * @param ios JsonInputStream 56 | * @param context 内容上下文 57 | * @return JsonObject 58 | */ 59 | public static JsonObject getReturn(JsonInputStream ios, ServantInvokeContext context) { 60 | return ios.getItem(context.getJsonRetVal()); 61 | } 62 | 63 | /** 64 | * @param buffer 接收到的数据Buffer 65 | * @param context 包含发送参数、返回值、返回参数列表的内容 66 | */ 67 | public static void parseTarsStream(byte[] buffer, ServantInvokeContext context) { 68 | Object[] outTars = new Object[context.getArgumentValues().length + 1]; 69 | if (context.getArgumentValues().length > 0 && context.getArgumentValues()[0] instanceof JsonObject) { 70 | JsonInputStream inputStream = new JsonInputStream(buffer); 71 | context.setJsonRetVal(getReturn(inputStream, context)); 72 | //性能测试分支 73 | JsonObject rootObj = generateFullJsonObject(context.getArgumentValues()); 74 | JsonObject outJson = inputStream.read(rootObj); 75 | JsonObject[] outJsonArgs = new JsonObject[context.getArgumentValues().length]; 76 | for (int i = 1; i <= context.getArgumentValues().length; i++) { 77 | JsonObject item = outJson 78 | .get(String.valueOf(i)) 79 | .getAsJsonObject(); 80 | 81 | if (JsonConst.TARS.equalsIgnoreCase(item.get(JsonConst.KEY_TYPE).getAsString())) { 82 | JsonElement element = item.get(JsonConst.KEY_VALUE); 83 | if (!element.isJsonNull()) { 84 | outJsonArgs[i - 1] = element.getAsJsonObject(); 85 | } 86 | } else { 87 | item.remove(JsonConst.KEY_TAG); 88 | outJsonArgs[i - 1] = item; 89 | } 90 | } 91 | context.setRetVal(outTars[0]); 92 | context.setRetArguments(outJsonArgs); 93 | } else { 94 | TarsInputStream ios = new TarsInputStream(buffer); 95 | outTars[0] = ios.read(context.getRetValue(), 0, false); 96 | int tag = 1; 97 | for (Object param : context.getArgumentValues()) { 98 | outTars[tag] = ios.read(param, tag, false); 99 | tag++; 100 | } 101 | context.setRetVal(outTars[0]); 102 | context.setRetArguments(outTars); 103 | } 104 | } 105 | 106 | 107 | private static ByteBuffer jsonObjectToTarsStream(JsonObject rootObj) { 108 | JsonOutputStream oos = new JsonOutputStream(); 109 | oos.write(rootObj); 110 | return oos.getByteBuffer(); 111 | } 112 | 113 | public static ByteBuffer paramsToJceStream(Object[] objs) { 114 | if (objs.length > 0 && objs[0] instanceof JsonObject) { 115 | //性能测试分支 116 | JsonObject rootObj = generateFullJsonObject(objs); 117 | return jsonObjectToTarsStream(rootObj); 118 | } else { 119 | TarsOutputStream oos = new TarsOutputStream(); 120 | int tag = 1; 121 | for (Object obj : objs) { 122 | oos.write(obj, tag); 123 | tag++; 124 | } 125 | return oos.getByteBuffer(); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/packet/RequestPacket.java: -------------------------------------------------------------------------------- 1 | // 2 | // Source code recreated from a .class file by IntelliJ IDEA 3 | // (powered by Fernflower decompiler) 4 | // 5 | 6 | package com.tencent.tars.protocol.packet; 7 | 8 | import com.tencent.tars.protocol.TarsStructUtil; 9 | import com.tencent.tars.protocol.tars.TarsInputStream; 10 | import com.tencent.tars.protocol.tars.TarsOutputStream; 11 | import com.tencent.tars.protocol.tars.TarsStructBase; 12 | import com.tencent.tars.utils.TextUtils; 13 | 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | public final class RequestPacket extends TarsStructBase { 18 | public short iVersion = 0; 19 | public byte cPacketType = 0; 20 | public int iMessageType = 0; 21 | public int iRequestId = 0; 22 | public String sServantName = null; 23 | public String sFuncName = null; 24 | public byte[] sBuffer; 25 | public int iTimeout = 0; 26 | public Map context; 27 | public Map status; 28 | static byte[] cache_sBuffer = null; 29 | static Map cache_context = null; 30 | 31 | public RequestPacket() { 32 | } 33 | 34 | public RequestPacket(short iVersion, byte cPacketType, int iMessageType, int iRequestId, String sServantName, String sFuncName, byte[] sBuffer, int iTimeout, Map context, Map status) { 35 | this.iVersion = iVersion; 36 | this.cPacketType = cPacketType; 37 | this.iMessageType = iMessageType; 38 | this.iRequestId = iRequestId; 39 | this.sServantName = sServantName; 40 | this.sFuncName = sFuncName; 41 | this.sBuffer = sBuffer; 42 | this.iTimeout = iTimeout; 43 | this.context = context; 44 | this.status = status; 45 | } 46 | 47 | public boolean equals(Object o) { 48 | RequestPacket t = (RequestPacket)o; 49 | 50 | return TarsUtil.equals(1, t.iVersion) && TarsUtil.equals(1, t.cPacketType) && TarsUtil.equals(1, t.iMessageType) && TarsUtil.equals(1, t.iRequestId) && TarsUtil.equals(1, t.sServantName) && TarsUtil.equals(1, t.sFuncName) && TarsUtil.equals(1, t.sBuffer) && TarsUtil.equals(1, t.iTimeout) && TarsUtil.equals(1, t.context) && TarsUtil.equals(1, t.status); 51 | } 52 | 53 | public Object clone() { 54 | Object o = null; 55 | 56 | try { 57 | o = super.clone(); 58 | } catch (CloneNotSupportedException var3) { 59 | assert false; 60 | } 61 | 62 | return o; 63 | } 64 | 65 | public void writeTo(TarsOutputStream _os) { 66 | _os.write(this.iVersion, 1); 67 | _os.write(this.cPacketType, 2); 68 | _os.write(this.iMessageType, 3); 69 | _os.write(this.iRequestId, 4); 70 | _os.write(this.sServantName, 5); 71 | _os.write(this.sFuncName, 6); 72 | _os.write(this.sBuffer, 7); 73 | _os.write(this.iTimeout, 8); 74 | _os.write(this.context, 9); 75 | _os.write(this.status, 10); 76 | } 77 | 78 | public void readFrom(TarsInputStream _is) { 79 | try { 80 | this.iVersion = _is.read(this.iVersion, 1, true); 81 | this.cPacketType = _is.read(this.cPacketType, 2, true); 82 | this.iMessageType = _is.read(this.iMessageType, 3, true); 83 | this.iRequestId = _is.read(this.iRequestId, 4, true); 84 | this.sServantName = _is.readString(5, true); 85 | this.sFuncName = _is.readString(6, true); 86 | if (null == cache_sBuffer) { 87 | cache_sBuffer = new byte[]{0}; 88 | } 89 | 90 | this.sBuffer = (byte[])_is.read(cache_sBuffer, 7, true); 91 | this.iTimeout = _is.read(this.iTimeout, 8, true); 92 | if (null == cache_context) { 93 | cache_context = new HashMap(); 94 | cache_context.put("", ""); 95 | } 96 | 97 | this.context = (Map)_is.read(cache_context, 9, true); 98 | if (null == cache_context) { 99 | cache_context = new HashMap(); 100 | cache_context.put("", ""); 101 | } 102 | 103 | this.status = (Map)_is.read(cache_context, 10, true); 104 | } catch (Exception var3) { 105 | var3.printStackTrace(); 106 | System.out.println("RequestPacket decode error " + TextUtils.byteArrayToHexStr(this.sBuffer)); 107 | throw new RuntimeException(var3); 108 | } 109 | } 110 | 111 | public void display(StringBuilder _os, int _level) { 112 | TarsDisplayer _ds = new TarsDisplayer(_os, _level); 113 | _ds.display(this.iVersion, "iVersion"); 114 | _ds.display(this.cPacketType, "cPacketType"); 115 | _ds.display(this.iMessageType, "iMessageType"); 116 | _ds.display(this.iRequestId, "iRequestId"); 117 | _ds.display(this.sServantName, "sServantName"); 118 | _ds.display(this.sFuncName, "sFuncName"); 119 | _ds.display(this.sBuffer, "sBuffer"); 120 | _ds.display(this.iTimeout, "iTimeout"); 121 | _ds.display(this.context, "context"); 122 | _ds.display(this.status, "status"); 123 | } 124 | 125 | public static void main(String[] args) { 126 | RequestPacket req = new RequestPacket(); 127 | req.sFuncName="ok"; 128 | req.sServantName="112"; 129 | req.sBuffer = new byte[] {1,10}; 130 | req.context = new HashMap<>(); 131 | req.status = new HashMap<>(); 132 | byte[] bs = TarsStructUtil.tarsStructToUTF8ByteArray(req); 133 | req.sFuncName="OK2"; 134 | TarsStructUtil.getTarsStruct(bs, req); 135 | System.out.println(req.sFuncName); 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/sampler/TarsImpl.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.sampler; 2 | 3 | import com.google.gson.JsonObject; 4 | import com.tencent.tars.jmeter.constants.ITarsConst; 5 | import com.tencent.tars.protocol.json.JsonStreamUtil; 6 | import com.tencent.tars.tup.ServantInvokeContext; 7 | import com.tencent.tars.tup.TupClient; 8 | import com.tencent.tars.utils.ErrorCode; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.util.Arrays; 13 | 14 | /** 15 | * tars 接口测试 16 | * 17 | * @author brookechen 18 | */ 19 | public class TarsImpl extends TarsAbstractImpl { 20 | private static final Logger log = LoggerFactory.getLogger(TarsImpl.class); 21 | 22 | private TupClient client = null; 23 | private boolean isKeepAlive; 24 | private boolean isProfileNetStarted = false; 25 | 26 | 27 | public TarsImpl(TarsSamplerBase testElement) { 28 | super(testElement); 29 | isKeepAlive = testElement.isKeepAlive(); 30 | if (isKeepAlive) { 31 | beforeTransmit(null); 32 | } 33 | } 34 | 35 | /** 36 | * 数据发送前 37 | *

38 | * public short iVersion = 0; 39 | * public byte cPacketType = 0; 40 | * public int iMessageType = 0; 41 | */ 42 | private void beforeTransmit(TarsSampleResult result) { 43 | if (client == null) { 44 | client = TupClient.builder() 45 | .setIp(testElement.getServantIp()) 46 | .setPort(testElement.getServantPort()) 47 | .setServant(testElement.getServantPath()) 48 | .setFunc(testElement.getFuncName()) 49 | .setProxy(this.getProxy()) 50 | .setConnectTimeout(testElement.getConnectTimeout()) 51 | .setReadTimeout(testElement.getReadTimeout()) 52 | .setTransmitType(testElement.getTransmitType()) 53 | .build(); 54 | } 55 | try { 56 | log.debug(String.format("Thread %s before tup network init.", threadName)); 57 | client.init(); 58 | log.debug(String.format("Thread %s after tup network init.", threadName)); 59 | } catch (Throwable t) { 60 | this.localThrowable = t; 61 | this.errCode += ErrorCode.ErrorPrepareNetwork; 62 | } 63 | if (result != null) { 64 | updateResult(result, ""); 65 | } 66 | } 67 | 68 | private void transmitData(TarsSampleResult result) { 69 | log.debug(String.format("Thread %s before transmit data.", threadName)); 70 | StringBuilder resultData = new StringBuilder(); 71 | try { 72 | //根据UI配置的parameters来构造每个Tup包的RequestPacket 73 | client.setMessageType(testElement.getTupMessageType()); 74 | client.setTimeout(testElement.getTupTimeout()); 75 | client.setPacketType(testElement.getTupPacketType()); 76 | client.setVersion(testElement.getTupVersion()); 77 | client.setContext(testElement.getContextMap()); 78 | client.setStatus(testElement.getStatusMap()); 79 | 80 | ServantInvokeContext context = new ServantInvokeContext(testElement.getReturnValue(), testElement.getRequestParameters()); 81 | this.errCode = client.invokeMethod(context); 82 | result.setSentBytes(context.getSendBytes()); 83 | resultData.append(ITarsConst.RETURN_VALUE_NAME + ":\n"); 84 | resultData.append(JsonStreamUtil.toPrettyFormat(context.getJsonRetVal())).append("\n\n"); 85 | resultData.append("Status" + ":\n"); 86 | resultData.append(JsonStreamUtil.toPrettyFormat(context.getStatus())).append("\n\n"); 87 | resultData.append("Parameters" + ":\n"); 88 | JsonObject[] retArgs = (JsonObject[]) context.getRetArguments(); 89 | if (retArgs != null && 90 | retArgs.length > 0) { 91 | resultData.append(JsonStreamUtil.toPrettyFormat(testElement.getResponseBody(retArgs))); 92 | } else { 93 | log.warn("retArgs:" + (retArgs == null ? "null" : Arrays.toString(retArgs))); 94 | } 95 | } catch (Throwable t) { 96 | this.localThrowable = t; 97 | this.errCode += ErrorCode.ErrorTarsException; 98 | } 99 | updateResult(result, resultData.toString()); 100 | log.debug(String.format("Thread %s after transmit data.", threadName)); 101 | } 102 | 103 | private void afterTransmit(TarsSampleResult result) { 104 | log.debug(String.format("Thread %s before stop network.", threadName)); 105 | try { 106 | client.stop(); 107 | } catch (Throwable t) { 108 | if (this.localThrowable == null) { 109 | this.localThrowable = t; 110 | } 111 | if (this.errCode == 0) { 112 | this.errCode += ErrorCode.ErrorStopNetwork; 113 | } 114 | updateResult(result, ""); 115 | } 116 | log.debug(String.format("Thread %s after stop network.", threadName)); 117 | } 118 | 119 | @Override 120 | public TarsSampleResult sample(TarsSampleResult result) { 121 | updateResult(result, ""); 122 | if (!isKeepAlive) { 123 | beforeTransmit(result); 124 | } 125 | if (!testElement.getSuccessfulStatus(result)) { 126 | errorResult(this.localThrowable, result); 127 | //initNetwork阶段就已经失败了. 128 | return result; 129 | } 130 | transmitData(result); 131 | if (!isKeepAlive) { 132 | afterTransmit(result); 133 | } 134 | return result; 135 | } 136 | 137 | @Override 138 | public boolean interrupt() { 139 | if (client != null) { 140 | client.stop(); 141 | } 142 | client = null; 143 | return true; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/gui/widgets/ArgumentsPanelBase.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.gui.widgets; 2 | 3 | import com.tencent.tars.jmeter.gui.CustomResUtils; 4 | import org.apache.jmeter.config.Argument; 5 | import org.apache.jmeter.config.Arguments; 6 | import org.apache.jmeter.config.gui.ArgumentsPanel; 7 | import org.apache.jmeter.config.gui.RowDetailDialog; 8 | import org.apache.jmeter.testelement.TestElement; 9 | import org.apache.jmeter.testelement.property.JMeterProperty; 10 | import org.apache.jorphan.gui.GuiUtils; 11 | import org.apache.jorphan.gui.ObjectTableModel; 12 | import org.apache.jorphan.reflect.Functor; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import javax.swing.*; 17 | import java.util.Iterator; 18 | 19 | public abstract class ArgumentsPanelBase extends ArgumentsPanel { 20 | private static final Logger log = LoggerFactory.getLogger(ArgumentsPanelBase.class); 21 | private static final long serialVersionUID = 1L; 22 | 23 | protected static int NAME_COL = 0; 24 | protected static int VALUE_COL = 1; 25 | 26 | /** 27 | * When pasting from the clipboard, split lines on linebreak or '&' 28 | */ 29 | private static final String CLIPBOARD_LINE_DELIMITERS = "\n|&"; //$NON-NLS-1$ 30 | 31 | /** 32 | * When pasting from the clipboard, split parameters on tab or '=' 33 | */ 34 | private static final String CLIPBOARD_ARG_DELIMITERS = "\t|="; //$NON-NLS-1$ 35 | 36 | 37 | public ArgumentsPanelBase(String label) { 38 | this(label,true); 39 | } 40 | 41 | public ArgumentsPanelBase(String label,boolean disableButton) { 42 | super(label, null, false, false, null, disableButton); 43 | } 44 | 45 | 46 | @Override 47 | protected void initializeTableModel() { 48 | if (tableModel == null) { 49 | tableModel = new ObjectTableModel(new String[]{COLUMN_RESOURCE_NAMES_0, COLUMN_RESOURCE_NAMES_1}, 50 | Argument.class, 51 | new Functor[]{ 52 | new Functor("getName"), // $NON-NLS-1$ 53 | new Functor("getValue")}, // $NON-NLS-1$\ 54 | new Functor[]{ 55 | new Functor("setName"), // $NON-NLS-1$ 56 | new Functor("setValue")}, // $NON-NLS-1$ 57 | new Class[]{String.class, String.class}); 58 | } 59 | } 60 | 61 | 62 | @Override 63 | public TestElement createTestElement() { 64 | log.info("createTestElement"); 65 | Arguments args = getUnclonedParameters(); 66 | super.configureTestElement(args); 67 | return (TestElement) args.clone(); 68 | } 69 | 70 | 71 | protected abstract Arguments getDefaultArguments(); 72 | 73 | private Arguments getUnclonedParameters() { 74 | stopTableEditing(); 75 | @SuppressWarnings("unchecked") 76 | Iterator modelData = (Iterator) tableModel.iterator(); 77 | Arguments args = new Arguments(); 78 | while (modelData.hasNext()) { 79 | Argument arg = modelData.next(); 80 | args.addArgument(arg); 81 | } 82 | return args; 83 | } 84 | 85 | @Override 86 | public void configure(TestElement el) { 87 | super.configure(el); 88 | if (el instanceof Arguments) { 89 | tableModel.clearData(); 90 | for (JMeterProperty jMeterProperty : ((Arguments) el).getArguments()) { 91 | Argument arg = (Argument) jMeterProperty.getObjectValue(); 92 | tableModel.addRow(arg); 93 | } 94 | } 95 | checkButtonsStatus(); 96 | } 97 | 98 | @Override 99 | protected void addFromClipboard() { 100 | addFromClipboard(CLIPBOARD_LINE_DELIMITERS, CLIPBOARD_ARG_DELIMITERS); 101 | } 102 | 103 | 104 | protected void init() { // WARNING: called from ctor so must not be overridden (i.e. must be private or final) 105 | // register the right click menu 106 | JTable table = getTable(); 107 | final JPopupMenu popupMenu = new JPopupMenu(); 108 | JMenuItem variabilizeItem = new JMenuItem(CustomResUtils.getResString("tars.mouse.transform.into.variable")); 109 | JMenuItem detailItem = new JMenuItem(CustomResUtils.getResString("tars.mouse.detail.edit")); 110 | variabilizeItem.addActionListener(e -> transformNameIntoVariable()); 111 | detailItem.addActionListener(e -> showDetail()); 112 | popupMenu.add(variabilizeItem); 113 | popupMenu.add(detailItem); 114 | table.setComponentPopupMenu(popupMenu); 115 | } 116 | 117 | @Override 118 | public void clear() { 119 | super.clear(); 120 | this.configure(getDefaultArguments()); 121 | } 122 | 123 | private void showDetail() { 124 | int[] rowsSelected = getTable().getSelectedRows(); 125 | GuiUtils.stopTableEditing(getTable()); 126 | if (rowsSelected.length == 1) { 127 | getTable().clearSelection(); 128 | RowDetailDialog detailDialog = new RowDetailDialog(tableModel, rowsSelected[0]); 129 | detailDialog.setVisible(true); 130 | } 131 | } 132 | 133 | @Override 134 | protected void sizeColumns(JTable _table) { 135 | _table.setRowHeight(30); 136 | } 137 | 138 | /** 139 | * replace the argument value of the selection with a variable 140 | * the variable name is derived from the parameter name 141 | */ 142 | private void transformNameIntoVariable() { 143 | int[] rowsSelected = getTable().getSelectedRows(); 144 | for (int selectedRow : rowsSelected) { 145 | String name = (String) tableModel.getValueAt(selectedRow, NAME_COL); 146 | if (name != null && !name.trim().isEmpty()) { 147 | name = name.trim(); 148 | name = name.replaceAll("\\$", "_"); 149 | name = name.replaceAll("\\{", "_"); 150 | name = name.replaceAll("\\}", "_"); 151 | tableModel.setValueAt("${" + name + "}", selectedRow, VALUE_COL); 152 | } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin or MSYS, switch paths to Windows format before running java 129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=`expr $i + 1` 158 | done 159 | case $i in 160 | 0) set -- ;; 161 | 1) set -- "$args0" ;; 162 | 2) set -- "$args0" "$args1" ;; 163 | 3) set -- "$args0" "$args1" "$args2" ;; 164 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=`save "$@"` 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | exec "$JAVACMD" "$@" 184 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/tup/session/UdpSession.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.tup.session; 2 | 3 | import com.tencent.tars.tup.IPEndPoint; 4 | import com.tencent.tars.utils.ErrorCode; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.io.*; 9 | import java.net.*; 10 | import java.util.concurrent.atomic.AtomicBoolean; 11 | 12 | public class UdpSession extends Session { 13 | private static final Logger log = LoggerFactory.getLogger(UdpSession.class); 14 | 15 | private AtomicBoolean mStopped = new AtomicBoolean(true); // 停止标记位 16 | private final Object mSndLock = new Object(); 17 | private DatagramSocket mSocket; 18 | private DatagramPacket mSendPacket; 19 | private DatagramPacket mRecvPacket; 20 | private int recvSize = 1024; 21 | // private static final int RECV_MAX_SIZE = 16384; 22 | private IPEndPoint mIPEndPoint; 23 | 24 | private String threadName = Thread.currentThread().getName(); 25 | 26 | public UdpSession(IPEndPoint endPoint) { 27 | this.mIPEndPoint = endPoint; 28 | } 29 | 30 | 31 | /** 32 | * udp network是否已启动 33 | */ 34 | private boolean isStarted() { 35 | return !mStopped.get(); 36 | } 37 | 38 | /** 39 | * 启动网络,支持重启网络 40 | */ 41 | @Override 42 | public synchronized int start(boolean isRestart) { 43 | if (isStarted() && !isRestart) { 44 | log.info("startService()" + " isStarted() " + isStarted()); 45 | return ErrorCode.ERR_NONE; 46 | } 47 | if (!isSocketClosed()) { 48 | stopSocket(); 49 | } 50 | int ret = checkSocket(mIPEndPoint); 51 | if (ret != ErrorCode.ERR_NONE) { 52 | log.info("startService()" + " checkSocket() ret = " + ret); 53 | return ret; 54 | } 55 | return ErrorCode.ERR_NONE; 56 | } 57 | 58 | 59 | /** 60 | * 启动网络,支持重启网络 61 | */ 62 | /** 63 | * 从ip策略中尝试获取到可用ip 64 | */ 65 | private int checkSocket(final IPEndPoint ipPoint) { 66 | int ret; 67 | try { 68 | mSocket = new DatagramSocket(); 69 | InetAddress serverAddr = InetAddress.getByName(ipPoint.getIp()); 70 | mSocket.connect(serverAddr, ipPoint.getPort()); 71 | mSocket.setSoTimeout(this.readTimeout); 72 | ret = 0; 73 | } catch (UnknownHostException e) { 74 | ret = ErrorCode.ERR_NETWORK_UNKNOWN_HOST_EXCEPTION; 75 | log.error("checkSocket() UnknownHostException ", e); 76 | } catch (Throwable t) { 77 | ret = ErrorCode.ERR_NETWORK_START_THROWABLE; 78 | log.error("checkSocket() Throwable ", t); 79 | } 80 | return ret; 81 | } 82 | 83 | 84 | public int recvInSync() { 85 | int retcode = ErrorCode.ERR_NONE; 86 | try { 87 | byte[] respData; 88 | mRecvPacket = new DatagramPacket(new byte[recvSize], recvSize); 89 | mSocket.receive(mRecvPacket); 90 | ByteArrayInputStream iss = new ByteArrayInputStream(mRecvPacket.getData()); 91 | DataInputStream is = new DataInputStream(iss); 92 | int size = is.readInt() - 4; 93 | respData = getBytesFromIS(is, 0, size); 94 | is.close(); 95 | if (respData == null) { 96 | String err = "decode resp data get error data. because of get length (" + size + ") data return null at " + threadName; 97 | log.error(err); 98 | retcode = ErrorCode.ERR_NETWORK_RECV_NULL; 99 | return retcode; 100 | } 101 | if (respData.length != size) { 102 | String err = "decode resp data get error data. because of error length (" + size + ") or getBytes error at " + threadName; 103 | log.error(err); 104 | retcode = ErrorCode.ERR_NETWORK_RECV_0; 105 | return retcode; 106 | } 107 | handleData(respData); 108 | } catch (EOFException e) { 109 | log.error("sendDataInSync() has a EOFException at " + threadName, e); 110 | retcode = ErrorCode.ERR_NETWORK_UDP_RECV_EOF; 111 | } catch (IOException e) { 112 | log.error("sendDataInSync() has a IOException at " + threadName, e); 113 | retcode = ErrorCode.ERR_NETWORK_UDP_RECV_IOE; 114 | } catch (Throwable t) { 115 | log.error("sendDataInSync() has a Throwable at " + threadName, t); 116 | retcode = ErrorCode.ERR_NETWORK_UDP_RECV_THROWABLE; 117 | } 118 | return retcode; 119 | } 120 | 121 | @Override 122 | public int sendData(final byte[] data) { 123 | this.threadName = Thread.currentThread().getName(); 124 | if (!isSocketConnected()) { 125 | log.error("ERR_NETWORK_SOCKET_NOT_CONNECTED"); 126 | return ErrorCode.ERR_NETWORK_SOCKET_NOT_CONNECTED; 127 | } 128 | return sendDataInSync(data); 129 | } 130 | 131 | private int sendDataInSync(final byte[] data) { 132 | try { 133 | ByteArrayOutputStream oss = new ByteArrayOutputStream(); 134 | DataOutputStream os = new DataOutputStream(oss); 135 | int len = data.length + 4; 136 | os.writeInt(len); 137 | os.write(data); 138 | mSendPacket = new DatagramPacket(oss.toByteArray(), len); 139 | this.mNetListener.sentBytesDispatch(len, data); 140 | oss.close(); 141 | mSocket.send(mSendPacket); 142 | } catch (SocketException e) { 143 | log.error("sendDataInSync()" + " has a SocketException at" + threadName, e); 144 | return ErrorCode.ERR_NETWORK_SOCKET_TIMEOUT_EXCEPTION_RW; 145 | } catch (Throwable t) { 146 | log.error("sendDataInSync()" + " has a Throwable at" + threadName, t); 147 | return ErrorCode.ERR_NETWORK_EXCEPTION; 148 | } 149 | return recvInSync(); 150 | } 151 | 152 | 153 | /** 154 | * 关闭网络 155 | * 关闭过程中的错误信息不需要。 156 | */ 157 | public synchronized int stop() { 158 | INetListener temp = this.mNetListener; 159 | removeListener(); 160 | boolean ret = stopSocket(); 161 | if (!ret) { 162 | return ErrorCode.ERR_NETWORK_CLOSE_FAILED; 163 | } 164 | mStopped.set(true); 165 | this.setNetworkListener(temp); 166 | return ErrorCode.ERR_NONE; 167 | } 168 | 169 | private boolean stopSocket() { 170 | if (isSocketClosed()) { 171 | log.info("stopService socket success:true"); 172 | return true; 173 | } 174 | 175 | boolean ret = true; 176 | try { 177 | mSocket.close(); 178 | mRecvPacket = null; 179 | mSendPacket = null; 180 | mSocket = null; 181 | // 睡眠1秒,待资源释放结束 182 | Thread.sleep(1000); 183 | } catch (InterruptedException e) { 184 | log.error("stopSocket() " + "InterruptedException ", e); 185 | } 186 | return ret; 187 | } 188 | 189 | private boolean isSocketClosed() { 190 | if (null == mSocket) { 191 | return true; 192 | } 193 | return (mSocket.isClosed()); 194 | } 195 | 196 | private boolean isSocketConnected() { 197 | if (null == mSocket) { 198 | return false; 199 | } 200 | return (!isSocketClosed() && mSocket.isConnected()); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/gui/widgets/Tars2JsonDialog.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.gui.widgets; 2 | 3 | import org.apache.jmeter.gui.action.KeyStrokes; 4 | import org.apache.jmeter.gui.util.JSyntaxTextArea; 5 | import org.apache.jmeter.gui.util.JTextScrollPane; 6 | import org.apache.jmeter.util.JMeterUtils; 7 | import org.apache.jorphan.gui.ComponentUtil; 8 | import org.apache.jorphan.gui.JLabeledTextField; 9 | import org.apache.jorphan.gui.ObjectTableModel; 10 | 11 | import javax.swing.*; 12 | import javax.swing.event.DocumentEvent; 13 | import javax.swing.event.DocumentListener; 14 | import java.awt.*; 15 | import java.awt.event.ActionEvent; 16 | import java.awt.event.ActionListener; 17 | 18 | public class Tars2JsonDialog extends JDialog implements ActionListener, DocumentListener { 19 | 20 | /** 21 | * Command for CANCEL. 22 | */ 23 | private static final String CLOSE = "close"; // $NON-NLS-1$ 24 | 25 | private static final String UPDATE = "update"; // $NON-NLS-1$ 26 | 27 | private JTextField nameTF; 28 | 29 | private JSyntaxTextArea valueTA; 30 | 31 | private JButton closeButton; 32 | 33 | private ObjectTableModel tableModel; 34 | 35 | private JLabeledTextField outerTextArea; 36 | 37 | private int selectedRow; 38 | 39 | private boolean textChanged = true; // change to false after the first insert 40 | 41 | private final boolean updateData; 42 | 43 | public Tars2JsonDialog(JLabeledTextField textArea) { 44 | super((JFrame) null, "tars2json", true); //$NON-NLS-1$ 45 | updateData = true; 46 | this.outerTextArea = textArea; 47 | init(); 48 | } 49 | 50 | public Tars2JsonDialog(ObjectTableModel tableModel, int selectedRow) { 51 | super((JFrame) null, "tars2json", true); //$NON-NLS-1$ 52 | updateData = true; 53 | this.tableModel = tableModel; 54 | this.selectedRow = selectedRow; 55 | init(); 56 | } 57 | 58 | @Override 59 | protected JRootPane createRootPane() { 60 | JRootPane rootPane = new JRootPane(); 61 | // Hide Window on ESC 62 | Action escapeAction = new AbstractAction("ESCAPE") { 63 | 64 | private static final long serialVersionUID = -8699034338969407625L; 65 | 66 | @Override 67 | public void actionPerformed(ActionEvent actionEvent) { 68 | setVisible(false); 69 | } 70 | }; 71 | // Do update on Enter 72 | Action enterAction = new AbstractAction("ENTER") { 73 | 74 | private static final long serialVersionUID = -1529005452976176873L; 75 | 76 | @Override 77 | public void actionPerformed(ActionEvent actionEvent) { 78 | doUpdate(actionEvent); 79 | setVisible(false); 80 | } 81 | }; 82 | ActionMap actionMap = rootPane.getActionMap(); 83 | actionMap.put(escapeAction.getValue(Action.NAME), escapeAction); 84 | actionMap.put(enterAction.getValue(Action.NAME), enterAction); 85 | InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); 86 | inputMap.put(KeyStrokes.ESC, escapeAction.getValue(Action.NAME)); 87 | inputMap.put(KeyStrokes.ENTER, enterAction.getValue(Action.NAME)); 88 | return rootPane; 89 | } 90 | 91 | private void init() { // WARNING: called from ctor so must not be overridden (i.e. must be private or final) 92 | this.getContentPane().setLayout(new BorderLayout(10, 10)); 93 | 94 | JLabel nameLabel = new JLabel(JMeterUtils.getResString("name")); //$NON-NLS-1$ 95 | nameTF = new JTextField(JMeterUtils.getResString("name"), 20); //$NON-NLS-1$ 96 | nameTF.getDocument().addDocumentListener(this); 97 | JPanel namePane = new JPanel(new BorderLayout()); 98 | namePane.add(nameLabel, BorderLayout.WEST); 99 | namePane.add(nameTF, BorderLayout.CENTER); 100 | 101 | JLabel valueLabel = new JLabel(JMeterUtils.getResString("value")); //$NON-NLS-1$ 102 | valueTA = JSyntaxTextArea.getInstance(30, 80); 103 | valueTA.getDocument().addDocumentListener(this); 104 | if (tableModel != null) { 105 | setValues((String) tableModel.getValueAt(selectedRow, 0), (String) tableModel.getValueAt(selectedRow, 1)); 106 | } else if (outerTextArea != null) { 107 | setValues(outerTextArea.getLabel(), outerTextArea.getText()); 108 | } 109 | JPanel valuePane = new JPanel(new BorderLayout()); 110 | valuePane.add(valueLabel, BorderLayout.NORTH); 111 | JTextScrollPane jTextScrollPane = JTextScrollPane.getInstance(valueTA); 112 | valuePane.add(jTextScrollPane, BorderLayout.CENTER); 113 | 114 | JPanel detailPanel = new JPanel(new BorderLayout()); 115 | detailPanel.add(namePane, BorderLayout.NORTH); 116 | 117 | detailPanel.add(valuePane, BorderLayout.CENTER); 118 | 119 | JPanel mainPanel = new JPanel(); 120 | mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); 121 | mainPanel.setBorder(BorderFactory.createEmptyBorder(7, 3, 3, 3)); 122 | mainPanel.add(detailPanel, BorderLayout.CENTER); 123 | 124 | TarsStructPanel loadPane = new TarsStructPanel(valueTA); 125 | mainPanel.add(loadPane, BorderLayout.SOUTH); 126 | 127 | JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); 128 | JButton updateButton = new JButton(JMeterUtils.getResString("update")); //$NON-NLS-1$ 129 | if (updateData) { 130 | updateButton.setActionCommand(UPDATE); 131 | updateButton.addActionListener(this); 132 | } 133 | closeButton = new JButton(JMeterUtils.getResString("close")); //$NON-NLS-1$ 134 | closeButton.setActionCommand(CLOSE); 135 | closeButton.addActionListener(this); 136 | 137 | if (updateData) { 138 | buttonsPanel.add(updateButton); 139 | } 140 | buttonsPanel.add(closeButton); 141 | mainPanel.add(buttonsPanel, BorderLayout.SOUTH); 142 | 143 | this.getContentPane().add(mainPanel); 144 | nameTF.requestFocusInWindow(); 145 | 146 | this.pack(); 147 | ComponentUtil.centerComponentInWindow(this); 148 | } 149 | 150 | /** 151 | * Do search 152 | * 153 | * @param e {@link ActionEvent} 154 | */ 155 | @Override 156 | public void actionPerformed(ActionEvent e) { 157 | String action = e.getActionCommand(); 158 | if (action.equals(CLOSE)) { 159 | this.setVisible(false); 160 | } else if (action.equals(UPDATE) && updateData) { 161 | doUpdate(e); 162 | } 163 | } 164 | 165 | 166 | /** 167 | * Set TextField and TA values from model 168 | */ 169 | private void setValues(String name, String value) { 170 | nameTF.setText(name); 171 | valueTA.setInitialText(value); 172 | valueTA.setCaretPosition(0); 173 | textChanged = false; 174 | } 175 | 176 | /** 177 | * Update model values 178 | * 179 | * @param actionEvent the event that led to this call 180 | */ 181 | protected void doUpdate(ActionEvent actionEvent) { 182 | if (tableModel != null) { 183 | tableModel.setValueAt(nameTF.getText(), selectedRow, 0); 184 | tableModel.setValueAt(valueTA.getText(), selectedRow, 1); 185 | } else if (outerTextArea != null) { 186 | outerTextArea.setText(valueTA.getText()); 187 | } 188 | // Change Cancel label to Close 189 | closeButton.setText(JMeterUtils.getResString("close")); //$NON-NLS-1$ 190 | textChanged = false; 191 | } 192 | 193 | /** 194 | * Change the label of Close button to Cancel (after the first text changes) 195 | */ 196 | private void changeLabelButton() { 197 | if (!textChanged) { 198 | closeButton.setText(JMeterUtils.getResString("cancel")); //$NON-NLS-1$ 199 | textChanged = true; 200 | } 201 | } 202 | 203 | @Override 204 | public void insertUpdate(DocumentEvent e) { 205 | changeLabelButton(); 206 | } 207 | 208 | @Override 209 | public void removeUpdate(DocumentEvent e) { 210 | changeLabelButton(); 211 | } 212 | 213 | @Override 214 | public void changedUpdate(DocumentEvent e) { 215 | changeLabelButton(); 216 | } 217 | } -------------------------------------------------------------------------------- /README.zh.md: -------------------------------------------------------------------------------- 1 | # Tars JMeter 2 | 3 | Tars JMeter是一款针对Tars协议进行私有化定制的JMeter测试插件,其目的是为了帮助用户解决Tars服务的性能评估与测试。您可能会在以下场景使用到Tars JMeter: 4 | 5 | 1. 您开发了一组Tars服务,需要对这组RPC服务,进行简单自测时,您可以使用JMeter搭载该插件,基于Tup 收发进行无需编码的接口单测; 6 | 2. 您需要对您的Tars接口进行性能评估、压力测试、稳定性测试时,您可以使用JMeter搭载该插件。 7 | 8 | TarsJMeter特点如下: 9 | 10 | 1. 易用性强,用户只需对JMeter有一定的了解,即可采用TarsJMeter简洁的UI实现测试用例开发。 11 | 2. 支持分布式,通过JMeter的集群模式,可实现Tars服务的负载测试。目前我们有使用集群模式轻松触顶测试过吞吐量达50000TPS的Tars单服务。 12 | 3. 可测复杂场景,TarsJMeter结合JMeter丰富的 Logic Controller, Pre Processors, Post Processors,Timer,Config Element等组件,可丰富测试场景,使得测试用例不再是单一的接口测试。 13 | 4. 数据可监控,JMeter可把Tars服务的测试数据上报至InfluxDB(时序数据库),InfluxDB可与第三方监控平台对接,实现对数据流量的实时监控。 14 | 15 | ## 安装步骤 16 | 17 | 1. 安装**JAVA JDK** (建议java8以上); 18 | 2. [下载JMeter](https://jmeter.apache.org/download_jmeter.cgi),解压到本地目录即可,建议JMeter 5.2及以上版本; 19 | 3. 安装目录下的/bin 存放了jmeter可执行文件; **安装目录下的/lib/ext**可以添加扩展的第三方协议测试库; 20 | 4. Gradle编译打包或者[dist下载](https://github.com/TarsCloud/TarsJMeter/blob/master/dist/TarsJMeter-1.7.1.jar) 21 | 5. 生成或下载tars_jmeter.jar后,把它放入JMeter安装目录下的**/lib/ext**里。 22 | 23 | ## 用例编写步骤 24 | 25 | 1. 打开JMeter(执行JMeter目录下的bin/jmeter.bat或bin/jmeter.sh) 26 | 27 | 2. 依次添加线程组、取样器(Sampler),出现通用Tars请求表示安装成功。 28 | 29 | 30 | 3. 选择通用Tars请求,创建采样器完成。 31 | tars服务文件示例: 32 | ``` 33 | module TestApp 34 | { 35 | struct User { 36 | 0 require string name; 37 | }; 38 | 39 | interface Hello 40 | { 41 | string hello(int no, string name); 42 | string hello2(string name); 43 | int hello3(int no, string name, out string meg); 44 | int hello4(int no, out User user); 45 | }; 46 | }; 47 | ``` 48 | 49 | 采样器示例配置: 50 | 51 | 52 | 53 | * 被测服务地址:待测Tars服务的IP 54 | 55 | * 被测服务端口:待测Tars服务端口 56 | 57 | * 被测服务路径:待测Tars服务的Servant节点信息,例如:TestTars.HelloServer.HelloObj 58 | 59 | * 被测接口方法:待测Tars服务的被测函数方法,例如:hello4 60 | 61 | * 接口返回值类型:被测函数方法的Return返回值 62 | 63 | * tars2json:本地tars文件或包含tars的目录中tars结构体自动转换为供测试使用的json格式 64 | 65 | 66 | 67 | * 方法参数列表:名称(自定义,一般为函数的入参变量名),方法参数列表(根据函数的入参变量类型,转换为对应的json格式),type(选择函数的入参类型)例如:int hello4(int no, out User user); 68 | 69 | * Tars扩展参数:提供基本的Tars测试环境配置,可修改 70 | 71 | 72 | 73 | * 请求上下文:客户context(上下文信息)上报,客户端至Tars服务端单向。 74 | 75 | 76 | 77 | * 请求状态:客户与Tars服务间双向交互状态信息 78 | 79 | 80 | 81 | 82 | 83 | 4. 点击运行,查看树结果,可获取Tars服务的响应信息 84 | 85 | 86 | 87 | ## Tars Json数据定义及使用 88 | 89 | 插件使用`json`来定义目标Tars方法的入参或返回值数据,这样可以做到Tars结构化数据能够更好的可视化。插件集成的`Tars2JsonMojo`工具,提供从Tars Struct到 Json数据的快速转换能力。json可视化数据支持类型列表如下: 90 | 91 | `tars` //tars结构化数据 92 | `map` //map数据 93 | `vector` //复杂数据数组 94 | `boolean` // 8种基本类型数据 95 | `byte` 96 | `int` 97 | `short` 98 | `long` 99 | `float` 100 | `double` 101 | `string` 102 | `boolean[]` // 8种基本类型数据的数组 103 | `byte[]` 104 | `int[]` 105 | `short[]` 106 | `long[]` 107 | `float[]` 108 | `double[]` 109 | `string[]` 110 | 111 | ### 数据定义举例 112 | 113 | 基础类型及基础类型数组的定义: 114 | - string 115 | ```json 116 | { 117 | "type" : "string", 118 | "value" : "this is a primitive type" 119 | } 120 | ``` 121 | 122 | - int 123 | 124 | ```json 125 | { 126 | "type" : "int", 127 | "value" : 100 128 | } 129 | ``` 130 | 131 | - int[] 132 | ```json 133 | { 134 | "type" : "int[]", 135 | "value" : [100 , 200 ] 136 | } 137 | ``` 138 | 139 | `map`类型的定义: 140 | 141 | ```json 142 | { 143 | "type": "map", 144 | "value": [ 145 | { 146 | "key": { 147 | "type": "string", 148 | "value": "map key", 149 | "tag": 0 150 | }, 151 | "value": { 152 | "type": "string", 153 | "value": "map value", 154 | "tag": 1 155 | } 156 | } 157 | ], 158 | "tag": 0 159 | } 160 | ``` 161 | 162 | `vector`类型的定义,除8大基本类型的数组以外,区分基本类型的`vector`和tars struct的`vector`是为了,在使用较常使用的基本类型`vector`时,`json`结构更为清晰简洁: 163 | 164 | ```json 165 | { 166 | "type": "vector", 167 | "value": [ 168 | { 169 | "type": "tars", 170 | "value": "more detail tars struct {}", 171 | "tag": 0 172 | }, 173 | { 174 | "type": "tars", 175 | "value": "more detail tars struct {}", 176 | "tag": 0 177 | } 178 | ], 179 | "tag": 0 180 | } 181 | ``` 182 | 183 | tars混合结构示意,对于如下Tars Sturct和tars Interface的IDL定义文件: 184 | 185 | ```cpp 186 | module Tars2JsonExample 187 | { 188 | enum EOpType 189 | { 190 | EOpType_None = 0, 191 | EOpType_SmsAuth = 1, 192 | }; 193 | 194 | struct SubStruct 195 | { 196 | 0 optional string sub; 197 | }; 198 | 199 | struct TarsStructExample 200 | { 201 | 0 optional vector stringVec; 202 | 1 optional long tryLoginTime = 0; 203 | 2 optional EOpType enumTest; 204 | 3 optional vector> vectorMap; 205 | 4 optional map > mapCheck; 206 | }; 207 | 208 | interface Tars2JsonExampleServant 209 | { 210 | int getTarsStruct(TarsStructExample resp); 211 | }; 212 | }; 213 | ``` 214 | 215 | 可以通过tars2json自动转化为: 216 | 217 | ```json 218 | { 219 | "stringVec": { 220 | "type": "string[]", 221 | "value": [ "" ], 222 | "tag": 0 223 | }, 224 | "tryLoginTime": { 225 | "type": "long", 226 | "value": 0, 227 | "tag": 1 228 | }, 229 | "enumTest": { 230 | "type": "int", 231 | "value": 0, 232 | "tag": 2 233 | }, 234 | "vectorMap": { 235 | "type": "vector", 236 | "value": [ 237 | { 238 | "type": "map", 239 | "value": [ 240 | { 241 | "key": { 242 | "type": "string", 243 | "value": "", 244 | "tag": 0 245 | }, 246 | "value": { 247 | "type": "tars", 248 | "value": { 249 | "sub": { 250 | "type": "string", 251 | "value": "", 252 | "tag": 0 253 | } 254 | }, 255 | "tag": 1 256 | } 257 | } 258 | ], 259 | "tag": 0 260 | } 261 | ], 262 | "tag": 3 263 | }, 264 | "mapCheck": { 265 | "type": "map", 266 | "value": [ 267 | { 268 | "key": { 269 | "type": "int", 270 | "value": 0, 271 | "tag": 0 272 | }, 273 | "value": { 274 | "type": "byte[]", 275 | "value": [ 0 ], 276 | "tag": 1 277 | } 278 | } 279 | ], 280 | "tag": 4 281 | } 282 | } 283 | ``` 284 | 285 | ### Tars2Json使用 286 | 287 | 您在使用插件时,并不需要手工地编写`json`格式的tars数据,插件中集成的tars2json工具会自动识别您定义的tars接口文件,完成转换,您只需: 288 | 289 | 1. 选择接口参数或返回值类型; 290 | 2. 如为tars,点击插件界面底部的tars2json button; 291 | 3. 指定"目标Tars接口名称",如`TarsStructExample`; 292 | 4. 选择"目标Tars所在路径",可以是Tars文件所在的目录路径,也可以是Tars文件的文件路径; 293 | 5. 点击button tars2json,即可获得对应Tars Struct 的json数据描述。 294 | 295 | 296 | ## JMeter压测集群部署建议 297 | 298 | JMeter有一个广为人知的缺点:它的经典模型每个用户就是一个Java Thread,在线程调度方面,资源耗用是比较大的,这将导致单台部署JMeter的压测机器输出性能可能不会太高。 299 | 300 | 但,JMeter支持分布式压测,通过如下图的组网,可伸缩扩展JMeter slave个数,轻松满足各个量级的压力需求。 301 | 302 | ![JMeter分布式组网图](./res/network.png) 303 | 304 | 同时可以使用JMeter压测集群K8s部署方案来更加方便的管理压测集群:https://github.com/kubernauts/jmeter-kubernetes 305 | 306 | ## JMeter报表建议 307 | 308 | 无论是否使用K8s,当您搭建完JMeter + Influxdb + Grafana经典组网的压测环境后,您可以使用如下的Grafana dashboard来完成性能可视化监控。 309 | 310 | Apache JMeter Dashboard using Core InfluxdbBackendListenerClient: https://grafana.com/grafana/dashboards/5496 311 | 312 | This dashboard requires Apache JMeter 5 and upper versions. It shows overall statistics and you can zoom on one particular transaction. In order to use it you need to use JMeter Backend Listener and select InfluxdbBackendListenerClient. 313 | 314 | Setup: 315 | 316 | - Add Backend Listener to your test plan (Add -> Listener -> Backend Listener) and select org.apache.jmeter.visualizers.backend.influxdb.HttpMetricsSender 317 | - Provide in the Parameters table the InfluxDB settings, provide a name for the test, and specify which samplers to record. 318 | 319 | For more details, see this : 320 | 321 | - https://jmeter.apache.org/usermanual/component_reference.html#Backend_Listener 322 | - https://jmeter.apache.org/usermanual/realtime-results.html 323 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/json/JsonOutputStream.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.protocol.json; 2 | 3 | import com.google.gson.*; 4 | import com.tencent.tars.protocol.JsonConst; 5 | import com.tencent.tars.protocol.exceptions.JsonEncodeException; 6 | import com.tencent.tars.protocol.tars.TarsOutputStream; 7 | import com.tencent.tars.protocol.tars.TarsStructBase; 8 | 9 | import java.io.File; 10 | import java.io.FileInputStream; 11 | import java.io.FileNotFoundException; 12 | import java.io.InputStreamReader; 13 | import java.nio.ByteBuffer; 14 | import java.util.Map; 15 | 16 | import static com.tencent.tars.protocol.json.JsonStreamUtil.*; 17 | /** 18 | * json to tars bytes. 19 | * 20 | * @author brookechen 21 | */ 22 | public class JsonOutputStream { 23 | 24 | private TarsOutputStream os; 25 | 26 | public JsonOutputStream() { 27 | this.os = new TarsOutputStream(); 28 | } 29 | 30 | /** 31 | * direct path json file or json string to tars bytes 32 | */ 33 | public JsonOutputStream(String pathOrJson) { 34 | this(); 35 | JsonObject rootObject; 36 | if (new File(pathOrJson).isFile()) { 37 | InputStreamReader reader; 38 | try { 39 | FileInputStream is = new FileInputStream(pathOrJson); 40 | reader = new InputStreamReader(is); 41 | } catch (FileNotFoundException e) { 42 | // impossible branch. 43 | return; 44 | } 45 | rootObject = JsonParser.parseReader(reader).getAsJsonObject(); 46 | } else { 47 | rootObject = JsonParser.parseString(pathOrJson).getAsJsonObject(); 48 | } 49 | this.write(rootObject); 50 | } 51 | 52 | public void write(JsonObject rootObject) { 53 | if (os == null) { 54 | os = new TarsOutputStream(); 55 | } 56 | for (Map.Entry map : rootObject.entrySet()) { 57 | JsonElement element = map.getValue(); 58 | if (element.isJsonObject()) { 59 | JsonObject subObject = element.getAsJsonObject(); 60 | writeItem(subObject); 61 | } else{ 62 | throw new JsonEncodeException("this is not tars struct."); 63 | } 64 | } 65 | } 66 | 67 | private void writeItem(JsonObject subObject) { 68 | if (isPrimitive(subObject)) { 69 | writePrimitive(subObject); 70 | } else if (isVector(subObject)) { 71 | writeVector(subObject); 72 | } else if (isMap(subObject)) { 73 | writeMap(subObject); 74 | } else if (isCustom(subObject)) { 75 | writeTars(subObject); 76 | } 77 | } 78 | 79 | private void writePrimitive(JsonObject jsonObject) { 80 | if (jsonObject == null) { 81 | throw new JsonEncodeException("write primitive jsonObject error: jsonObject is null"); 82 | } 83 | String type = getType(jsonObject); 84 | int tag = getTag(jsonObject); 85 | JsonElement valueElement = getValue(jsonObject); 86 | if (JsonConst.BOOLEAN.equalsIgnoreCase(type)) { 87 | boolean value = valueElement.getAsBoolean(); 88 | os.write(value, tag); 89 | } else if (JsonConst.INT.equalsIgnoreCase(type)) { 90 | int value = valueElement.getAsInt(); 91 | os.write(value, tag); 92 | } else if (JsonConst.SHORT.equalsIgnoreCase(type)) { 93 | short value = valueElement.getAsShort(); 94 | os.write(value, tag); 95 | } else if (JsonConst.LONG.equalsIgnoreCase(type)) { 96 | long value = valueElement.getAsLong(); 97 | os.write(value, tag); 98 | } else if (JsonConst.FLOAT.equalsIgnoreCase(type)) { 99 | float value = valueElement.getAsFloat(); 100 | os.write(value, tag); 101 | } else if (JsonConst.DOUBLE.equalsIgnoreCase(type)) { 102 | double value = valueElement.getAsDouble(); 103 | os.write(value, tag); 104 | } else if (JsonConst.BYTE.equalsIgnoreCase(type)) { 105 | byte value = valueElement.getAsByte(); 106 | os.write(value, tag); 107 | } else if (JsonConst.STRING.equalsIgnoreCase(type)) { 108 | String value = valueElement.getAsString(); 109 | os.write(value, tag); 110 | } else if (JsonConst.BOOLEAN_VEC.equalsIgnoreCase(type)) { 111 | Boolean[] value = jsonToArray(valueElement, Boolean[].class); 112 | os.write(value, tag); 113 | } else if (JsonConst.INT_VEC.equalsIgnoreCase(type)) { 114 | Integer[] value = jsonToArray(valueElement, Integer[].class); 115 | os.write(value, tag); 116 | } else if (JsonConst.SHORT_VEC.equalsIgnoreCase(type)) { 117 | Short[] value = jsonToArray(valueElement, Short[].class); 118 | os.write(value, tag); 119 | } else if (JsonConst.LONG_VEC.equalsIgnoreCase(type)) { 120 | Long[] value = jsonToArray(valueElement, Long[].class); 121 | os.write(value, tag); 122 | } else if (JsonConst.FLOAT_VEC.equalsIgnoreCase(type)) { 123 | Float[] value = jsonToArray(valueElement, Float[].class); 124 | os.write(value, tag); 125 | } else if (JsonConst.DOUBLE_VEC.equalsIgnoreCase(type)) { 126 | Double[] value = jsonToArray(valueElement, Double[].class); 127 | os.write(value, tag); 128 | } else if (JsonConst.BYTE_VEC.equalsIgnoreCase(type)) { 129 | //这个稍微有点点不同,是SIMPLE_LIST 130 | Byte[] oValue = jsonToArray(valueElement, Byte[].class); 131 | byte[] value = new byte[oValue.length]; 132 | for (int i = 0; i < oValue.length; i++) { 133 | value[i] = oValue[i]; 134 | } 135 | os.write(value, tag); 136 | } else if (JsonConst.STRING_VEC.equalsIgnoreCase(type)) { 137 | String[] value = jsonToArray(valueElement, String[].class); 138 | os.write(value, tag); 139 | } else { 140 | throw new JsonEncodeException("write primitive type error:" + type); 141 | } 142 | } 143 | 144 | private void writeTars(JsonObject jsonObject) { 145 | JsonElement valueElement = getValue(jsonObject); 146 | int tag = getTag(jsonObject); 147 | this.os.reserve(2); 148 | this.os.writeHead(TarsStructBase.STRUCT_BEGIN, tag); 149 | this.write(valueElement.getAsJsonObject()); 150 | this.os.reserve(2); 151 | this.os.writeHead(TarsStructBase.STRUCT_END, 0); 152 | } 153 | 154 | private void writeVector(JsonObject jsonObject) { 155 | JsonElement valueElement = getValue(jsonObject); 156 | int tag = getTag(jsonObject); 157 | this.os.reserve(8); 158 | this.os.writeHead(TarsStructBase.LIST, tag); 159 | JsonArray valueArray = valueElement.getAsJsonArray(); 160 | this.os.write(valueArray.size(), 0); 161 | for (int j = 0; j < valueArray.size(); j++) { 162 | JsonElement subElement = valueArray.get(j); 163 | if (subElement.isJsonObject()) { 164 | JsonObject subObject = subElement.getAsJsonObject(); 165 | writeItem(subObject); 166 | } 167 | } 168 | } 169 | 170 | private void writeMap(JsonObject jsonObject) { 171 | JsonElement valueElement = getValue(jsonObject); 172 | JsonArray valueArray = valueElement.getAsJsonArray(); 173 | int tag = getTag(jsonObject); 174 | this.os.reserve(8); 175 | this.os.writeHead(TarsStructBase.MAP, tag); 176 | this.os.write(valueArray == null ? 0 : valueArray.size(), 0); 177 | if (valueArray != null) { 178 | for (int i = 0; i < valueArray.size(); i++) { 179 | JsonObject kvItem = valueArray.get(i).getAsJsonObject(); 180 | JsonObject keyJsonObject = getKey(kvItem).getAsJsonObject(); 181 | JsonObject valueJsonObject = getValue(kvItem).getAsJsonObject(); 182 | writeItem(keyJsonObject); // json数据的key这里一定要是 tag == 0 ,已经在tars2json里面做好了 183 | writeItem(valueJsonObject); // json数据的value这里一定要是 value == 1 184 | } 185 | } 186 | } 187 | 188 | public byte[] getBytes() { 189 | return this.os.toByteArray(); 190 | } 191 | 192 | public ByteBuffer getByteBuffer(){ 193 | return ByteBuffer.wrap(this.os.toByteArray()); 194 | } 195 | 196 | public JsonArray getBytesAsJsonArray() { 197 | return new Gson().toJsonTree(getBytes(), Byte[].class).getAsJsonArray(); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/tup/session/TcpSession.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.tup.session; 2 | 3 | import com.tencent.tars.tup.IPEndPoint; 4 | import com.tencent.tars.utils.ErrorCode; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.io.DataInputStream; 9 | import java.io.DataOutputStream; 10 | import java.io.EOFException; 11 | import java.io.IOException; 12 | import java.net.*; 13 | import java.util.concurrent.atomic.AtomicBoolean; 14 | 15 | public class TcpSession extends Session { 16 | private static final Logger log = LoggerFactory.getLogger(TcpSession.class); 17 | 18 | private AtomicBoolean mStopped = new AtomicBoolean(true); // 停止标记位 19 | private final Object mSndLock = new Object(); 20 | private Socket mSocket; 21 | private DataOutputStream mSocketWriter; // 写入流 22 | private DataInputStream mSocketReader; // 读取流 23 | private IPEndPoint mIPEndPoint; 24 | private Proxy mProxy = null; 25 | 26 | private String threadName = Thread.currentThread().getName(); 27 | 28 | public TcpSession(IPEndPoint endPoint, Proxy proxy) { 29 | this.mIPEndPoint = endPoint; 30 | this.mProxy = proxy; 31 | } 32 | 33 | public TcpSession(IPEndPoint endPoint) { 34 | this.mIPEndPoint = endPoint; 35 | } 36 | 37 | /** 38 | * tcp network是否已启动 39 | */ 40 | private boolean isStarted() { 41 | return !mStopped.get(); 42 | } 43 | 44 | /** 45 | * 启动网络,支持重启网络 46 | */ 47 | @Override 48 | public synchronized int start(boolean isRestart) { 49 | if (isStarted() && !isRestart) { 50 | log.info("startService()" + " isStarted() " + isStarted()); 51 | return ErrorCode.ERR_NONE; 52 | } 53 | int ret = checkSocket(mIPEndPoint); 54 | if (ret != ErrorCode.ERR_NONE) { 55 | log.info("startService()" + " checkSocket() ret = " + ret); 56 | return ret; 57 | } 58 | return ErrorCode.ERR_NONE; 59 | } 60 | 61 | public int recvInSync() { 62 | int retcode = ErrorCode.ERR_NONE; 63 | try { 64 | byte[] respData; 65 | int size = mSocketReader.readInt() - 4; 66 | respData = getBytesFromIS(mSocketReader, 0, size); 67 | if (respData == null) { 68 | String err = "decode resp data get error data. because of get length (" + size + ") data return null at " + threadName; 69 | log.error(err); 70 | retcode = ErrorCode.ERR_NETWORK_RECV_NULL; 71 | return retcode; 72 | } 73 | if (respData.length != size) { 74 | String err = "decode resp data get error data. because of error length (" + size + ") or getBytes error at " + threadName; 75 | log.error(err); 76 | retcode = ErrorCode.ERR_NETWORK_RECV_0; 77 | return retcode; 78 | } 79 | handleData(respData); 80 | } catch (EOFException e) { 81 | log.error("sendDataInSync() has a EOFException at " + threadName, e); 82 | retcode = ErrorCode.ERR_NETWORK_TCP_RECV_EOF; 83 | } catch (IOException e) { 84 | log.error("sendDataInSync() has a IOException at " + threadName, e); 85 | retcode = ErrorCode.ERR_NETWORK_TCP_RECV_IOE; 86 | } catch (Throwable t) { 87 | log.error("sendDataInSync() has a Throwable at " + threadName, t); 88 | retcode = ErrorCode.ERR_NETWORK_TCP_RECV_THROWABLE; 89 | } 90 | return retcode; 91 | } 92 | 93 | @Override 94 | public int sendData(final byte[] data) { 95 | this.threadName = Thread.currentThread().getName(); 96 | if (!isSocketConnected()) { 97 | log.error("ERR_NETWORK_SOCKET_NOT_CONNECTED"); 98 | return ErrorCode.ERR_NETWORK_SOCKET_NOT_CONNECTED; 99 | } 100 | return sendDataInSync(data); 101 | } 102 | 103 | private int sendDataInSync(final byte[] data) { 104 | try { 105 | int len = data.length + 4; 106 | mSocketWriter.writeInt(len); 107 | mSocketWriter.write(data); 108 | mSocketWriter.flush(); 109 | this.mNetListener.sentBytesDispatch(len, data); 110 | } catch (SocketException e) { 111 | log.error("sendDataInSync()" + " has a SocketException at" + threadName, e); 112 | return ErrorCode.ERR_NETWORK_SOCKET_TIMEOUT_EXCEPTION_RW; 113 | } catch (Throwable t) { 114 | log.error("sendDataInSync()" + " has a Throwable at" + threadName, t); 115 | return ErrorCode.ERR_NETWORK_EXCEPTION; 116 | } 117 | return recvInSync(); 118 | } 119 | 120 | /** 121 | * 关闭网络 122 | * 关闭过程中的错误信息不需要。 123 | */ 124 | public synchronized int stop() { 125 | INetListener temp = this.mNetListener; 126 | removeListener(); 127 | boolean ret = stopSocket(); 128 | if (!ret) { 129 | return ErrorCode.ERR_NETWORK_CLOSE_FAILED; 130 | } 131 | mStopped.set(true); 132 | this.setNetworkListener(temp); 133 | return ErrorCode.ERR_NONE; 134 | } 135 | 136 | /** 137 | * 从ip策略中尝试获取到可用ip 138 | */ 139 | private int checkSocket(final IPEndPoint ipPoint) { 140 | if (null == ipPoint) { 141 | return ErrorCode.ERR_NETWORK_ILLEGAL_ARGUMENT; 142 | } 143 | 144 | int ret; 145 | try { 146 | if (startSocket(ipPoint)) { 147 | ret = ErrorCode.ERR_NONE; 148 | } else { 149 | ret = ErrorCode.ERR_NETWORK_START_UNKNOWN; 150 | } 151 | } catch (UnknownHostException e) { 152 | ret = ErrorCode.ERR_NETWORK_UNKNOWN_HOST_EXCEPTION; 153 | log.error("checkSocket() UnknownHostException ", e); 154 | } catch (SocketTimeoutException e) { 155 | ret = ErrorCode.ERR_NETWORK_TCP_CHECK_SOCKET_TIMEOUT_FAILED; 156 | log.error("checkSocket() SocketTimeoutException ", e); 157 | } catch (Throwable t) { 158 | ret = ErrorCode.ERR_NETWORK_START_THROWABLE; 159 | log.error("checkSocket() Throwable ", t); 160 | } 161 | return ret; 162 | } 163 | 164 | 165 | private boolean startSocket(final IPEndPoint ipPoint) throws IOException { 166 | if (!isSocketClosed()) { 167 | stopSocket(); 168 | } 169 | 170 | mIPEndPoint = ipPoint; 171 | InetAddress serverAddr = InetAddress.getByName(ipPoint.getIp()); 172 | mSocket = acquireSocketWithTimeout(serverAddr, ipPoint.getPort()); 173 | mSocketWriter = new DataOutputStream(mSocket.getOutputStream()); 174 | mSocketReader = new DataInputStream(mSocket.getInputStream()); 175 | mSocket.setSoTimeout(this.readTimeout); 176 | return isSocketConnected(); 177 | } 178 | 179 | 180 | private boolean stopSocket() { 181 | if (isSocketClosed()) { 182 | log.info("stopService socket success:true"); 183 | return true; 184 | } 185 | 186 | boolean ret = true; 187 | try { 188 | mSocket.close(); 189 | mSocketReader.close(); 190 | mSocketWriter.close(); 191 | mSocket = null; 192 | mProxy = null; 193 | // 睡眠1秒,待资源释放结束 194 | Thread.sleep(1000); 195 | } catch (InterruptedException e) { 196 | log.error("stopSocket() " + "InterruptedException ", e); 197 | } catch (IOException e) { 198 | ret = false; 199 | log.error("stopSocket() " + "mSocket.close() ", e); 200 | } 201 | return ret; 202 | } 203 | 204 | 205 | private Socket acquireSocketWithTimeout(InetAddress dstAddress, int dstPort) throws IOException { 206 | log.info("MMConnectionManager--> acquireSocketWithTimeOut, addr: " + dstAddress + ", port: " + dstPort); 207 | Socket socket; 208 | if (this.mProxy == null) { 209 | socket = new Socket(); 210 | } else { 211 | socket = new Socket(this.mProxy); 212 | } 213 | socket.setSoLinger(false, 0); 214 | socket.connect(new InetSocketAddress(dstAddress, dstPort), connectTimeout); 215 | return socket; 216 | } 217 | 218 | private boolean isSocketClosed() { 219 | if (null == mSocket) { 220 | return true; 221 | } 222 | return (mSocket.isClosed()); 223 | } 224 | 225 | private boolean isSocketConnected() { 226 | if (null == mSocket) { 227 | return false; 228 | } 229 | return (!isSocketClosed() && mSocket.isConnected()); 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/tup/TupClient.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.tup; 2 | 3 | import com.tencent.tars.protocol.TarsStructUtil; 4 | import com.tencent.tars.protocol.packet.RequestPacket; 5 | import com.tencent.tars.protocol.packet.ResponsePacket; 6 | import com.tencent.tars.tup.session.INetListener; 7 | import com.tencent.tars.tup.session.Session; 8 | import com.tencent.tars.tup.session.TcpSession; 9 | import com.tencent.tars.tup.session.UdpSession; 10 | import com.tencent.tars.utils.ErrorCode; 11 | 12 | import java.net.Proxy; 13 | import java.nio.ByteBuffer; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | import java.util.concurrent.atomic.AtomicBoolean; 17 | import java.util.concurrent.atomic.AtomicInteger; 18 | 19 | /** 20 | * TupClient实现 21 | */ 22 | public class TupClient implements INetListener { 23 | 24 | private Session session; 25 | 26 | private Proxy mProxy = null; 27 | private String mIp; //IP 28 | private int mPort; //端口 29 | private String mServant; 30 | private String mFunc; 31 | private int connectTimeout = 8000; 32 | private int readTimeout = 8000; 33 | private String transmit = "TCP"; 34 | 35 | private short iVersion = 0; 36 | private byte cPacketType = 0; 37 | private int iMessageType = 0; 38 | private final AtomicInteger requestNo = new AtomicInteger(0); 39 | private int iTimeout = 4000; 40 | private Map context = new HashMap<>(); 41 | private Map status = new HashMap<>(); 42 | 43 | 44 | private ResponsePacket currentResp = null; 45 | private byte[] sentData = null; 46 | private int sentLen = 0; 47 | 48 | private int startErrorCode = 0; 49 | private final AtomicBoolean mRunning = new AtomicBoolean(false); 50 | 51 | public static final class Builder { 52 | 53 | private Proxy mProxy = null; 54 | private String mIp; //IP 55 | private int mPort; //端口 56 | private String mServant; 57 | private String mFunc; 58 | private int connectTimeout = 8000; 59 | private int readTimeout = 8000; 60 | private String transmit = "TCP"; 61 | 62 | public Builder setProxy(Proxy proxy) { 63 | this.mProxy = proxy; 64 | return this; 65 | } 66 | 67 | public Builder setIp(String ip) { 68 | this.mIp = ip; 69 | return this; 70 | } 71 | 72 | public Builder setPort(int port) { 73 | this.mPort = port; 74 | return this; 75 | } 76 | 77 | public Builder setServant(String servant) { 78 | this.mServant = servant; 79 | return this; 80 | } 81 | 82 | public Builder setFunc(String func) { 83 | this.mFunc = func; 84 | return this; 85 | } 86 | 87 | public Builder setConnectTimeout(int connectTimeout) { 88 | this.connectTimeout = connectTimeout; 89 | return this; 90 | } 91 | 92 | public Builder setReadTimeout(int readTimeout) { 93 | this.readTimeout = readTimeout; 94 | return this; 95 | } 96 | 97 | public Builder setTransmitType(String transmit) { 98 | this.transmit = transmit; 99 | return this; 100 | } 101 | 102 | public TupClient build() { 103 | TupClient client = new TupClient(); 104 | client.mProxy = this.mProxy; 105 | client.mIp = this.mIp; 106 | client.mPort = this.mPort; 107 | client.mServant = this.mServant; 108 | client.mFunc = this.mFunc; 109 | client.connectTimeout = this.connectTimeout; 110 | client.readTimeout = this.readTimeout; 111 | client.transmit = this.transmit; 112 | if (client.transmit.equals("TCP")) { 113 | client.session = new TcpSession(new IPEndPoint(client.mIp, client.mPort), client.mProxy); 114 | } else { 115 | client.session = new UdpSession(new IPEndPoint(client.mIp, client.mPort)); 116 | } 117 | client.session.setConnectTimeout(client.connectTimeout); 118 | client.session.setReadTimeout(client.readTimeout); 119 | return client; 120 | } 121 | } 122 | 123 | private TupClient() { 124 | } 125 | 126 | public void init() { 127 | if (mRunning.get()) { 128 | stop(); 129 | } 130 | if (!mRunning.get()) { 131 | session.setNetworkListener(this); 132 | startErrorCode = session.start(false); 133 | if (startErrorCode == ErrorCode.ERR_NONE) { 134 | mRunning.set(true); 135 | } 136 | } 137 | } 138 | 139 | public void stop() { 140 | if (!mRunning.get()) { 141 | return; 142 | } 143 | if (null != this.session) { 144 | session.stop(); 145 | } 146 | mRunning.set(false); 147 | } 148 | 149 | @Override 150 | public void sentBytesDispatch(int length, byte[] sentData) { 151 | this.sentLen = length; 152 | this.sentData = sentData; 153 | } 154 | 155 | @Override 156 | public void handleData(final byte[] data) { 157 | if (data == null) { 158 | return; 159 | } 160 | currentResp = TarsStructUtil.getTarsStruct(data, new ResponsePacket()); 161 | } 162 | 163 | public static TupClient.Builder builder() { 164 | return new Builder(); 165 | } 166 | 167 | private int sendRequestPacket(byte[] sbuffer) { 168 | RequestPacket requestPacket = new RequestPacket(); 169 | requestPacket.sServantName = this.mServant; 170 | requestPacket.sFuncName = this.mFunc; 171 | requestPacket.iMessageType = this.iMessageType; 172 | requestPacket.iRequestId = requestNo.get(); 173 | requestPacket.iVersion = this.iVersion; 174 | requestPacket.cPacketType = this.cPacketType; 175 | requestPacket.iTimeout = this.iTimeout; 176 | requestPacket.sBuffer = sbuffer; 177 | requestPacket.context = this.context; 178 | requestPacket.status = this.status; 179 | byte[] data = TarsStructUtil.tarsStructToUTF8ByteArray(requestPacket); 180 | return this.session.sendData(data); 181 | } 182 | 183 | public void setVersion(short iVersion) { 184 | this.iVersion = iVersion; 185 | } 186 | 187 | public void setPacketType(byte cPacketType) { 188 | this.cPacketType = cPacketType; 189 | } 190 | 191 | public void setMessageType(int iMessageType) { 192 | this.iMessageType = iMessageType; 193 | } 194 | 195 | public void setTimeout(int iTimeout) { 196 | this.iTimeout = iTimeout; 197 | } 198 | 199 | public void setContext(Map context) { 200 | this.context = context; 201 | } 202 | 203 | public void setStatus(Map status) { 204 | this.status = status; 205 | } 206 | 207 | public Map getContext() { 208 | return this.context; 209 | } 210 | 211 | public Map getStatus() { 212 | return this.status; 213 | } 214 | 215 | public int invokeMethod(ServantInvokeContext context) { 216 | int localErrorCode = ErrorCode.ERR_NONE; 217 | if (startErrorCode != 0) { 218 | //如果网络初始化失败,不用往下走了,直接分发错误码上去 219 | return startErrorCode; 220 | } 221 | requestNo.addAndGet(1); 222 | ByteBuffer bf = TupUtil.paramsToJceStream(context.getArgumentValues()); 223 | localErrorCode += this.sendRequestPacket(bf.array()); 224 | if (localErrorCode != ErrorCode.ERR_NONE) { 225 | context.setSendBytes(0); 226 | return localErrorCode; 227 | } 228 | ResponsePacket responsePacket = currentResp; 229 | context.setSendBytes(this.sentLen); 230 | if (responsePacket == null) { 231 | localErrorCode += ErrorCode.ERR_TUP_RESPONSE_BODY_EMPTY; 232 | return localErrorCode; 233 | } else if (responsePacket.iRequestId != requestNo.get()) { 234 | localErrorCode += ErrorCode.ERR_TUP_REQUEST_SEQ_NOT_MATCH; 235 | return localErrorCode; 236 | } else { 237 | //数据返回码不为0的时候,也有可能有数据需要透传上去 238 | if (responsePacket.iRet != 0) { 239 | localErrorCode += responsePacket.iRet; 240 | } 241 | try { 242 | context.setStatus(responsePacket.status); 243 | TupUtil.parseTarsStream(responsePacket.SBuffer, context); 244 | } catch (Exception e) { 245 | localErrorCode += ErrorCode.ERR_TUP_RESPONSE_DECODE; 246 | } 247 | } 248 | return localErrorCode; 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/json/JsonStreamUtil.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.protocol.json; 2 | 3 | import com.google.gson.*; 4 | import com.tencent.tars.protocol.JsonConst; 5 | import com.tencent.tars.protocol.exceptions.JsonDecodeException; 6 | import com.tencent.tars.protocol.TarsStructUtil; 7 | import com.tencent.tars.protocol.tars.TarsStructBase; 8 | 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.Map; 12 | 13 | public class JsonStreamUtil { 14 | /** 15 | * 把JceStruct按模板录制成json数据 16 | * @param base 数据对象 17 | * @param template json模板 18 | * @return 填充有实际对象的json格式数据 19 | */ 20 | public static JsonObject getJsonForTars(TarsStructBase base, JsonObject template){ 21 | byte[] requestData = TarsStructUtil.tarsStructToUTF8ByteArray(base); 22 | return new JsonInputStream(requestData).read(template); 23 | } 24 | 25 | public static String toPrettyFormat(JsonObject jsonObject) { 26 | Gson gson = new GsonBuilder().setPrettyPrinting().create(); 27 | return gson.toJson(jsonObject); 28 | } 29 | 30 | public static String toPrettyFormat(Map maoObject) { 31 | Gson gson = new GsonBuilder().setPrettyPrinting().create(); 32 | return gson.toJson(maoObject,Map.class); 33 | } 34 | 35 | static String getType(JsonObject object) { 36 | if (object == null) { 37 | throw new JsonDecodeException("get type error: jsonObject is null"); 38 | } 39 | if (object.get(JsonConst.KEY_TYPE) == null) { 40 | throw new JsonDecodeException("get type is null:" + object.toString()); 41 | } 42 | String type = object.get(JsonConst.KEY_TYPE).getAsString(); 43 | if (type == null || type.isEmpty()) { 44 | throw new JsonDecodeException("get type is null:" + object.toString()); 45 | } 46 | return type; 47 | } 48 | 49 | static int getTag(JsonObject object) { 50 | if (object == null) { 51 | throw new JsonDecodeException("get tag error: jsonObject is null"); 52 | } 53 | if (object.get(JsonConst.KEY_TAG) == null) { 54 | throw new JsonDecodeException("get tag is null:" + object.toString()); 55 | } 56 | JsonElement tagElement = object.get(JsonConst.KEY_TAG); 57 | 58 | int tag = tagElement.getAsInt(); 59 | if (tag < 0) { 60 | throw new JsonDecodeException("get tag error, tag==" + tag + " , jsonObject:" + object.toString()); 61 | } 62 | return tag; 63 | } 64 | 65 | static JsonElement getKey(JsonObject object){ 66 | if (object == null) { 67 | throw new JsonDecodeException("get map key error: jsonObject is null"); 68 | } 69 | JsonElement element = object.get(JsonConst.KEY_MAP_KEY); 70 | if (element == null) { 71 | throw new JsonDecodeException("get map key is null:" + object.toString()); 72 | } 73 | return element; 74 | } 75 | 76 | static JsonElement getValue(JsonObject object) { 77 | if (object == null) { 78 | throw new JsonDecodeException("get value error: jsonObject is null"); 79 | } 80 | JsonElement element = object.get(JsonConst.KEY_VALUE); 81 | if (element == null) { 82 | throw new JsonDecodeException("get value is null:" + object.toString()); 83 | } 84 | return element; 85 | } 86 | 87 | static boolean isVector(JsonObject object) { 88 | return JsonConst.VECTOR.equalsIgnoreCase(getType(object)); 89 | } 90 | 91 | static boolean isMap(JsonObject object) { 92 | return JsonConst.MAP.equalsIgnoreCase(getType(object)); 93 | } 94 | 95 | static boolean isCustom(JsonObject object) { 96 | return JsonConst.TARS.equalsIgnoreCase(getType(object)); 97 | } 98 | 99 | static boolean isPrimitive(JsonObject object) { 100 | String type = getType(object); 101 | return JsonConst.BOOLEAN.equalsIgnoreCase(type) 102 | || JsonConst.INT.equalsIgnoreCase(type) 103 | || JsonConst.SHORT.equalsIgnoreCase(type) 104 | || JsonConst.LONG.equalsIgnoreCase(type) 105 | || JsonConst.FLOAT.equalsIgnoreCase(type) 106 | || JsonConst.DOUBLE.equalsIgnoreCase(type) 107 | || JsonConst.BYTE.equalsIgnoreCase(type) 108 | || JsonConst.STRING.equalsIgnoreCase(type) 109 | || JsonConst.BOOLEAN_VEC.equalsIgnoreCase(type) 110 | || JsonConst.INT_VEC.equalsIgnoreCase(type) 111 | || JsonConst.SHORT_VEC.equalsIgnoreCase(type) 112 | || JsonConst.LONG_VEC.equalsIgnoreCase(type) 113 | || JsonConst.FLOAT_VEC.equalsIgnoreCase(type) 114 | || JsonConst.DOUBLE_VEC.equalsIgnoreCase(type) 115 | || JsonConst.BYTE_VEC.equalsIgnoreCase(type) 116 | || JsonConst.STRING_VEC.equalsIgnoreCase(type); 117 | } 118 | 119 | static T[] jsonToArray(JsonElement element, Class clazz) { 120 | Gson gson = new Gson(); 121 | return gson.fromJson(element, clazz); 122 | } 123 | 124 | public static JsonObject getDoubleValue(double value) { 125 | JsonObject ret = new JsonObject(); 126 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.DOUBLE); 127 | ret.addProperty(JsonConst.KEY_VALUE, value); 128 | return ret; 129 | } 130 | 131 | public static JsonObject getDoubleVectorValue(double[] value) { 132 | JsonObject ret = new JsonObject(); 133 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.DOUBLE_VEC); 134 | ret.add(JsonConst.KEY_VALUE, JsonParser.parseString(new Gson().toJson(Collections.singletonList(value))).getAsJsonArray()); 135 | return ret; 136 | } 137 | 138 | public static JsonObject getFloatValue(float value) { 139 | JsonObject ret = new JsonObject(); 140 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.FLOAT); 141 | ret.addProperty(JsonConst.KEY_VALUE, value); 142 | return ret; 143 | } 144 | 145 | public static JsonObject getFloatVectorValue(float[] value) { 146 | JsonObject ret = new JsonObject(); 147 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.FLOAT_VEC); 148 | ret.add(JsonConst.KEY_VALUE,JsonParser.parseString(new Gson().toJson(Collections.singletonList(value))).getAsJsonArray()); 149 | return ret; 150 | } 151 | 152 | 153 | public static JsonObject getLongValue(long value) { 154 | JsonObject ret = new JsonObject(); 155 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.LONG); 156 | ret.addProperty(JsonConst.KEY_VALUE, value); 157 | return ret; 158 | } 159 | 160 | public static JsonObject getLongVectorValue(long[] value) { 161 | JsonObject ret = new JsonObject(); 162 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.LONG_VEC); 163 | ret.add(JsonConst.KEY_VALUE,JsonParser.parseString(new Gson().toJson(Collections.singletonList(value))).getAsJsonArray()); 164 | return ret; 165 | } 166 | 167 | public static JsonObject getShortValue(short value) { 168 | JsonObject ret = new JsonObject(); 169 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.SHORT); 170 | ret.addProperty(JsonConst.KEY_VALUE, value); 171 | return ret; 172 | } 173 | 174 | public static JsonObject getShortVectorValue(short[] value) { 175 | JsonObject ret = new JsonObject(); 176 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.SHORT_VEC); 177 | ret.add(JsonConst.KEY_VALUE,JsonParser.parseString(new Gson().toJson(Collections.singletonList(value))).getAsJsonArray()); 178 | return ret; 179 | } 180 | 181 | public static JsonObject getByteValue(byte value) { 182 | JsonObject ret = new JsonObject(); 183 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.BYTE); 184 | ret.addProperty(JsonConst.KEY_VALUE, value); 185 | return ret; 186 | } 187 | 188 | public static JsonObject getByteVectorValue(byte[] value) { 189 | JsonObject ret = new JsonObject(); 190 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.BYTE_VEC); 191 | ret.add(JsonConst.KEY_VALUE,JsonParser.parseString(new Gson().toJson(Collections.singletonList(value))).getAsJsonArray()); 192 | return ret; 193 | } 194 | 195 | public static JsonObject getBoolValue(boolean value) { 196 | JsonObject ret = new JsonObject(); 197 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.BOOLEAN); 198 | ret.addProperty(JsonConst.KEY_VALUE, value); 199 | return ret; 200 | } 201 | 202 | public static JsonObject getBoolVectorValue(boolean[] value) { 203 | JsonObject ret = new JsonObject(); 204 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.BOOLEAN_VEC); 205 | ret.add(JsonConst.KEY_VALUE,JsonParser.parseString(new Gson().toJson(Collections.singletonList(value))).getAsJsonArray()); 206 | return ret; 207 | } 208 | 209 | public static JsonObject getIntValue(int value) { 210 | JsonObject ret = new JsonObject(); 211 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.INT); 212 | ret.addProperty(JsonConst.KEY_VALUE, value); 213 | return ret; 214 | } 215 | 216 | public static JsonObject getTarsValue(JsonObject value) { 217 | JsonObject ret = new JsonObject(); 218 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.TARS); 219 | ret.add(JsonConst.KEY_VALUE, value); 220 | return ret; 221 | } 222 | 223 | public static JsonObject getIntVectorValue(int[] value) { 224 | JsonObject ret = new JsonObject(); 225 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.INT_VEC); 226 | ret.add(JsonConst.KEY_VALUE,JsonParser.parseString(new Gson().toJson(Collections.singletonList(value))).getAsJsonArray()); 227 | return ret; 228 | } 229 | 230 | public static JsonObject getStringValue(String value) { 231 | JsonObject ret = new JsonObject(); 232 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.STRING); 233 | ret.addProperty(JsonConst.KEY_VALUE, value); 234 | return ret; 235 | } 236 | 237 | public static JsonObject getStringVectorValue(String[] value) { 238 | JsonObject ret = new JsonObject(); 239 | ret.addProperty(JsonConst.KEY_TYPE, JsonConst.STRING_VEC); 240 | ret.add(JsonConst.KEY_VALUE, JsonParser.parseString(new Gson().toJson(Arrays.asList(value))).getAsJsonArray()); 241 | return ret; 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/jmeter/gui/GenralTarsConfigGui.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.jmeter.gui; 2 | 3 | import com.tencent.tars.jmeter.constants.ITarsConst; 4 | import com.tencent.tars.jmeter.gui.widgets.*; 5 | import com.tencent.tars.jmeter.sampler.TarsSamplerBase; 6 | import com.tencent.tars.protocol.JsonConst; 7 | import org.apache.jmeter.config.Arguments; 8 | import org.apache.jmeter.gui.util.HorizontalPanel; 9 | import org.apache.jmeter.gui.util.VerticalPanel; 10 | import org.apache.jmeter.testelement.TestElement; 11 | import org.apache.jorphan.gui.JLabeledTextField; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import javax.swing.*; 16 | import java.awt.*; 17 | import java.awt.event.ItemEvent; 18 | 19 | /** 20 | * JMeter Tars协议测试 采样器UI 21 | * 22 | * @author brookechen 23 | */ 24 | public class GenralTarsConfigGui extends JPanel { 25 | private static final Logger log = LoggerFactory.getLogger(GenralTarsConfigGui.class); 26 | 27 | private static final int TAB_TARS_PARAMETERS = 0; 28 | private static final int TAB_EXTRA_PARAMETERS = 1; 29 | 30 | private static final int PROTOCOL_TCP_INDEX = 0; 31 | private static final int PROTOCOL_UDP_INDEX = 1; 32 | 33 | private JLabeledTextField ip; 34 | private JLabeledTextField port; 35 | private JComboBox protocol; 36 | 37 | private JLabeledTextField servantName; 38 | private JLabeledTextField funcName; 39 | private JTypeComboBox retTypeComboBox; 40 | 41 | private JPanel returnValuePanel; 42 | private JLabeledTextField returnValueView; 43 | private JButton tars2json; 44 | 45 | private JTabbedPane contentTabbedPane; 46 | // Body request data 47 | private FuncParameterPanel requestParameterPanel; 48 | private ExtraArgumentsPanel tarsArgsPanel; 49 | 50 | private MapArgPanel contextArgsPanel; 51 | private MapArgPanel statusArgPanel; 52 | 53 | public GenralTarsConfigGui() { 54 | init(); 55 | } 56 | 57 | 58 | protected final JPanel getHeaderPanel() { 59 | JPanel headerPane = new VerticalPanel(); 60 | headerPane.add(getAddressingPanel()); 61 | headerPane.add(getTarsServantPanel()); 62 | headerPane.add(getReturnValuePanel()); 63 | return headerPane; 64 | } 65 | 66 | //寻址 67 | protected final JPanel getAddressingPanel() { 68 | ip = new JLabeledTextField(CustomResUtils.getResString("tars.addressing.ip"), 20); 69 | port = new JLabeledTextField(CustomResUtils.getResString("tars.addressing.port"), 10); 70 | JLabel label = new JLabel(CustomResUtils.getResString("tars.addressing.protocol")); 71 | protocol = new JComboBox<>(); // $NON-NLS-1$ 72 | protocol.addItem(ITarsConst.TCP); 73 | protocol.addItem(ITarsConst.UDP); 74 | protocol.setSelectedIndex(PROTOCOL_TCP_INDEX); 75 | 76 | JPanel addressingPane = new HorizontalPanel(); 77 | addressingPane.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder())); // $NON-NLS-1$ 78 | addressingPane.add(ip); 79 | addressingPane.add(port); 80 | addressingPane.add(label); 81 | addressingPane.add(protocol); 82 | return addressingPane; 83 | } 84 | 85 | //服务名 86 | protected final JPanel getTarsServantPanel() { 87 | servantName = new JLabeledTextField(CustomResUtils.getResString("tars.servant.path"), 20); // $NON-NLS-1$ 88 | funcName = new JLabeledTextField(CustomResUtils.getResString("tars.func.name"), 10); // $NON-NLS-1$ 89 | JLabel label = new JLabel(CustomResUtils.getResString("tars.retval.type")); 90 | retTypeComboBox = new JTypeComboBox(true); // $NON-NLS-1$ 91 | 92 | JPanel tarsPanel = new HorizontalPanel(); 93 | tarsPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder())); // $NON-NLS-1$ 94 | tarsPanel.add(servantName); 95 | tarsPanel.add(funcName); 96 | tarsPanel.add(label); 97 | tarsPanel.add(retTypeComboBox); 98 | return tarsPanel; 99 | } 100 | 101 | protected final JPanel getReturnValuePanel() { 102 | returnValuePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); 103 | returnValueView = new JLabeledTextField(CustomResUtils.getResString("tars.retval.content"), 30); // $NON-NLS-1$ 104 | tars2json = new JButton("tars2json"); 105 | returnValuePanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder())); // $NON-NLS-1$ 106 | returnValuePanel.add(tars2json, FlowLayout.LEFT); 107 | returnValuePanel.add(returnValueView, FlowLayout.LEFT); 108 | returnValuePanel.setVisible(false); 109 | return returnValuePanel; 110 | } 111 | 112 | protected final void initBehavior() { 113 | retTypeComboBox.addItemListener(e -> { 114 | if (e.getStateChange() != ItemEvent.SELECTED) { 115 | return; 116 | } 117 | if (JsonConst.TARS.equals(e.getItem().toString())) { 118 | returnValuePanel.setVisible(true); 119 | } else { 120 | returnValuePanel.setVisible(false); 121 | returnValueView.setText(""); 122 | } 123 | }); 124 | tars2json.addActionListener(e -> { 125 | Tars2JsonDialog tars2JsonDialog = new Tars2JsonDialog(returnValueView); 126 | tars2JsonDialog.setVisible(true); 127 | }); 128 | 129 | } 130 | 131 | protected final JTabbedPane getContentPanel() { 132 | contentTabbedPane = new JTabbedPane(); 133 | tarsArgsPanel = new ExtraArgumentsPanel(); 134 | requestParameterPanel = new FuncParameterPanel(CustomResUtils.getResString("tars.request.parameter")); 135 | contentTabbedPane.add(CustomResUtils.getResString("tars.request.parameter"), requestParameterPanel);// $NON-NLS-1$ 136 | contentTabbedPane.add(CustomResUtils.getResString("tars.param.extra.title"), tarsArgsPanel);// $NON-NLS-1$ 137 | 138 | contextArgsPanel = new MapArgPanel(CustomResUtils.getResString("tars.tup.req.context")); 139 | statusArgPanel = new MapArgPanel(CustomResUtils.getResString("tars.tup.req.status")); 140 | contentTabbedPane.add(CustomResUtils.getResString("tars.tup.req.context"), contextArgsPanel);// $NON-NLS-1$ 141 | contentTabbedPane.add(CustomResUtils.getResString("tars.tup.req.status"), statusArgPanel);// $NON-NLS-1$ 142 | 143 | contentTabbedPane.setSelectedIndex(TAB_TARS_PARAMETERS); 144 | return contentTabbedPane; 145 | } 146 | 147 | private void init() { 148 | this.setLayout(new BorderLayout()); 149 | JPanel sharkRequestPanel = new VerticalPanel(); 150 | sharkRequestPanel.setLayout(new BorderLayout()); 151 | sharkRequestPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), 152 | CustomResUtils.getResString("tars.header.title"))); // $NON-NLS-1$ 153 | sharkRequestPanel.add(getHeaderPanel(), BorderLayout.NORTH); 154 | sharkRequestPanel.add(getContentPanel(), BorderLayout.CENTER); 155 | initBehavior(); 156 | this.add(sharkRequestPanel, BorderLayout.CENTER); 157 | } 158 | 159 | /** 160 | * Set the text, etc. in the UI. 161 | */ 162 | public void configure(TestElement el) { 163 | setName(el.getName()); 164 | ip.setText(el.getPropertyAsString(ITarsConst.SERVANT_IP)); 165 | port.setText(el.getPropertyAsString(ITarsConst.SERVANT_PORT)); 166 | if (ITarsConst.TCP.equalsIgnoreCase(el.getPropertyAsString(ITarsConst.SERVANT_PROTOCOL))) { 167 | protocol.setSelectedIndex(PROTOCOL_TCP_INDEX); 168 | } else { 169 | protocol.setSelectedIndex(PROTOCOL_UDP_INDEX); 170 | } 171 | servantName.setText(el.getPropertyAsString(ITarsConst.SERVANT_PATH)); 172 | funcName.setText(el.getPropertyAsString(ITarsConst.FUNC_NAME)); 173 | retTypeComboBox.setSelectedItem(el.getPropertyAsString(ITarsConst.TARS_RETURN_TYPE)); 174 | returnValueView.setText(el.getPropertyAsString(ITarsConst.TARS_RETURN_VALUE)); 175 | Arguments funcParam = (Arguments) el.getProperty(ITarsConst.FUNC_ARGUMENTS).getObjectValue(); 176 | if (funcParam != null) { 177 | requestParameterPanel.configure(funcParam); 178 | } 179 | Arguments arguments = (Arguments) el.getProperty(ITarsConst.ARGUMENTS).getObjectValue(); 180 | if (arguments != null) { 181 | tarsArgsPanel.configure(arguments); 182 | } 183 | Arguments contextArgs = (Arguments) el.getProperty(ITarsConst.CONTEXT_ARGUMENTS).getObjectValue(); 184 | if (contextArgs != null) { 185 | contextArgsPanel.configure(contextArgs); 186 | } 187 | Arguments statusArgs = (Arguments) el.getProperty(ITarsConst.STATUS_ARGUMENTS).getObjectValue(); 188 | if (statusArgs != null) { 189 | statusArgPanel.configure(statusArgs); 190 | } 191 | } 192 | 193 | /** 194 | * Save the GUI values in the sampler. 195 | */ 196 | public void modifyTestElement(TestElement element) { 197 | TarsSamplerBase sampler = (TarsSamplerBase) element; 198 | sampler.setServantIp(ip.getText()); 199 | sampler.setServantPort(port.getText()); 200 | sampler.setTransmitType((String) protocol.getSelectedItem()); 201 | sampler.setServantPath(servantName.getText()); 202 | sampler.setFuncName(funcName.getText()); 203 | if (retTypeComboBox.getSelectedItem() != null) { 204 | sampler.setReturnType(retTypeComboBox.getSelectedItem().toString()); 205 | sampler.setReturnValue(returnValueView.getText()); 206 | } 207 | 208 | Arguments args = (Arguments) tarsArgsPanel.createTestElement(); 209 | sampler.setArguments(args); 210 | Arguments dataArgs = (Arguments) requestParameterPanel.createTestElement(); 211 | sampler.setDataArguments(dataArgs); 212 | Arguments contextArgs = (Arguments) contextArgsPanel.createTestElement(); 213 | sampler.setContextArguments(contextArgs); 214 | Arguments statusArgs = (Arguments) statusArgPanel.createTestElement(); 215 | sampler.setStatusArguments(statusArgs); 216 | } 217 | 218 | 219 | public void clear() { 220 | servantName.setText(""); 221 | funcName.setText(""); 222 | protocol.setSelectedIndex(PROTOCOL_TCP_INDEX); 223 | retTypeComboBox.setSelectedItem(JsonConst.INT); 224 | tarsArgsPanel.clear(); 225 | requestParameterPanel.clear(); 226 | contextArgsPanel.clear(); 227 | statusArgPanel.clear(); 228 | contentTabbedPane.setSelectedIndex(TAB_TARS_PARAMETERS); 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/utils/ErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.tencent.tars.utils; 2 | 3 | /** 4 | * 错误码归拢 5 | * 6 | * @author brookechen 7 | */ 8 | public class ErrorCode { 9 | /** 10 | * no error. 11 | */ 12 | public static final int ERR_NONE = 0; 13 | 14 | /** 15 | * 获取拼装错误的信息 16 | */ 17 | public static String getErrMessage(int errorCode) { 18 | return getNetError(errorCode) 19 | + getTupError(errorCode) 20 | + getJMeterError(errorCode) 21 | + getServerError(errorCode); 22 | } 23 | 24 | /** 25 | * Tars retCode error. 26 | * -(1~99) 27 | */ 28 | public final static int SERVERDECODEERR = -1; 29 | 30 | public final static int SERVERENCODEERR = -2; 31 | 32 | public final static int SERVERNOFUNCERR = -3; 33 | 34 | public final static int SERVERNOSERVANTERR = -4; 35 | 36 | public final static int SERVERRESETGRID = -5; 37 | 38 | public final static int SERVERQUEUETIMEOUT = -6; 39 | 40 | public final static int ASYNCCALLTIMEOUT = -7; 41 | 42 | public final static int PROXYCONNECTERR = -8; 43 | 44 | public static final int SERVEROVERLOAD = -9; 45 | 46 | public final static int SERVERUNKNOWNERR = -99; 47 | 48 | 49 | public static String getServerError(int localError) { 50 | int serverError = filterServerErrCode(localError); 51 | switch (serverError) { 52 | case ERR_NONE: 53 | return ""; 54 | case SERVERDECODEERR: 55 | return "Server decode error."; 56 | case SERVERENCODEERR: 57 | return "Server encode error."; 58 | case SERVERNOFUNCERR: 59 | return "Server no function error."; 60 | case SERVERNOSERVANTERR: 61 | return "Server not servant error."; 62 | case SERVERRESETGRID: 63 | return "Server error set grid."; 64 | case SERVERQUEUETIMEOUT: 65 | return "server queue timeout."; 66 | case ASYNCCALLTIMEOUT: 67 | return "async call timeout."; 68 | case PROXYCONNECTERR: 69 | return "proxy connect error."; 70 | case SERVEROVERLOAD: 71 | return "server overload."; 72 | case SERVERUNKNOWNERR: 73 | default: 74 | return "Server unknown code:" + serverError + "."; 75 | } 76 | } 77 | 78 | /** 79 | * jmeter层错误码 80 | * -(1~99)*100 81 | */ 82 | private static final int ERROR_JMETER_BASE = 100; 83 | 84 | public static final int ErrorProxyException = -1 * ERROR_JMETER_BASE; 85 | public static final int ErrorTarsException = -2 * ERROR_JMETER_BASE; 86 | public static final int ErrorSampleBaseException = -3 * ERROR_JMETER_BASE; 87 | public static final int ErrorPrepareNetwork = -4 * ERROR_JMETER_BASE; 88 | public static final int ErrorStopNetwork = -5 * ERROR_JMETER_BASE; 89 | public static final int ERROR_JMETER_UNKNOWN = -99 * ERROR_JMETER_BASE; 90 | 91 | 92 | public static String getJMeterError(int localError) { 93 | int jMeterError = filterJMeterErrCode(localError); 94 | switch (jMeterError) { 95 | case ERR_NONE: 96 | return ""; 97 | case ErrorProxyException: 98 | return "JMeter ErrorProxyException, "; 99 | case ErrorTarsException: 100 | return "JMeter ErrorTarsException, "; 101 | case ErrorSampleBaseException: 102 | return "JMeter ErrorSampleBaseException, "; 103 | case ErrorPrepareNetwork: 104 | return "JMeter ErrorPrepareNetwork, "; 105 | case ErrorStopNetwork: 106 | return "JMeter ErrorStopNetwork, "; 107 | case ERROR_JMETER_UNKNOWN: 108 | default: 109 | return "JMeter unknown code:" + jMeterError + ", "; 110 | } 111 | } 112 | 113 | 114 | /** 115 | * tup层错误码 116 | * -(1~99)*10000 117 | */ 118 | private static final int ERROR_TUP_BASE = 10000; 119 | public static final int ERR_TUP_RESPONSE_BODY_EMPTY = -1 * ERROR_TUP_BASE; 120 | public static final int ERR_TUP_RESPONSE_DECODE = -2 * ERROR_TUP_BASE; 121 | public static final int ERR_TUP_REQUEST_SEQ_NOT_MATCH = -3 * ERROR_TUP_BASE; 122 | public static final int ERR_TUP_UNKNOWN = -99 * ERROR_TUP_BASE; 123 | 124 | 125 | public static String getTupError(int localErr) { 126 | int tupError = filterTupErrCode(localErr); 127 | switch (tupError) { 128 | case ERR_NONE: 129 | return ""; 130 | case ERR_TUP_RESPONSE_BODY_EMPTY: 131 | return "TUP ERR_TUP_RESPONSE_BODY_EMPTY, "; 132 | case ERR_TUP_RESPONSE_DECODE: 133 | return "TUP ERR_TUP_RESPONSE_DECODE, "; 134 | case ERR_TUP_REQUEST_SEQ_NOT_MATCH: 135 | return "TUP ERR_TUP_REQUEST_SEQ_NOT_MATCH, "; 136 | case ERR_TUP_UNKNOWN: 137 | default: 138 | return "Tup unknown code:" + tupError + ", "; 139 | } 140 | } 141 | 142 | /** 143 | * 网络层错误码 144 | * -(1~99)*1000000 145 | */ 146 | private static final int ERROR_NETWORK_BASE = 1000000; 147 | 148 | public static final int ERR_NETWORK_TCP_CHECK_SOCKET_TIMEOUT_FAILED = -1 * ERROR_NETWORK_BASE; // tcp check socket timeout 149 | public static final int ERR_NETWORK_UNKNOWN_HOST_EXCEPTION = -2 * ERROR_NETWORK_BASE; // 未知主机 150 | public static final int ERR_NETWORK_SOCKET_TIMEOUT_EXCEPTION_RW = -3 * ERROR_NETWORK_BASE; // 读写时的socket超时(业务数据可能已经到了后台) 151 | public static final int ERR_NETWORK_EXCEPTION = -4 * ERROR_NETWORK_BASE; // 其他网络 异常 152 | public static final int ERR_NETWORK_SOCKET_NOT_CONNECTED = -5 * ERROR_NETWORK_BASE; // socket未连接(一般不会出现) 153 | public static final int ERR_NETWORK_CLOSE_FAILED = -6 * ERROR_NETWORK_BASE; // 关闭连接失败 154 | public static final int ERR_NETWORK_ILLEGAL_ARGUMENT = -7 * ERROR_NETWORK_BASE; // 非法参数 155 | public static final int ERR_NETWORK_TCP_RECV_EOF = -8 * ERROR_NETWORK_BASE; // 回包读取EOF 156 | public static final int ERR_NETWORK_TCP_RECV_IOE = -9 * ERROR_NETWORK_BASE; // 回包read IOE 157 | public static final int ERR_NETWORK_TCP_RECV_THROWABLE = -10 * ERROR_NETWORK_BASE; // 回包读取时,抛出异常 158 | public static final int ERR_NETWORK_RECV_NULL = -11 * ERROR_NETWORK_BASE; // 回包读取时,resp为空 159 | public static final int ERR_NETWORK_RECV_0 = -12 * ERROR_NETWORK_BASE; // 回包读取时,读到0 160 | public static final int ERR_NETWORK_START_THROWABLE = -13 * ERROR_NETWORK_BASE; // 连接网络时throwable 161 | public static final int ERR_NETWORK_START_UNKNOWN = -14 * ERROR_NETWORK_BASE; // 连接网络时throwable 162 | public static final int ERR_NETWORK_UDP_RECV_EOF = -15 * ERROR_NETWORK_BASE; // UDP接收报文存贮大小不够 163 | public static final int ERR_NETWORK_UDP_RECV_IOE = -16 * ERROR_NETWORK_BASE; // 回包read IOE 164 | public static final int ERR_NETWORK_UDP_RECV_THROWABLE = -17 * ERROR_NETWORK_BASE; // 回包读取时,抛出异常 165 | public static final int ERR_NETWORK_UNKNOWN = -99 * ERROR_NETWORK_BASE; 166 | 167 | 168 | public static String getNetError(int localErr) { 169 | int netErr = filterNetworkCode(localErr); 170 | switch (netErr) { 171 | case ERR_NONE: 172 | return ""; 173 | case ERR_NETWORK_TCP_CHECK_SOCKET_TIMEOUT_FAILED: //-30000; // tcp check socket timeout 174 | return "NetErr: tcp check socket timeout, "; 175 | case ERR_NETWORK_UNKNOWN_HOST_EXCEPTION: //-70000; // 未知主机 176 | return "NetErr: unknown host, "; 177 | case ERR_NETWORK_SOCKET_TIMEOUT_EXCEPTION_RW: //-120000; // 读写时的socket超时(业务数据可能已经到了后台) 178 | return "NetErr: read socket timeout, "; 179 | case ERR_NETWORK_EXCEPTION: //-150000; // 其他网络异常 180 | return "NetErr: other network exception, "; 181 | case ERR_NETWORK_SOCKET_NOT_CONNECTED: //-180000; // socket未连接(一般不会出现) 182 | return "NetErr: socket not connected, "; 183 | case ERR_NETWORK_CLOSE_FAILED: //-210000; // 关闭连接失败 184 | return "NetErr: network close fail, "; 185 | case ERR_NETWORK_ILLEGAL_ARGUMENT: //-240000; // 非法参数 186 | return "NetErr: network illegal argument, "; 187 | case ERR_NETWORK_TCP_RECV_EOF: //-560000; // 回包读取EOF 188 | return "NetErr: tcp recv eof, "; 189 | case ERR_NETWORK_TCP_RECV_IOE: //-570000; // 回包read IOE 190 | return "NetErr: tcp recv ioe, "; 191 | case ERR_NETWORK_TCP_RECV_THROWABLE: //-580000; // 回包读取时,抛出异常 192 | return "NetErr: tcp recv throwable, "; 193 | case ERR_NETWORK_RECV_NULL: //-590000; // 回包读取时,resp为空 194 | return "NetErr: network recv null, "; 195 | case ERR_NETWORK_RECV_0: //-600000; // 回包读取时,读到0 196 | return "NetErr: network recv 0 size, "; 197 | case ERR_NETWORK_START_THROWABLE: 198 | return "NetErr: check socket throwable, "; 199 | case ERR_NETWORK_START_UNKNOWN: 200 | return "NetErr: start socket unknown error, "; 201 | case ERR_NETWORK_UDP_RECV_EOF: 202 | return "NetErr: udp recv iod, "; 203 | case ERR_NETWORK_UDP_RECV_IOE: 204 | return "NetErr: udp recv ioe, "; 205 | case ERR_NETWORK_UDP_RECV_THROWABLE: 206 | return "NetErr: udp recv throwable, "; 207 | case ERR_NETWORK_UNKNOWN: 208 | default: 209 | return "Network unknown code:" + netErr; 210 | } 211 | } 212 | 213 | public static int filterServerErrCode(final int retCode) { 214 | return (retCode % ERROR_JMETER_BASE); 215 | 216 | } 217 | 218 | /** 219 | * 获取jmeter层错误码 220 | */ 221 | public static int filterJMeterErrCode(final int retCode) { 222 | return (retCode % ERROR_TUP_BASE) - filterServerErrCode(retCode); 223 | } 224 | 225 | /** 226 | * 获得tup层错误码 227 | */ 228 | public static int filterTupErrCode(final int retCode) { 229 | return (retCode % ERROR_NETWORK_BASE) - filterJMeterErrCode(retCode) - filterServerErrCode(retCode); 230 | } 231 | 232 | 233 | /** 234 | * 获得网络错误码 235 | */ 236 | public static int filterNetworkCode(final int retCode) { 237 | return (retCode % 100000000) - filterTupErrCode(retCode) - filterJMeterErrCode(retCode) - filterServerErrCode(retCode); 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /src/main/java/com/tencent/tars/protocol/tars/TarsOutputStream.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Tencent is pleased to support the open source community by making Tars available. 3 | *

4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 5 | *

6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | *

9 | * https://opensource.org/licenses/BSD-3-Clause 10 | *

11 | * Unless required by applicable law or agreed to in writing, software distributed 12 | * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations under the License. 15 | */ 16 | 17 | package com.tencent.tars.protocol.tars; 18 | 19 | import com.tencent.tars.protocol.exceptions.TarsEncodeException; 20 | import com.tencent.tars.utils.HexUtil; 21 | 22 | import java.io.UnsupportedEncodingException; 23 | import java.nio.ByteBuffer; 24 | import java.util.Collection; 25 | import java.util.List; 26 | import java.util.Map; 27 | 28 | public class TarsOutputStream { 29 | 30 | private ByteBuffer bs; 31 | 32 | public TarsOutputStream(ByteBuffer bs) { 33 | this.bs = bs; 34 | } 35 | 36 | public TarsOutputStream(int capacity) { 37 | bs = ByteBuffer.allocate(capacity); 38 | } 39 | 40 | public TarsOutputStream() { 41 | this(128); 42 | } 43 | 44 | public ByteBuffer getByteBuffer() { 45 | return bs; 46 | } 47 | 48 | public byte[] toByteArray() { 49 | byte[] newBytes = new byte[bs.position()]; 50 | System.arraycopy(bs.array(), 0, newBytes, 0, bs.position()); 51 | return newBytes; 52 | } 53 | 54 | public void reserve(int len) { 55 | if (bs.remaining() < len) { 56 | int n = (bs.capacity() + len) * 2; 57 | ByteBuffer bs2 = ByteBuffer.allocate(n); 58 | bs2.put(bs.array(), 0, bs.position()); 59 | bs = bs2; 60 | bs2 = null; 61 | } 62 | } 63 | 64 | public void writeHead(byte type, int tag) { 65 | if (tag < 15) { 66 | byte b = (byte) ((tag << 4) | type); 67 | bs.put(b); 68 | } else if (tag < 256) { 69 | byte b = (byte) ((15 << 4) | type); 70 | bs.put(b); 71 | bs.put((byte) tag); 72 | } else { 73 | throw new TarsEncodeException("tag is too large: " + tag); 74 | } 75 | } 76 | 77 | public void write(boolean b, int tag) { 78 | byte by = (byte) (b ? 0x01 : 0); 79 | write(by, tag); 80 | } 81 | 82 | public void write(byte b, int tag) { 83 | reserve(3); 84 | if (b == 0) { 85 | writeHead(TarsStructBase.ZERO_TAG, tag); 86 | } else { 87 | writeHead(TarsStructBase.BYTE, tag); 88 | bs.put(b); 89 | } 90 | } 91 | 92 | public void write(short n, int tag) { 93 | reserve(4); 94 | if (n >= Byte.MIN_VALUE && n <= Byte.MAX_VALUE) { 95 | write((byte) n, tag); 96 | } else { 97 | writeHead(TarsStructBase.SHORT, tag); 98 | bs.putShort(n); 99 | } 100 | } 101 | 102 | public void write(int n, int tag) { 103 | reserve(6); 104 | if (n >= Short.MIN_VALUE && n <= Short.MAX_VALUE) { 105 | write((short) n, tag); 106 | } else { 107 | writeHead(TarsStructBase.INT, tag); 108 | bs.putInt(n); 109 | } 110 | } 111 | 112 | public void write(long n, int tag) { 113 | reserve(10); 114 | if (n >= Integer.MIN_VALUE && n <= Integer.MAX_VALUE) { 115 | write((int) n, tag); 116 | } else { 117 | writeHead(TarsStructBase.LONG, tag); 118 | bs.putLong(n); 119 | } 120 | } 121 | 122 | public void write(float n, int tag) { 123 | reserve(6); 124 | writeHead(TarsStructBase.FLOAT, tag); 125 | bs.putFloat(n); 126 | } 127 | 128 | public void write(double n, int tag) { 129 | reserve(10); 130 | writeHead(TarsStructBase.DOUBLE, tag); 131 | bs.putDouble(n); 132 | } 133 | 134 | public void writeStringByte(String s, int tag) { 135 | byte[] by = HexUtil.hexStr2Bytes(s); 136 | reserve(10 + by.length); 137 | if (by.length > 255) { 138 | writeHead(TarsStructBase.STRING4, tag); 139 | bs.putInt(by.length); 140 | bs.put(by); 141 | } else { 142 | writeHead(TarsStructBase.STRING1, tag); 143 | bs.put((byte) by.length); 144 | bs.put(by); 145 | } 146 | } 147 | 148 | public void writeByteString(String s, int tag) { 149 | reserve(10 + s.length()); 150 | byte[] by = HexUtil.hexStr2Bytes(s); 151 | if (by.length > 255) { 152 | writeHead(TarsStructBase.STRING4, tag); 153 | bs.putInt(by.length); 154 | bs.put(by); 155 | } else { 156 | writeHead(TarsStructBase.STRING1, tag); 157 | bs.put((byte) by.length); 158 | bs.put(by); 159 | } 160 | } 161 | 162 | public void write(String s, int tag) { 163 | byte[] by; 164 | try { 165 | by = s.getBytes(sServerEncoding); 166 | } catch (UnsupportedEncodingException e) { 167 | by = s.getBytes(); 168 | } 169 | reserve(10 + by.length); 170 | if (by.length > 255) { 171 | writeHead(TarsStructBase.STRING4, tag); 172 | bs.putInt(by.length); 173 | bs.put(by); 174 | } else { 175 | writeHead(TarsStructBase.STRING1, tag); 176 | bs.put((byte) by.length); 177 | bs.put(by); 178 | } 179 | } 180 | 181 | public void write(Map m, int tag) { 182 | reserve(8); 183 | writeHead(TarsStructBase.MAP, tag); 184 | write(m == null ? 0 : m.size(), 0); 185 | if (m != null) { 186 | for (Map.Entry en : m.entrySet()) { 187 | write(en.getKey(), 0); 188 | write(en.getValue(), 1); 189 | } 190 | } 191 | } 192 | 193 | public void write(boolean[] l, int tag) { 194 | reserve(8); 195 | writeHead(TarsStructBase.LIST, tag); 196 | write(l.length, 0); 197 | for (boolean e : l) 198 | write(e, 0); 199 | } 200 | 201 | public void write(byte[] l, int tag) { 202 | reserve(8 + l.length); 203 | writeHead(TarsStructBase.SIMPLE_LIST, tag); 204 | writeHead(TarsStructBase.BYTE, 0); 205 | write(l.length, 0); 206 | bs.put(l); 207 | } 208 | 209 | public void write(short[] l, int tag) { 210 | reserve(8); 211 | writeHead(TarsStructBase.LIST, tag); 212 | write(l.length, 0); 213 | for (short e : l) 214 | write(e, 0); 215 | } 216 | 217 | public void write(int[] l, int tag) { 218 | reserve(8); 219 | writeHead(TarsStructBase.LIST, tag); 220 | write(l.length, 0); 221 | for (int e : l) 222 | write(e, 0); 223 | } 224 | 225 | public void write(long[] l, int tag) { 226 | reserve(8); 227 | writeHead(TarsStructBase.LIST, tag); 228 | write(l.length, 0); 229 | for (long e : l) 230 | write(e, 0); 231 | } 232 | 233 | public void write(float[] l, int tag) { 234 | reserve(8); 235 | writeHead(TarsStructBase.LIST, tag); 236 | write(l.length, 0); 237 | for (float e : l) 238 | write(e, 0); 239 | } 240 | 241 | public void write(double[] l, int tag) { 242 | reserve(8); 243 | writeHead(TarsStructBase.LIST, tag); 244 | write(l.length, 0); 245 | for (double e : l) 246 | write(e, 0); 247 | } 248 | 249 | public void write(T[] l, int tag) { 250 | writeArray(l, tag); 251 | } 252 | 253 | private void writeArray(Object[] l, int tag) { 254 | reserve(8); 255 | writeHead(TarsStructBase.LIST, tag); 256 | write(l.length, 0); 257 | for (Object e : l) 258 | write(e, 0); 259 | } 260 | 261 | public void write(Collection l, int tag) { 262 | reserve(8); 263 | writeHead(TarsStructBase.LIST, tag); 264 | write(l == null ? 0 : l.size(), 0); 265 | if (l != null) { 266 | for (T e : l) 267 | write(e, 0); 268 | } 269 | } 270 | 271 | public void write(TarsStructBase o, int tag) { 272 | reserve(2); 273 | writeHead(TarsStructBase.STRUCT_BEGIN, tag); 274 | o.writeTo(this); 275 | reserve(2); 276 | writeHead(TarsStructBase.STRUCT_END, 0); 277 | } 278 | 279 | public void write(Byte o, int tag) { 280 | write(o.byteValue(), tag); 281 | } 282 | 283 | public void write(Boolean o, int tag) { 284 | write(o.booleanValue(), tag); 285 | } 286 | 287 | public void write(Short o, int tag) { 288 | write(o.shortValue(), tag); 289 | } 290 | 291 | public void write(Integer o, int tag) { 292 | write(o.intValue(), tag); 293 | } 294 | 295 | public void write(Long o, int tag) { 296 | write(o.longValue(), tag); 297 | } 298 | 299 | public void write(Float o, int tag) { 300 | write(o.floatValue(), tag); 301 | } 302 | 303 | public void write(Double o, int tag) { 304 | write(o.doubleValue(), tag); 305 | } 306 | 307 | public void write(Object o, int tag) { 308 | if (o instanceof Byte) { 309 | write(((Byte) o).byteValue(), tag); 310 | } else if (o instanceof Boolean) { 311 | write(((Boolean) o).booleanValue(), tag); 312 | } else if (o instanceof Short) { 313 | write(((Short) o).shortValue(), tag); 314 | } else if (o instanceof Integer) { 315 | write(((Integer) o).intValue(), tag); 316 | } else if (o instanceof Long) { 317 | write(((Long) o).longValue(), tag); 318 | } else if (o instanceof Float) { 319 | write(((Float) o).floatValue(), tag); 320 | } else if (o instanceof Double) { 321 | write(((Double) o).doubleValue(), tag); 322 | } else if (o instanceof String) { 323 | write((String) o, tag); 324 | } else if (o instanceof Map) { 325 | write((Map) o, tag); 326 | } else if (o instanceof List) { 327 | write((List) o, tag); 328 | } else if (o instanceof TarsStructBase) { 329 | write((TarsStructBase) o, tag); 330 | } else if (o instanceof byte[]) { 331 | write((byte[]) o, tag); 332 | } else if (o instanceof boolean[]) { 333 | write((boolean[]) o, tag); 334 | } else if (o instanceof short[]) { 335 | write((short[]) o, tag); 336 | } else if (o instanceof int[]) { 337 | write((int[]) o, tag); 338 | } else if (o instanceof long[]) { 339 | write((long[]) o, tag); 340 | } else if (o instanceof float[]) { 341 | write((float[]) o, tag); 342 | } else if (o instanceof double[]) { 343 | write((double[]) o, tag); 344 | } else if (o.getClass().isArray()) { 345 | writeArray((Object[]) o, tag); 346 | } else if (o instanceof Collection) { 347 | write((Collection) o, tag); 348 | } else { 349 | throw new TarsEncodeException("write object error: unsupport type. " + o.getClass()); 350 | } 351 | } 352 | 353 | protected String sServerEncoding = "UTF-8"; 354 | 355 | public int setServerEncoding(String se) { 356 | sServerEncoding = se; 357 | return 0; 358 | } 359 | 360 | // public static void main(String[] args) { 361 | // TarsOutputStream os = new TarsOutputStream(); 362 | // long n = 0x1234567890012345L; 363 | // os.write(n, 0); 364 | // ByteBuffer bs = os.getByteBuffer(); 365 | // System.out.println(HexUtil.bytes2HexStr(bs.array())); 366 | // System.out.println(Arrays.toString(os.toByteArray())); 367 | // } 368 | } 369 | --------------------------------------------------------------------------------