This method is used by the {@link MiniTemplatorCache} class to
+ * clone the cached MiniTemplator objects.
+ */
+ public MiniTemplator cloneReset() {
+ MiniTemplator m = newInstance();
+ m.mtp = mtp; // the MiniTemplatorParser object is shared among the clones
+ m.charset = charset;
+ // (subtemplateBasePath does not have to be copied, because the subtemplates have already been read)
+ m.reset();
+ return m; }
+
+ /**
+ * Sets a template variable.
+ * For variables that are used in blocks, the variable value
+ * must be set before addBlock()
is called.
+ * @param variableName the name of the variable to be set. Case-insensitive.
+ * @param variableValue the new value of the variable. May be null
.
+ * @param isOptional specifies whether an exception should be thrown when the
+ * variable does not exist in the template. If isOptional
is
+ * false
and the variable does not exist, an exception is thrown.
+ * @throws VariableNotDefinedException when no variable with the
+ * specified name exists in the template and isOptional
is false
.
+ */
+ public void setVariable (String variableName, String variableValue, boolean isOptional)
+ throws VariableNotDefinedException {
+ int varNo = mtp.lookupVariableName(variableName);
+ if (varNo == -1) {
+ if (isOptional) {
+ return; }
+ throw new VariableNotDefinedException(variableName); }
+ varValuesTab[varNo] = variableValue; }
+
+ /**
+ * Sets a template variable.
+ *
Convenience method for: setVariable (variableName, variableValue, false)
+ * @param variableName the name of the variable to be set. Case-insensitive.
+ * @param variableValue the new value of the variable. May be null
.
+ * @throws VariableNotDefinedException when no variable with the
+ * specified name exists in the template.
+ * @see #setVariable(String, String, boolean)
+ */
+ public void setVariable (String variableName, String variableValue)
+ throws VariableNotDefinedException {
+ setVariable(variableName, variableValue, false); }
+
+ /**
+ * Sets a template variable to an integer value.
+ *
Convenience method for: setVariable (variableName, Integer.toString(variableValue))
+ * @param variableName the name of the variable to be set. Case-insensitive.
+ * @param variableValue the new value of the variable.
+ * @throws VariableNotDefinedException when no variable with the
+ * specified name exists in the template.
+ */
+ public void setVariable (String variableName, int variableValue)
+ throws VariableNotDefinedException {
+ setVariable(variableName, Integer.toString(variableValue)); }
+
+ /**
+ * Sets an optional template variable.
+ *
Convenience method for: setVariable (variableName, variableValue, true)
+ * @param variableName the name of the variable to be set. Case-insensitive.
+ * @param variableValue the new value of the variable. May be null
.
+ * @see #setVariable(String, String, boolean)
+ */
+ public void setVariableOpt (String variableName, String variableValue) {
+ setVariable(variableName, variableValue, true); }
+
+ /**
+ * Sets an optional template variable to an integer value.
+ *
Convenience method for: setVariableOpt (variableName, Integer.toString(variableValue))
+ * @param variableName the name of the variable to be set. Case-insensitive.
+ * @param variableValue the new value of the variable.
+ */
+ public void setVariableOpt (String variableName, int variableValue) {
+ // We want to avoid the integer to string conversion if the template variable does not exist.
+ int varNo = mtp.lookupVariableName(variableName);
+ if (varNo == -1) {
+ return; }
+ varValuesTab[varNo] = Integer.toString(variableValue); }
+
+ /**
+ * Sets a template variable to an escaped value.
+ *
Convenience method for: setVariable (variableName, MiniTemplator.escapeHtml(variableValue), isOptional)
+ * @param variableName the name of the variable to be set.
+ * @param variableValue the new value of the variable. May be null
.
+ * Special HTML/XML characters are escaped.
+ * @param isOptional specifies whether an exception should be thrown when the
+ * variable does not exist in the template. If isOptional
is
+ * false
and the variable does not exist, an exception is thrown.
+ * @throws VariableNotDefinedException when no variable with the
+ * specified name exists in the template and isOptional
is false
.
+ * @see #setVariable(String, String, boolean)
+ * @see #escapeHtml(String)
+ */
+ public void setVariableEsc (String variableName, String variableValue, boolean isOptional)
+ throws VariableNotDefinedException {
+ setVariable(variableName, escapeHtml(variableValue), isOptional); }
+
+ /**
+ * Sets a template variable to an escaped value.
+ *
Convenience method for: setVariable (variableName, MiniTemplator.escapeHtml(variableValue), false)
+ * @param variableName the name of the variable to be set. Case-insensitive.
+ * @param variableValue the new value of the variable. May be null
.
+ * Special HTML/XML characters are escaped.
+ * @throws VariableNotDefinedException when no variable with the
+ * specified name exists in the template.
+ * @see #setVariable(String, String, boolean)
+ * @see #escapeHtml(String)
+ */
+ public void setVariableEsc (String variableName, String variableValue)
+ throws VariableNotDefinedException {
+ setVariable(variableName, escapeHtml(variableValue), false); }
+
+ /**
+ * Sets an optional template variable to an escaped value.
+ *
Convenience method for: setVariable (variableName, MiniTemplator.escapeHtml(variableValue), true)
+ * @param variableName the name of the variable to be set. Case-insensitive.
+ * @param variableValue the new value of the variable. May be null
.
+ * Special HTML/XML characters are escaped.
+ * @see #setVariable(String, String, boolean)
+ * @see #escapeHtml(String)
+ */
+ public void setVariableOptEsc (String variableName, String variableValue) {
+ setVariable(variableName, escapeHtml(variableValue), true); }
+
+ /**
+ * Checks whether a variable with the specified name exists within the template.
+ * @param variableName the name of the variable. Case-insensitive.
+ * @return true
if the variable exists.
+ * false
if no variable with the specified name exists in the template.
+ */
+ public boolean variableExists (String variableName) {
+ return mtp.lookupVariableName(variableName) != -1; }
+
+ /**
+ * Returns a map with the names and current values of the template variables.
+ */
+ public Map getVariables() {
+ HashMap map = new HashMap(mtp.varTabCnt);
+ for (int varNo = 0; varNo < mtp.varTabCnt; varNo++)
+ map.put(mtp.varTab[varNo], varValuesTab[varNo]);
+ return map; }
+
+ /**
+ * Adds an instance of a template block.
+ * If the block contains variables, these variables must be set
+ * before the block is added.
+ * If the block contains subblocks (nested blocks), the subblocks
+ * must be added before this block is added.
+ * If multiple blocks exist with the specified name, an instance
+ * is added for each block occurrence.
+ * @param blockName the name of the block to be added. Case-insensitive.
+ * @param isOptional specifies whether an exception should be thrown when the
+ * block does not exist in the template. If isOptional
is
+ * false
and the block does not exist, an exception is thrown.
+ * @throws BlockNotDefinedException when no block with the specified name
+ * exists in the template and isOptional
is false
.
+ */
+ public void addBlock (String blockName, boolean isOptional)
+ throws BlockNotDefinedException {
+ int blockNo = mtp.lookupBlockName(blockName);
+ if(blockNo == -1) {
+ if (isOptional) {
+ return; }
+ throw new BlockNotDefinedException(blockName); }
+ while (blockNo != -1) {
+ addBlockByNo(blockNo);
+ blockNo = mtp.blockTab[blockNo].nextWithSameName; }}
+
+ /**
+ * Adds an instance of a template block.
+ *
Convenience method for: addBlock (blockName, false)
+ * @param blockName the name of the block to be added. Case-insensitive.
+ * @throws BlockNotDefinedException when no block with the specified name
+ * exists in the template.
+ * @see #addBlock(String, boolean)
+ */
+ public void addBlock (String blockName)
+ throws BlockNotDefinedException {
+ addBlock(blockName, false); }
+
+ /**
+ * Adds an instance of an optional template block.
+ *
Convenience method for: addBlock (blockName, true)
+ * @param blockName the name of the block to be added. Case-insensitive.
+ * @see #addBlock(String, boolean)
+ */
+ public void addBlockOpt (String blockName) {
+ addBlock(blockName, true); }
+
+ private void addBlockByNo (int blockNo) {
+ MiniTemplatorParser.BlockTabRec btr = mtp.blockTab[blockNo];
+ BlockDynTabRec bdtr = blockDynTab[blockNo];
+ int blockInstNo = registerBlockInstance();
+ BlockInstTabRec bitr = blockInstTab[blockInstNo];
+ if (bdtr.firstBlockInstNo == -1) {
+ bdtr.firstBlockInstNo = blockInstNo; }
+ if (bdtr.lastBlockInstNo != -1) {
+ blockInstTab[bdtr.lastBlockInstNo].nextBlockInstNo = blockInstNo; } // set forward pointer of chain
+ bdtr.lastBlockInstNo = blockInstNo;
+ bitr.blockNo = blockNo;
+ bitr.instanceLevel = bdtr.instances++;
+ if (btr.parentBlockNo == -1) {
+ bitr.parentInstLevel = -1; }
+ else {
+ bitr.parentInstLevel = blockDynTab[btr.parentBlockNo].instances; }
+ bitr.nextBlockInstNo = -1;
+ if (btr.blockVarCnt > 0) {
+ bitr.blockVarTab = new String[btr.blockVarCnt]; }
+ for (int blockVarNo=0; blockVarNo blockInstTab.length) {
+ blockInstTab = (BlockInstTabRec[])MiniTemplatorParser.resizeArray(blockInstTab, 2*blockInstTabCnt); }
+ blockInstTab[blockInstNo] = new BlockInstTabRec();
+ return blockInstNo; }
+
+ /**
+ * Checks whether a block with the specified name exists within the template.
+ * @param blockName the name of the block.
+ * @return true
if the block exists.
+ * false
if no block with the specified name exists in the template.
+ */
+ public boolean blockExists (String blockName) {
+ return mtp.lookupBlockName(blockName) != -1; }
+
+//--- output generation ----------------------------------------------
+
+ /**
+ * Generates the HTML page and writes it into a file.
+ * @param outputFileName name of the file to which the generated HTML page will be written.
+ * @throws IOException when an i/o error occurs while writing to the file.
+ */
+ public void generateOutput (String outputFileName)
+ throws IOException {
+ FileOutputStream stream = null;
+ OutputStreamWriter writer = null;
+ try {
+ stream = new FileOutputStream(outputFileName);
+ writer = new OutputStreamWriter(stream, charset);
+ generateOutput(writer); }
+ finally {
+ if (writer != null) {
+ writer.close(); }
+ if (stream != null) {
+ stream.close(); }}}
+
+ /**
+ * Generates the HTML page and writes it to a character stream.
+ * @param outputWriter a character stream (writer
) to which
+ * the HTML page will be written.
+ * @throws IOException when an i/o error occurs while writing to the stream.
+ */
+ public void generateOutput (Writer outputWriter)
+ throws IOException {
+ String s = generateOutput();
+ outputWriter.write(s); }
+
+ /**
+ * Generates the HTML page and returns it as a string.
+ * @return A string that contains the generated HTML page.
+ */
+ public String generateOutput() {
+ if (blockDynTab[0].instances == 0) {
+ addBlockByNo(0); } // add main block
+ for (int blockNo=0; blockNo parentInstLevel) {
+ break; }
+ writeBlockInstance(out, blockInstNo);
+ bdtr.currBlockInstNo = bitr.nextBlockInstNo; }}
+
+ private void writeBlockInstance (StringBuilder out, int blockInstNo) {
+ BlockInstTabRec bitr = blockInstTab[blockInstNo];
+ int blockNo = bitr.blockNo;
+ MiniTemplatorParser.BlockTabRec btr = mtp.blockTab[blockNo];
+ int tPos = btr.tPosContentsBegin;
+ int subBlockNo = blockNo + 1;
+ int varRefNo = btr.firstVarRefNo;
+ while (true) {
+ int tPos2 = btr.tPosContentsEnd;
+ int kind = 0; // assume end-of-block
+ if (varRefNo != -1 && varRefNo < mtp.varRefTabCnt) { // check for variable reference
+ MiniTemplatorParser.VarRefTabRec vrtr = mtp.varRefTab[varRefNo];
+ if (vrtr.tPosBegin < tPos) {
+ varRefNo++;
+ continue; }
+ if (vrtr.tPosBegin < tPos2) {
+ tPos2 = vrtr.tPosBegin;
+ kind = 1; }}
+ if (subBlockNo < mtp.blockTabCnt) { // check for subblock
+ MiniTemplatorParser.BlockTabRec subBtr = mtp.blockTab[subBlockNo];
+ if (subBtr.tPosBegin < tPos) {
+ subBlockNo++;
+ continue; }
+ if (subBtr.tPosBegin < tPos2) {
+ tPos2 = subBtr.tPosBegin;
+ kind = 2; }}
+ if (tPos2 > tPos) {
+ out.append(mtp.templateText.substring(tPos, tPos2)); }
+ switch (kind) {
+ case 0: // end of block
+ return;
+ case 1: { // variable
+ MiniTemplatorParser.VarRefTabRec vrtr = mtp.varRefTab[varRefNo];
+ if (vrtr.blockNo != blockNo) {
+ throw new AssertionError(); }
+ String variableValue = bitr.blockVarTab[vrtr.blockVarNo];
+ if (variableValue != null) {
+ out.append(variableValue); }
+ tPos = vrtr.tPosEnd;
+ varRefNo++;
+ break; }
+ case 2: { // sub block
+ MiniTemplatorParser.BlockTabRec subBtr = mtp.blockTab[subBlockNo];
+ if (subBtr.parentBlockNo != blockNo) {
+ throw new AssertionError(); }
+ writeBlockInstances(out, subBlockNo, bitr.instanceLevel); // recursive call
+ tPos = subBtr.tPosEnd;
+ subBlockNo++;
+ break; }}}}
+
+//--- general utility routines ---------------------------------------
+
+ // Reads the contents of a file into a string variable.
+ private String readFileIntoString (String fileName)
+ throws IOException {
+ FileInputStream stream = null;
+ InputStreamReader reader = null;
+ try {
+ stream = new FileInputStream(fileName);
+ reader = new InputStreamReader(stream, charset);
+ return readStreamIntoString(reader); }
+ finally {
+ if (reader != null) {
+ reader.close(); }
+ if (stream != null) {
+ stream.close(); }}}
+
+ // Reads the contents of a stream into a string variable.
+ private static String readStreamIntoString (Reader reader)
+ throws IOException {
+ StringBuilder s = new StringBuilder();
+ char a[] = new char[0x10000];
+ while (true) {
+ int l = reader.read(a);
+ if (l == -1) {
+ break; }
+ if (l <= 0) {
+ throw new IOException(); }
+ s.append(a, 0, l); }
+ return s.toString(); }
+
+ /**
+ * Escapes special HTML characters.
+ * Replaces the characters <, >, &, ' and " by their corresponding
+ * HTML/XML character entity codes.
+ * @param s the input string.
+ * @return the escaped output string.
+ */
+ public static String escapeHtml (String s) {
+ // (The code of this method is a bit redundant in order to optimize speed)
+ if (s == null) {
+ return null; }
+ int sLength = s.length();
+ boolean found = false;
+ int p;
+ loop1:
+ for (p=0; p': case '&': case '\'': case '"': found = true; break loop1; }}
+ if (!found) {
+ return s; }
+ StringBuilder sb = new StringBuilder(sLength+16);
+ sb.append(s.substring(0, p));
+ for (; p': sb.append (">"); break;
+ case '&': sb.append ("&"); break;
+ case '\'': sb.append ("'"); break;
+ case '"': sb.append ("""); break;
+ default: sb.append (c); }}
+ return sb.toString(); }
+
+} // End class MiniTemplator
+
+//====================================================================================================================
+
+// MiniTemplatorParser is an immutable object that contains the parsed template text.
+class MiniTemplatorParser {
+
+//--- constants ------------------------------------------------------
+
+ private static final int maxNestingLevel = 20; // maximum number of block nestings
+ private static final int maxCondLevels = 20; // maximum number of nested conditional commands ($if)
+ private static final int maxInclTemplateSize = 1000000; // maximum length of template string when including subtemplates
+ private static final String cmdStartStr = ""; // command end string
+ private static final String cmdStartStrShort = "<$"; // short form command start string
+ private static final String cmdEndStrShort = ">"; // short form command end string
+
+//--- nested classes -------------------------------------------------
+
+ public static class VarRefTabRec { // variable reference table record structure
+ int varNo; // variable no
+ int tPosBegin; // template position of begin of variable reference
+ int tPosEnd; // template position of end of variable reference
+ int blockNo; // block no of the (innermost) block that contains this variable reference
+ int blockVarNo; } // block variable no. Index into BlockInstTab.BlockVarTab
+ public static class BlockTabRec { // block table record structure
+ String blockName; // block name
+ int nextWithSameName; // block no of next block with same name or -1 (blocks are backward linked related to their position within the template)
+ int tPosBegin; // template position of begin of block
+ int tPosContentsBegin; // template pos of begin of block contents
+ int tPosContentsEnd; // template pos of end of block contents
+ int tPosEnd; // template position of end of block
+ int nestingLevel; // block nesting level
+ int parentBlockNo; // block no of parent block
+ boolean definitionIsOpen; // true while $BeginBlock processed but no $EndBlock
+ int blockVarCnt; // number of variables in block
+ int[] blockVarNoToVarNoMap; // maps block variable numbers to variable numbers
+ int firstVarRefNo; // variable reference no of first variable of this block or -1
+ boolean dummy; } // true if this is a dummy block that will never be included in the output
+
+//--- variables ------------------------------------------------------
+
+ public String templateText; // contents of the template file
+ private HashSet conditionFlags; // set of the condition flags, converted to uppercase
+ private boolean shortFormEnabled; // true to enable the short form of commands ("<$...>")
+
+ public String[] varTab; // variables table, contains variable names, array index is variable no
+ public int varTabCnt; // no of entries used in VarTab
+ private HashMap varNameToNoMap; // maps variable names to variable numbers
+ public VarRefTabRec[] varRefTab; // variable references table
+ // Contains an entry for each variable reference in the template. Ordered by templatePos.
+ public int varRefTabCnt; // no of entries used in VarRefTab
+
+ public BlockTabRec[] blockTab; // Blocks table, array index is block no
+ // Contains an entry for each block in the template. Ordered by tPosBegin.
+ public int blockTabCnt; // no of entries used in BlockTab
+ private HashMap blockNameToNoMap; // maps block names to block numbers
+
+ // The following variables are only used temporarilly during parsing of the template.
+ private int currentNestingLevel; // current block nesting level during parsing
+ private int[] openBlocksTab; // indexed by the block nesting level
+ // During parsing, this table contains the block numbers of the open parent blocks (nested outer blocks).
+ private int condLevel; // current nesting level of conditional commands ($if), -1 = main level
+ private boolean[] condEnabled; // enabled/disables state for the conditions of each level
+ private boolean[] condPassed; // true if an enabled condition clause has already been processed (separate for each level)
+ private MiniTemplator miniTemplator; // the MiniTemplator who created this parser object
+ // The reference to the MiniTemplator object is only used to call MiniTemplator.loadSubtemplate().
+ private boolean resumeCmdParsingFromStart; // true = resume command parsing from the start position of the last command
+
+//--- constructor ----------------------------------------------------
+
+ // (The MiniTemplator object is only passed to the parser, because the
+// parser needs to call MiniTemplator.loadSubtemplate() to load subtemplates.)
+ public MiniTemplatorParser (String templateText, Set conditionFlags, boolean shortFormEnabled, MiniTemplator miniTemplator)
+ throws MiniTemplator.TemplateSyntaxException {
+ this.templateText = templateText;
+ this.conditionFlags = createConditionFlagsSet(conditionFlags);
+ this.shortFormEnabled = shortFormEnabled;
+ this.miniTemplator = miniTemplator;
+ parseTemplate();
+ this.miniTemplator = null; }
+
+ private HashSet createConditionFlagsSet (Set flags) {
+ if (flags == null || flags.isEmpty()) {
+ return null; }
+ HashSet flags2 = new HashSet(flags.size());
+ for (String flag : flags) {
+ flags2.add (flag.toUpperCase()); }
+ return flags2; }
+
+//--- template parsing -----------------------------------------------
+
+ private void parseTemplate()
+ throws MiniTemplator.TemplateSyntaxException {
+ initParsing();
+ beginMainBlock();
+ parseTemplateCommands();
+ endMainBlock();
+ checkBlockDefinitionsComplete();
+ if (condLevel != -1) {
+ throw new MiniTemplator.TemplateSyntaxException ("$if without matching $endIf."); }
+ parseTemplateVariables();
+ associateVariablesWithBlocks();
+ terminateParsing(); }
+
+ private void initParsing() {
+ varTab = new String[64];
+ varTabCnt = 0;
+ varNameToNoMap = new HashMap();
+ varRefTab = new VarRefTabRec[64];
+ varRefTabCnt = 0;
+ blockTab = new BlockTabRec[16];
+ blockTabCnt = 0;
+ currentNestingLevel = 0;
+ blockNameToNoMap = new HashMap();
+ openBlocksTab = new int[maxNestingLevel+1];
+ condLevel = -1;
+ condEnabled = new boolean[maxCondLevels];
+ condPassed = new boolean[maxCondLevels]; }
+
+ private void terminateParsing() {
+ openBlocksTab = null; }
+
+ // Registers the main block.
+// The main block is an implicitly defined block that covers the whole template.
+ private void beginMainBlock() {
+ int blockNo = registerBlock(null); // =0
+ BlockTabRec btr = blockTab[blockNo];
+ btr.tPosBegin = 0;
+ btr.tPosContentsBegin = 0;
+ openBlocksTab[currentNestingLevel] = blockNo;
+ currentNestingLevel++; }
+
+ // Completes the main block registration.
+ private void endMainBlock() {
+ BlockTabRec btr = blockTab[0];
+ btr.tPosContentsEnd = templateText.length();
+ btr.tPosEnd = templateText.length();
+ btr.definitionIsOpen = false;
+ currentNestingLevel--; }
+
+//--- Template commands --------------------------------------------------------
+
+ // Parses commands within the template in the format "".
+// If shortFormEnabled is true, the short form commands in the format "<$...>" are also recognized.
+ private void parseTemplateCommands()
+ throws MiniTemplator.TemplateSyntaxException {
+ int p = 0; // p is the current position within templateText
+ while (true) {
+ int p0 = templateText.indexOf(cmdStartStr, p); // p0 is the start of the current command
+ boolean shortForm = false;
+ if (shortFormEnabled && p0 != p) {
+ if (p0 == -1) {
+ p0 = templateText.indexOf(cmdStartStrShort, p);
+ shortForm = true; }
+ else {
+ int p2 = templateText.substring(p, p0).indexOf(cmdStartStrShort);
+ if (p2 != -1) {
+ p0 = p + p2;
+ shortForm = true; }}}
+ if (p0 == -1) { // no more commands
+ break; }
+ conditionalExclude(p, p0); // process text up to the start of the current command
+ if (shortForm) { // short form command
+ p = templateText.indexOf(cmdEndStrShort, p0 + cmdStartStrShort.length());
+ if (p == -1) { // if no terminating ">" is found, we process it as normal text
+ p = p0 + cmdStartStrShort.length();
+ conditionalExclude(p0, p);
+ continue; }
+ p += cmdEndStrShort.length();
+ String cmdLine = templateText.substring(p0 + cmdStartStrShort.length(), p - cmdEndStrShort.length());
+ if (!processShortFormTemplateCommand(cmdLine, p0, p)) {
+ // If a short form command is not recognized, we process the whole command structure are normal text.
+ conditionalExclude(p0, p); }}
+ else { // normal (long) form command
+ p = templateText.indexOf(cmdEndStr, p0 + cmdStartStr.length());
+ if (p == -1) {
+ throw new MiniTemplator.TemplateSyntaxException("Invalid HTML comment in template at offset " + p0 + "."); }
+ p += cmdEndStr.length();
+ String cmdLine = templateText.substring(p0 + cmdStartStr.length(), p - cmdEndStr.length());
+ resumeCmdParsingFromStart = false;
+ if (!processTemplateCommand(cmdLine, p0, p)) {
+ conditionalExclude(p0, p); } // process as normal temlate text
+ if (resumeCmdParsingFromStart) { // (if a subtemplate has been included)
+ p = p0; }}}}
+
+ // Returns false if the command should be treatet as normal template text.
+ private boolean processTemplateCommand (String cmdLine, int cmdTPosBegin, int cmdTPosEnd)
+ throws MiniTemplator.TemplateSyntaxException {
+ int p0 = skipBlanks(cmdLine, 0);
+ if (p0 >= cmdLine.length()) {
+ return false; }
+ int p = skipNonBlanks(cmdLine, p0);
+ String cmd = cmdLine.substring(p0, p);
+ String parms = cmdLine.substring(p);
+ /* select */
+ if (cmd.equalsIgnoreCase("$beginBlock")) {
+ processBeginBlockCmd(parms, cmdTPosBegin, cmdTPosEnd); }
+ else if (cmd.equalsIgnoreCase("$endBlock")) {
+ processEndBlockCmd(parms, cmdTPosBegin, cmdTPosEnd); }
+ else if (cmd.equalsIgnoreCase("$include")) {
+ processIncludeCmd(parms, cmdTPosBegin, cmdTPosEnd); }
+ else if (cmd.equalsIgnoreCase("$if")) {
+ processIfCmd(parms, cmdTPosBegin, cmdTPosEnd); }
+ else if (cmd.equalsIgnoreCase("$elseIf")) {
+ processElseIfCmd(parms, cmdTPosBegin, cmdTPosEnd); }
+ else if (cmd.equalsIgnoreCase("$else")) {
+ processElseCmd(parms, cmdTPosBegin, cmdTPosEnd); }
+ else if (cmd.equalsIgnoreCase("$endIf")) {
+ processEndIfCmd(parms, cmdTPosBegin, cmdTPosEnd); }
+ else {
+ if (cmd.startsWith("$") && !cmd.startsWith("${")) {
+ throw new MiniTemplator.TemplateSyntaxException("Unknown command \"" + cmd + "\" in template at offset " + cmdTPosBegin + "."); }
+ else {
+ return false; }}
+ return true; }
+
+ // Returns false if the command is not recognized and should be treatet as normal temlate text.
+ private boolean processShortFormTemplateCommand (String cmdLine, int cmdTPosBegin, int cmdTPosEnd)
+ throws MiniTemplator.TemplateSyntaxException {
+ int p0 = skipBlanks(cmdLine, 0);
+ if (p0 >= cmdLine.length()) {
+ return false; }
+ int p = p0;
+ char cmd1 = cmdLine.charAt(p++);
+ if (cmd1 == '/' && p < cmdLine.length() && !Character.isWhitespace(cmdLine.charAt(p))) {
+ p++; }
+ String cmd = cmdLine.substring(p0, p);
+ String parms = cmdLine.substring(p).trim();
+ /* select */
+ if (cmd.equals("?")) {
+ processIfCmd(parms, cmdTPosBegin, cmdTPosEnd); }
+ else if (cmd.equals(":")) {
+ if (parms.length() > 0) {
+ processElseIfCmd(parms, cmdTPosBegin, cmdTPosEnd); }
+ else {
+ processElseCmd(parms, cmdTPosBegin, cmdTPosEnd); }}
+ else if (cmd.equals("/?")) {
+ processEndIfCmd(parms, cmdTPosBegin, cmdTPosEnd); }
+ else {
+ return false; }
+ return true; }
+
+ // Processes the $beginBlock command.
+ private void processBeginBlockCmd (String parms, int cmdTPosBegin, int cmdTPosEnd)
+ throws MiniTemplator.TemplateSyntaxException {
+ if (conditionalExclude(cmdTPosBegin, cmdTPosEnd)) {
+ return; }
+ int p0 = skipBlanks(parms, 0);
+ if (p0 >= parms.length()) {
+ throw new MiniTemplator.TemplateSyntaxException("Missing block name in $BeginBlock command in template at offset " + cmdTPosBegin + "."); }
+ int p = skipNonBlanks(parms, p0);
+ String blockName = parms.substring(p0, p);
+ if (!isRestOfStringBlank(parms, p)) {
+ throw new MiniTemplator.TemplateSyntaxException("Extra parameter in $BeginBlock command in template at offset " + cmdTPosBegin + "."); }
+ int blockNo = registerBlock(blockName);
+ BlockTabRec btr = blockTab[blockNo];
+ btr.tPosBegin = cmdTPosBegin;
+ btr.tPosContentsBegin = cmdTPosEnd;
+ openBlocksTab[currentNestingLevel] = blockNo;
+ currentNestingLevel++;
+ if (currentNestingLevel > maxNestingLevel) {
+ throw new MiniTemplator.TemplateSyntaxException("Block nesting overflow for block \"" + blockName + "\" in template at offset " + cmdTPosBegin + "."); }}
+
+ // Processes the $endBlock command.
+ private void processEndBlockCmd (String parms, int cmdTPosBegin, int cmdTPosEnd)
+ throws MiniTemplator.TemplateSyntaxException {
+ if (conditionalExclude(cmdTPosBegin, cmdTPosEnd)) {
+ return; }
+ int p0 = skipBlanks(parms, 0);
+ if (p0 >= parms.length()) {
+ throw new MiniTemplator.TemplateSyntaxException("Missing block name in $EndBlock command in template at offset " + cmdTPosBegin + "."); }
+ int p = skipNonBlanks(parms, p0);
+ String blockName = parms.substring(p0, p);
+ if (!isRestOfStringBlank(parms, p)) {
+ throw new MiniTemplator.TemplateSyntaxException("Extra parameter in $EndBlock command in template at offset " + cmdTPosBegin + "."); }
+ int blockNo = lookupBlockName(blockName);
+ if (blockNo == -1) {
+ throw new MiniTemplator.TemplateSyntaxException("Undefined block name \"" + blockName + "\" in $EndBlock command in template at offset " + cmdTPosBegin + "."); }
+ currentNestingLevel--;
+ BlockTabRec btr = blockTab[blockNo];
+ if (!btr.definitionIsOpen) {
+ throw new MiniTemplator.TemplateSyntaxException("Multiple $EndBlock command for block \"" + blockName + "\" in template at offset " + cmdTPosBegin + "."); }
+ if (btr.nestingLevel != currentNestingLevel) {
+ throw new MiniTemplator.TemplateSyntaxException("Block nesting level mismatch at $EndBlock command for block \"" + blockName + "\" in template at offset " + cmdTPosBegin + "."); }
+ btr.tPosContentsEnd = cmdTPosBegin;
+ btr.tPosEnd = cmdTPosEnd;
+ btr.definitionIsOpen = false; }
+
+ // Returns the block number of the newly registered block.
+ private int registerBlock (String blockName) {
+ int blockNo = blockTabCnt++;
+ if (blockTabCnt > blockTab.length) {
+ blockTab = (BlockTabRec[])resizeArray(blockTab, 2*blockTabCnt); }
+ BlockTabRec btr = new BlockTabRec();
+ blockTab[blockNo] = btr;
+ btr.blockName = blockName;
+ if (blockName != null) {
+ btr.nextWithSameName = lookupBlockName(blockName); }
+ else {
+ btr.nextWithSameName = -1; }
+ btr.nestingLevel = currentNestingLevel;
+ if (currentNestingLevel > 0) {
+ btr.parentBlockNo = openBlocksTab[currentNestingLevel-1]; }
+ else {
+ btr.parentBlockNo = -1; }
+ btr.definitionIsOpen = true;
+ btr.blockVarCnt = 0;
+ btr.firstVarRefNo = -1;
+ btr.blockVarNoToVarNoMap = new int[32];
+ btr.dummy = false;
+ if (blockName != null) {
+ blockNameToNoMap.put(blockName.toUpperCase(), new Integer(blockNo)); }
+ return blockNo; }
+
+ // Registers a dummy block to exclude a range within the template text.
+ private void excludeTemplateRange (int tPosBegin, int tPosEnd) {
+ if (blockTabCnt > 0) {
+ // Check whether we can extend the previous block.
+ BlockTabRec btr = blockTab[blockTabCnt-1];
+ if (btr.dummy && btr.tPosEnd == tPosBegin) {
+ btr.tPosContentsEnd = tPosEnd;
+ btr.tPosEnd = tPosEnd;
+ return; }}
+ int blockNo = registerBlock(null);
+ BlockTabRec btr = blockTab[blockNo];
+ btr.tPosBegin = tPosBegin;
+ btr.tPosContentsBegin = tPosBegin;
+ btr.tPosContentsEnd = tPosEnd;
+ btr.tPosEnd = tPosEnd;
+ btr.definitionIsOpen = false;
+ btr.dummy = true; }
+
+ // Checks that all block definitions are closed.
+ private void checkBlockDefinitionsComplete()
+ throws MiniTemplator.TemplateSyntaxException {
+ for (int blockNo=0; blockNo= parms.length()) {
+ throw new MiniTemplator.TemplateSyntaxException("Missing subtemplate name in $Include command in template at offset " + cmdTPosBegin + "."); }
+ int p;
+ if (parms.charAt(p0) == '"') { // subtemplate name is quoted
+ p0++;
+ p = parms.indexOf('"', p0);
+ if (p == -1) {
+ throw new MiniTemplator.TemplateSyntaxException("Missing closing quote for subtemplate name in $Include command in template at offset " + cmdTPosBegin + "."); }}
+ else {
+ p = skipNonBlanks(parms, p0); }
+ String subtemplateName = parms.substring(p0, p);
+ p++;
+ if (!isRestOfStringBlank(parms, p)) {
+ throw new MiniTemplator.TemplateSyntaxException("Extra parameter in $Include command in template at offset " + cmdTPosBegin + "."); }
+ insertSubtemplate(subtemplateName, cmdTPosBegin, cmdTPosEnd); }
+
+ private void insertSubtemplate (String subtemplateName, int tPos1, int tPos2) {
+ if (templateText.length() > maxInclTemplateSize) {
+ throw new RuntimeException("Subtemplate include aborted because the internal template string is longer than "+maxInclTemplateSize+" characters."); }
+ String subtemplate;
+ try {
+ subtemplate = miniTemplator.loadSubtemplate(subtemplateName); }
+ catch (IOException e) {
+ throw new RuntimeException("Error while loading subtemplate \""+subtemplateName+"\"", e); }
+ // (Copying the template to insert a subtemplate is a bit slow. In a future implementation of MiniTemplator,
+ // a table could be used that contains references to the string fragments.)
+ StringBuilder s = new StringBuilder(templateText.length()+subtemplate.length());
+ s.append(templateText, 0, tPos1);
+ s.append(subtemplate);
+ s.append(templateText, tPos2, templateText.length());
+ templateText = s.toString();
+ resumeCmdParsingFromStart = true; }
+
+//--- Conditional commands -----------------------------------------------------
+
+ // Returns the enabled/disabled state of the condition at level condLevel2.
+ private boolean isCondEnabled (int condLevel2) {
+ if (condLevel2 < 0) {
+ return true; }
+ return condEnabled[condLevel2]; }
+
+ // If the current condition is disabled, the text from tPosBegin to tPosEnd
+// is excluded and true is returned.
+// Otherwise nothing is done and false is returned.
+ private boolean conditionalExclude (int tPosBegin, int tPosEnd) {
+ if (isCondEnabled(condLevel)) {
+ return false; }
+ excludeTemplateRange(tPosBegin, tPosEnd);
+ return true; }
+
+ // Evaluates a condition expression of a conditional command, by comparing the
+// flags in the expression with the flags in TemplateSpecification.conditionFlags.
+// Returns true the condition is met.
+ private boolean evaluateConditionFlags (String flags) {
+ int p = 0;
+ while (true) {
+ p = skipBlanks(flags, p);
+ if (p >= flags.length()) {
+ break; }
+ boolean complement = false;
+ if (flags.charAt(p) == '!') {
+ complement = true; p++; }
+ p = skipBlanks(flags, p);
+ if (p >= flags.length()) {
+ break; }
+ int p0 = p;
+ p = skipNonBlanks(flags, p0+1);
+ String flag = flags.substring(p0, p).toUpperCase();
+ if ((conditionFlags != null && conditionFlags.contains(flag)) ^ complement) {
+ return true; }}
+ return false; }
+
+ // Processes the $if command.
+ private void processIfCmd (String parms, int cmdTPosBegin, int cmdTPosEnd)
+ throws MiniTemplator.TemplateSyntaxException {
+ excludeTemplateRange(cmdTPosBegin, cmdTPosEnd);
+ if (condLevel >= maxCondLevels-1) {
+ throw new MiniTemplator.TemplateSyntaxException ("Too many nested $if commands."); }
+ condLevel++;
+ boolean enabled = isCondEnabled(condLevel-1) && evaluateConditionFlags(parms);
+ condEnabled[condLevel] = enabled;
+ condPassed[condLevel] = enabled; }
+
+ // Processes the $elseIf command.
+ private void processElseIfCmd (String parms, int cmdTPosBegin, int cmdTPosEnd)
+ throws MiniTemplator.TemplateSyntaxException {
+ excludeTemplateRange(cmdTPosBegin, cmdTPosEnd);
+ if (condLevel < 0) {
+ throw new MiniTemplator.TemplateSyntaxException ("$elseIf without matching $if."); }
+ boolean enabled = isCondEnabled(condLevel-1) && !condPassed[condLevel] && evaluateConditionFlags(parms);
+ condEnabled[condLevel] = enabled;
+ if (enabled) {
+ condPassed[condLevel] = true; }}
+
+ // Processes the $else command.
+ private void processElseCmd (String parms, int cmdTPosBegin, int cmdTPosEnd)
+ throws MiniTemplator.TemplateSyntaxException {
+ excludeTemplateRange(cmdTPosBegin, cmdTPosEnd);
+ if (parms.trim().length() != 0) {
+ throw new MiniTemplator.TemplateSyntaxException ("Invalid parameters for $else command."); }
+ if (condLevel < 0) {
+ throw new MiniTemplator.TemplateSyntaxException ("$else without matching $if."); }
+ boolean enabled = isCondEnabled(condLevel-1) && !condPassed[condLevel];
+ condEnabled[condLevel] = enabled;
+ if (enabled) {
+ condPassed[condLevel] = true; }}
+
+ // Processes the $endIf command.
+ private void processEndIfCmd (String parms, int cmdTPosBegin, int cmdTPosEnd)
+ throws MiniTemplator.TemplateSyntaxException {
+ excludeTemplateRange(cmdTPosBegin, cmdTPosEnd);
+ if (parms.trim().length() != 0) {
+ throw new MiniTemplator.TemplateSyntaxException ("Invalid parameters for $endIf command."); }
+ if (condLevel < 0) {
+ throw new MiniTemplator.TemplateSyntaxException ("$endif without matching $if."); }
+ condLevel--; }
+
+//------------------------------------------------------------------------------
+
+ // Associates variable references with blocks.
+ private void associateVariablesWithBlocks() {
+ int varRefNo = 0;
+ int activeBlockNo = 0;
+ int nextBlockNo = 1;
+ while (varRefNo < varRefTabCnt) {
+ VarRefTabRec vrtr = varRefTab[varRefNo];
+ int varRefTPos = vrtr.tPosBegin;
+ int varNo = vrtr.varNo;
+ if (varRefTPos >= blockTab[activeBlockNo].tPosEnd) {
+ activeBlockNo = blockTab[activeBlockNo].parentBlockNo;
+ continue; }
+ if (nextBlockNo < blockTabCnt && varRefTPos >= blockTab[nextBlockNo].tPosBegin) {
+ activeBlockNo = nextBlockNo;
+ nextBlockNo++;
+ continue; }
+ BlockTabRec btr = blockTab[activeBlockNo];
+ if (varRefTPos < btr.tPosBegin) {
+ throw new AssertionError(); }
+ int blockVarNo = btr.blockVarCnt++;
+ if (btr.blockVarCnt > btr.blockVarNoToVarNoMap.length) {
+ btr.blockVarNoToVarNoMap = (int[])resizeArray(btr.blockVarNoToVarNoMap, 2*btr.blockVarCnt); }
+ btr.blockVarNoToVarNoMap[blockVarNo] = varNo;
+ if (btr.firstVarRefNo == -1) {
+ btr.firstVarRefNo = varRefNo; }
+ vrtr.blockNo = activeBlockNo;
+ vrtr.blockVarNo = blockVarNo;
+ varRefNo++; }}
+
+ // Parses variable references within the template in the format "${VarName}" .
+ private void parseTemplateVariables()
+ throws MiniTemplator.TemplateSyntaxException {
+ int p = 0;
+ while (true) {
+ p = templateText.indexOf("${", p);
+ if (p == -1) {
+ break; }
+ int p0 = p;
+ p = templateText.indexOf("}", p);
+ if (p == -1) {
+ throw new MiniTemplator.TemplateSyntaxException("Invalid variable reference in template at offset " + p0 + "."); }
+ p++;
+ String varName = templateText.substring(p0+2, p-1).trim();
+ if (varName.length() == 0) {
+ throw new MiniTemplator.TemplateSyntaxException("Empty variable name in template at offset " + p0 + "."); }
+ registerVariableReference(varName, p0, p); }}
+
+ private void registerVariableReference (String varName, int tPosBegin, int tPosEnd) {
+ int varNo;
+ varNo = lookupVariableName(varName);
+ if (varNo == -1) {
+ varNo = registerVariable(varName); }
+ int varRefNo = varRefTabCnt++;
+ if (varRefTabCnt > varRefTab.length) {
+ varRefTab = (VarRefTabRec[])resizeArray(varRefTab, 2*varRefTabCnt); }
+ VarRefTabRec vrtr = new VarRefTabRec();
+ varRefTab[varRefNo] = vrtr;
+ vrtr.tPosBegin = tPosBegin;
+ vrtr.tPosEnd = tPosEnd;
+ vrtr.varNo = varNo; }
+
+ // Returns the variable number of the newly registered variable.
+ private int registerVariable (String varName) {
+ int varNo = varTabCnt++;
+ if (varTabCnt > varTab.length) {
+ varTab = (String[])resizeArray(varTab, 2*varTabCnt); }
+ varTab[varNo] = varName;
+ varNameToNoMap.put(varName.toUpperCase(), new Integer(varNo));
+ return varNo; }
+
+//--- name lookup routines -------------------------------------------
+
+ // Maps variable name to variable number.
+// Returns -1 if the variable name is not found.
+ public int lookupVariableName (String varName) {
+ Integer varNoWrapper = varNameToNoMap.get(varName.toUpperCase());
+ if (varNoWrapper == null) {
+ return -1; }
+ int varNo = varNoWrapper.intValue();
+ return varNo; }
+
+ // Maps block name to block number.
+// If there are multiple blocks with the same name, the block number of the last
+// registered block with that name is returned.
+// Returns -1 if the block name is not found.
+ public int lookupBlockName (String blockName) {
+ Integer blockNoWrapper = blockNameToNoMap.get(blockName.toUpperCase());
+ if (blockNoWrapper == null) {
+ return -1; }
+ int blockNo = blockNoWrapper.intValue();
+ return blockNo; }
+
+//--- general utility routines ---------------------------------------
+
+ // Reallocates an array with a new size and copies the contents
+// of the old array to the new array.
+ public static Object resizeArray (Object oldArray, int newSize) {
+ int oldSize = java.lang.reflect.Array.getLength(oldArray);
+ Class> elementType = oldArray.getClass().getComponentType();
+ Object newArray = java.lang.reflect.Array.newInstance(
+ elementType, newSize);
+ int preserveLength = Math.min(oldSize, newSize);
+ if (preserveLength > 0) {
+ System.arraycopy(oldArray, 0, newArray, 0, preserveLength); }
+ return newArray; }
+
+ // Skips blanks (white space) in string s starting at position p.
+ private static int skipBlanks (String s, int p) {
+ while (p < s.length() && Character.isWhitespace(s.charAt(p))) p++;
+ return p; }
+
+ // Skips non-blanks (no-white space) in string s starting at position p.
+ private static int skipNonBlanks (String s, int p) {
+ while (p < s.length() && !Character.isWhitespace(s.charAt(p))) p++;
+ return p; }
+
+ // Returns true if string s is blank (white space) from position p to the end.
+ public static boolean isRestOfStringBlank (String s, int p) {
+ return skipBlanks(s, p) >= s.length(); }
+
+} // End class MiniTemplatorParser
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/impl/HelloServiceImpl.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/impl/HelloServiceImpl.java
deleted file mode 100644
index 3581bae3ae..0000000000
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/impl/HelloServiceImpl.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.taobao.arthas.service.impl;/**
- * @author: 風楪
- * @date: 2024/6/30 下午6:42
- */
-
-import helloworld.HelloServiceGrpc;
-import helloworld.Test;
-import io.grpc.stub.StreamObserver;
-
-/**
- * @author: FengYe
- * @date: 2024/6/30 下午6:42
- * @description: HelloServiceImpl
- */
-public class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {
- @Override
- public void sayHello(Test.HelloRequest request, StreamObserver responseObserver) {
- String name = request.getName();
- System.out.println(name);
- responseObserver.onNext(Test.HelloReply.newBuilder().setMessage(name).build());
- responseObserver.onCompleted();
- }
-}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
index de7e35ea7e..5f2eb61b51 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
@@ -3,62 +3,104 @@
* @date: 2024/7/14 上午4:28
*/
+import com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass;
import com.google.protobuf.*;
-import com.taobao.arthas.service.ArthasSampleService;
-import helloworld.Test;
-import io.netty.buffer.ByteBuf;
import java.io.IOException;
import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.Map;
/**
* @author: FengYe
* @date: 2024/7/14 上午4:28
* @description: ArthasSampleRequest
*/
+@ProtobufClass
public class ArthasSampleRequest{
+ @Override
+ public String toString() {
+ return "ArthasSampleRequest{" +
+// "name='" + name + '\'' +
+ ", age=" + age +
+ ", price=" + price +
+ ", man=" + man +
+ '}';
+ }
+//
+// public String getName() {
+// return name;
+// }
+//
+// public void setName(String name) {
+// this.name = name;
+// }
+
+ public Double getAge() {
+ return age;
+ }
+
+ public void setAge(Double age) {
+ this.age = age;
+ }
- private String name;
+ public Long getPrice() {
+ return price;
+ }
- public ArthasSampleRequest(ByteBuffer byteBuffer){
- CodedInputStream codedInputStream = CodedInputStream.newInstance(byteBuffer);
- try {
- // 读取标签
- int tag;
- while ((tag = codedInputStream.readTag()) != 0) {
- int fieldNumber = WireFormat.getTagFieldNumber(tag);
- int wireType = WireFormat.getTagWireType(tag);
+ public void setPrice(Long price) {
+ this.price = price;
+ }
- System.out.println("Field Number: " + fieldNumber);
- System.out.println("Wire Type: " + wireType);
+ public Float getMan() {
+ return man;
+ }
- // 根据字段编号和类型读取对应的数据
- switch (wireType) {
- case WireFormat.WIRETYPE_VARINT:
- long varintValue = codedInputStream.readInt64();
- System.out.println("Varint Value: " + varintValue);
- break;
- case WireFormat.WIRETYPE_FIXED32:
- int fixed32Value = codedInputStream.readFixed32();
- System.out.println("Fixed32 Value: " + fixed32Value);
- break;
- case WireFormat.WIRETYPE_FIXED64:
- long fixed64Value = codedInputStream.readFixed64();
- System.out.println("Fixed64 Value: " + fixed64Value);
- break;
- case WireFormat.WIRETYPE_LENGTH_DELIMITED:
- int length = codedInputStream.readRawVarint32();
- byte[] bytes = codedInputStream.readRawBytes(length);
- System.out.println("Length-delimited Value: " + new String(bytes));
- break;
- default:
- throw new IOException("Unsupported wire type: " + wireType);
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
+ public void setMan(Float man) {
+ this.man = man;
}
+
+// private String name;
+ private Double age;
+ private Long price;
+ private Float man;
+
+// public ArthasSampleRequest(ByteBuffer byteBuffer){
+// CodedInputStream codedInputStream = CodedInputStream.newInstance(byteBuffer);
+// try {
+// // 读取标签
+// int tag;
+// while ((tag = codedInputStream.readTag()) != 0) {
+// int fieldNumber = WireFormat.getTagFieldNumber(tag);
+// int wireType = WireFormat.getTagWireType(tag);
+//
+// System.out.println("Field Number: " + fieldNumber);
+// System.out.println("Wire Type: " + wireType);
+//
+//
+// // 根据字段编号和类型读取对应的数据
+// switch (wireType) {
+// case WireFormat.WIRETYPE_VARINT:
+// long varintValue = codedInputStream.readInt64();
+// System.out.println("Varint Value: " + varintValue);
+// break;
+// case WireFormat.WIRETYPE_FIXED32:
+// int fixed32Value = codedInputStream.readFixed32();
+// System.out.println("Fixed32 Value: " + fixed32Value);
+// break;
+// case WireFormat.WIRETYPE_FIXED64:
+// long fixed64Value = codedInputStream.readFixed64();
+// System.out.println("Fixed64 Value: " + fixed64Value);
+// break;
+// case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+// int length = codedInputStream.readRawVarint32();
+// byte[] bytes = codedInputStream.readRawBytes(length);
+// System.out.println("Length-delimited Value: " + new String(bytes));
+// break;
+// default:
+// throw new IOException("Unsupported wire type: " + wireType);
+// }
+// }
+// } catch (IOException e) {
+// e.printStackTrace();
+// }
+// }
}
diff --git a/arthas-grpc-server/src/main/resources/class_template.tpl b/arthas-grpc-server/src/main/resources/class_template.tpl
new file mode 100644
index 0000000000..f7031aa529
--- /dev/null
+++ b/arthas-grpc-server/src/main/resources/class_template.tpl
@@ -0,0 +1,102 @@
+${package}
+
+import java.io.Serializable;
+
+import ${importPackage};
+
+
+public class ${className} implements ${codecClassName}<${targetProxyClassName}>, Serializable {
+ public static final long serialVersionUID = 1L;
+ private ${descriptorClsName} descriptor;
+
+ public byte[] encode(${targetProxyClassName} t) throws IOException {
+ CodecOutputByteArray output = CodecOutputByteArray.get();
+ doWriteTo(t, output.getCodedOutputStream());
+ return output.getData();
+ }
+
+ public ${targetProxyClassName} decode(byte[] bb) throws IOException {
+ CodedInputStream input = CodedInputStream.newInstance(bb, 0, bb.length);
+ return readFrom(input);
+ }
+
+ public int size(${targetProxyClassName} t) throws IOException {
+ int size = 0;
+
+ ${encodeFieldType} ${encodeFieldName} = null;
+ if (!CodedConstant.isNull(${encodeFieldGetter})) {
+ ${encodeFieldName} = ${writeValueToField};
+ size += ${calcSize}
+ }
+ ${checkNull}
+
+ return size;
+ }
+
+ public void doWriteTo(${targetProxyClassName} t, CodedOutputStream output)
+ throws IOException {
+
+ ${encodeFieldType} ${encodeFieldName} = null;
+ if (!CodedConstant.isNull(${encodeFieldGetter})) {
+ ${encodeFieldName} = ${writeValueToField};
+ ${encodeWriteFieldValue}
+ }
+
+ }
+
+ public void writeTo(${targetProxyClassName} t, CodedOutputStream output)
+ throws IOException {
+ doWriteTo(t, output);
+ }
+
+ public ${targetProxyClassName} readFrom(CodedInputStream input) throws IOException {
+ ${targetProxyClassName} ret = new ${targetProxyClassName}();
+
+ ${initListMapFields}
+
+
+ ${enumInitialize};
+
+ try {
+ boolean done = false;
+ Codec codec = null;
+ while (!done) {
+ int tag = input.readTag();
+ if (tag == 0) {
+ break;
+ }
+
+ if (tag == ${decodeOrder}) {
+ ${objectDecodeExpress}
+ ${decodeFieldSetValue}
+ ${objectDecodeExpressSuffix}
+ ${deocdeCheckNull}
+ continue;
+ }
+ ${objectPackedDecodeExpress}
+
+
+ input.skipField(tag);
+ }
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ throw e;
+ } catch (java.io.IOException e) {
+ throw e;
+ }
+
+ return ret;
+
+ }
+
+
+ public com.google.protobuf.Descriptors.Descriptor getDescriptor() throws IOException {
+ if (this.descriptor != null) {
+ return this.descriptor;
+ }
+ com.google.protobuf.Descriptors.Descriptor descriptor =
+ CodedConstant.getDescriptor(${targetProxyClassName}.class);
+ return (this.descriptor = descriptor);
+ }
+}
+
+
\ No newline at end of file
From 8761959911d9fffab678769783999f64e16dca3b Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Wed, 24 Jul 2024 02:15:53 +0800
Subject: [PATCH 08/48] init
---
.../taobao/arthas/protobuf/ProtobufProxy.java | 84 +++++++++++++++++++
.../arthas/protobuf/ProtobufProxyFactory.java | 40 ---------
.../src/main/resources/class_template.tpl | 2 +-
3 files changed, 85 insertions(+), 41 deletions(-)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
delete mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxyFactory.java
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
new file mode 100644
index 0000000000..e343d3a42b
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -0,0 +1,84 @@
+package com.taobao.arthas.protobuf;/**
+ * @author: 風楪
+ * @date: 2024/7/17 下午9:57
+ */
+
+
+import com.baidu.bjf.remoting.protobuf.Codec;
+import com.taobao.arthas.protobuf.utils.MiniTemplator;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author: FengYe
+ * @date: 2024/7/17 下午9:57
+ * @description: ProtoBufProxy
+ */
+public class ProtobufProxy {
+ private static final String TEMPLATE_FILE = "/class_template.tpl";
+
+ private static final Map codecCache = new ConcurrentHashMap();
+
+ private Class> clazz;
+
+ private MiniTemplator miniTemplator;
+
+ public ProtobufProxy(Class> clazz) {
+ this.clazz = clazz;
+ }
+
+ public ProtobufCodec getCodecCacheSide(Class> clazz) {
+ ProtobufCodec codec = codecCache.get(clazz.getName());
+ if (codec != null) {
+ return codec;
+ }
+ try {
+ codec = create(clazz);
+ codecCache.put(clazz.getName(), codec);
+ return codec;
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ return null;
+ }
+ }
+
+ public ProtobufCodec create(Class> clazz) throws Exception {
+ String path = Objects.requireNonNull(clazz.getResource(TEMPLATE_FILE)).getPath();
+ miniTemplator = new MiniTemplator(path);
+
+ miniTemplator.setVariable("package", "package " + clazz.getPackage().getName() + ";");
+
+ processImportBlock();
+
+ miniTemplator.setVariable("className", clazz.getName() + "$$ProxyClass");
+ miniTemplator.setVariable("codecClassName", ProtobufCodec.class.getName());
+ miniTemplator.setVariable("targetProxyClassName", clazz.getName());
+
+
+ return null;
+ }
+
+ private void processImportBlock(){
+ Set imports = new HashSet<>();
+ imports.add("java.util.*");
+ imports.add("java.io.IOException");
+ imports.add("java.lang.reflect.*");
+// imports.add("com.baidu.bjf.remoting.protobuf.FieldType"); // fix the class ambiguous of FieldType
+// imports.add("com.baidu.bjf.remoting.protobuf.code.*");
+// imports.add("com.baidu.bjf.remoting.protobuf.utils.*");
+// imports.add("com.baidu.bjf.remoting.protobuf.*");
+ imports.add("com.google.protobuf.*");
+ imports.add(clazz.getName());
+ for (String pkg : imports) {
+ miniTemplator.setVariable("importBlock", pkg);
+ miniTemplator.addBlock("imports");
+ }
+ }
+
+
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxyFactory.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxyFactory.java
deleted file mode 100644
index 93f874e745..0000000000
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxyFactory.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.taobao.arthas.protobuf;/**
- * @author: 風楪
- * @date: 2024/7/17 下午9:57
- */
-
-
-import com.taobao.arthas.Main;
-import com.taobao.arthas.protobuf.utils.MiniTemplator;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * @author: FengYe
- * @date: 2024/7/17 下午9:57
- * @description: ProtoBufProxy
- */
-public class ProtobufProxyFactory {
- private static final String TEMPLATE_FILE = "/class_template.tpl";
-
- private static final Map codecCache = new ConcurrentHashMap();
-
- public static ProtobufCodec getCodec(Class> clazz) throws IOException {
- ProtobufCodec codec = codecCache.get(clazz.getName());
- if (codec != null) {
- return codec;
- }
- return create(clazz);
- }
-
- public static ProtobufCodec create(Class> clazz) throws IOException {
- String path = Objects.requireNonNull(clazz.getResource(TEMPLATE_FILE)).getPath();
- MiniTemplator miniTemplator = new MiniTemplator(path);
-
- return null;
- }
-}
diff --git a/arthas-grpc-server/src/main/resources/class_template.tpl b/arthas-grpc-server/src/main/resources/class_template.tpl
index f7031aa529..76ea118627 100644
--- a/arthas-grpc-server/src/main/resources/class_template.tpl
+++ b/arthas-grpc-server/src/main/resources/class_template.tpl
@@ -2,7 +2,7 @@ ${package}
import java.io.Serializable;
-import ${importPackage};
+import ${importBlock};
public class ${className} implements ${codecClassName}<${targetProxyClassName}>, Serializable {
From 0116fcdf978e93870390fd3860035396dcac5167 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Thu, 25 Jul 2024 02:12:14 +0800
Subject: [PATCH 09/48] update: add protobuf codec
---
.../taobao/arthas/protobuf/ProtobufClass.java | 12 ----
.../taobao/arthas/protobuf/ProtobufField.java | 22 +++++++
.../taobao/arthas/protobuf/ProtobufProxy.java | 27 ++++++--
.../protobuf/annotation/ProtobufClass.java | 19 ++++++
.../annotation/ProtobufCustomedField.java | 23 +++++++
.../protobuf/annotation/ProtobufIgnore.java | 19 ++++++
.../arthas/protobuf/utils/FieldUtil.java | 61 +++++++++++++++++++
7 files changed, 166 insertions(+), 17 deletions(-)
delete mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufClass.java
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufClass.java
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomedField.java
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufIgnore.java
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufClass.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufClass.java
deleted file mode 100644
index 1388162f71..0000000000
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufClass.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.taobao.arthas.protobuf;/**
- * @author: 風楪
- * @date: 2024/7/17 下午10:00
- */
-
-/**
- * @author: FengYe
- * @date: 2024/7/17 下午10:00
- * @description: ProtoBufClass
- */
-public @interface ProtobufClass {
-}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
new file mode 100644
index 0000000000..700daf9eaa
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
@@ -0,0 +1,22 @@
+package com.taobao.arthas.protobuf;/**
+ * @author: 風楪
+ * @date: 2024/7/25 上午12:14
+ */
+
+import com.google.protobuf.WireFormat;
+
+import java.lang.reflect.Field;
+
+/**
+ * @author: FengYe
+ * @date: 2024/7/25 上午12:14
+ * @description: ProtobufField
+ */
+public class ProtobufField {
+
+ private int order;
+
+ private Field javaField;
+
+ private ProtobufFieldType protobufFieldType;
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index e343d3a42b..5015128756 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -5,13 +5,12 @@
import com.baidu.bjf.remoting.protobuf.Codec;
+import com.taobao.arthas.protobuf.annotation.ProtobufClass;
import com.taobao.arthas.protobuf.utils.MiniTemplator;
import java.io.IOException;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
+import java.lang.reflect.Field;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -28,8 +27,12 @@ public class ProtobufProxy {
private MiniTemplator miniTemplator;
+ private List protobufFields;
+
public ProtobufProxy(Class> clazz) {
+ Objects.requireNonNull(clazz);
this.clazz = clazz;
+ loadProtobufField();
}
public ProtobufCodec getCodecCacheSide(Class> clazz) {
@@ -63,7 +66,7 @@ public ProtobufCodec create(Class> clazz) throws Exception {
return null;
}
- private void processImportBlock(){
+ private void processImportBlock() {
Set imports = new HashSet<>();
imports.add("java.util.*");
imports.add("java.io.IOException");
@@ -80,5 +83,19 @@ private void processImportBlock(){
}
}
+ public void processEncodeBlock() {
+
+ }
+
+
+ private void loadProtobufField() {
+ List fields = new ArrayList<>();
+ ProtobufClass annotation = clazz.getAnnotation(ProtobufClass.class);
+ if (annotation != null) {
+
+ } else {
+ //todo 添加指定字段映射关系
+ }
+ }
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufClass.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufClass.java
new file mode 100644
index 0000000000..20e50adc99
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufClass.java
@@ -0,0 +1,19 @@
+package com.taobao.arthas.protobuf.annotation;/**
+ * @author: 風楪
+ * @date: 2024/7/25 上午12:19
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author: FengYe
+ * @date: 2024/7/25 上午12:19
+ * @description: ProtobufClass 用于标识 protobuf class
+ */
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ProtobufClass {
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomedField.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomedField.java
new file mode 100644
index 0000000000..7a50de6336
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomedField.java
@@ -0,0 +1,23 @@
+package com.taobao.arthas.protobuf.annotation;/**
+ * @author: 風楪
+ * @date: 2024/7/25 上午12:21
+ */
+
+import com.baidu.bjf.remoting.protobuf.FieldType;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author: FengYe
+ * @date: 2024/7/25 上午12:21
+ * @description: ProtobufField 用于自定义标识字段;当类上添加 ProtobufClass 时,该注解不生效
+ */
+@Target({ ElementType.FIELD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ProtobufCustomedField {
+ int order() default 0;
+ FieldType fieldType() default FieldType.DEFAULT;
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufIgnore.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufIgnore.java
new file mode 100644
index 0000000000..4ea603cf86
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufIgnore.java
@@ -0,0 +1,19 @@
+package com.taobao.arthas.protobuf.annotation;/**
+ * @author: 風楪
+ * @date: 2024/7/25 上午12:44
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author: FengYe
+ * @date: 2024/7/25 上午12:44
+ * @description: ProtobufIgnore
+ */
+@Target({ ElementType.TYPE, ElementType.FIELD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ProtobufIgnore {
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
new file mode 100644
index 0000000000..c96d00eca1
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
@@ -0,0 +1,61 @@
+package com.taobao.arthas.protobuf.utils;/**
+ * @author: 風楪
+ * @date: 2024/7/25 上午12:33
+ */
+
+import com.baidu.bjf.remoting.protobuf.annotation.Ignore;
+import com.sun.org.apache.bcel.internal.generic.RETURN;
+import com.taobao.arthas.protobuf.ProtobufField;
+import com.taobao.arthas.protobuf.annotation.ProtobufCustomedField;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author: FengYe
+ * @date: 2024/7/25 上午12:33
+ * @description: FieldUtil
+ */
+public class FieldUtil {
+
+ public static List getProtobufFieldList(Class> clazz, boolean enableCustomedField) {
+ // 获取所有的 java field
+ List fields = new ArrayList<>();
+ Field[] fieldsArray = clazz.getFields();
+ for (Field field : fieldsArray) {
+ if (enableCustomedField) {
+ ProtobufCustomedField annotation = field.getAnnotation(ProtobufCustomedField.class);
+ if (annotation != null) {
+ fields.add(field);
+ }
+ } else {
+ fields.add(field);
+ }
+ }
+
+ // 转化为 protobuf field
+ List protobufFields = new ArrayList<>();
+ for (Field field : fields) {
+ if (field.getAnnotation(Ignore.class) != null || Modifier.isTransient(field.getModifiers())) {
+ continue;
+ }
+
+ String fieldName = field.getName();
+ String filedTypeName = field.getType().getName();
+
+ // protobuf 不支持除字节数组以外任何数组
+ if (filedTypeName.startsWith("[")) {
+ if ((!filedTypeName.equals(byte[].class.getName())) && (!filedTypeName.equals(Byte[].class.getName()))) {
+ throw new RuntimeException("Array type of field '" + fieldName + "' on class '"
+ + field.getDeclaringClass().getName() + "' is not support, please use List instead.");
+ }
+ }
+
+
+ }
+ //TODO
+ return null;
+ }
+}
From 29eb16f00d2e51ed99ab4ee406e2a7cdddecf6e9 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Mon, 29 Jul 2024 01:42:43 +0800
Subject: [PATCH 10/48] update: add protobuf codec
---
.../taobao/arthas/protobuf/ProtobufField.java | 230 +++++++++++++++++-
...ldType.java => ProtobufFieldTypeEnum.java} | 10 +-
.../taobao/arthas/protobuf/ProtobufProxy.java | 38 ++-
.../protobuf/annotation/EnableZigZap.java | 19 ++
...ield.java => ProtobufCustomizedField.java} | 8 +-
.../arthas/protobuf/utils/FieldUtil.java | 226 +++++++++++++++--
.../service/req/ArthasSampleRequest.java | 94 +------
.../src/main/resources/class_template.tpl | 33 +--
8 files changed, 514 insertions(+), 144 deletions(-)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/{ProtobufFieldType.java => ProtobufFieldTypeEnum.java} (94%)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/EnableZigZap.java
rename arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/{ProtobufCustomedField.java => ProtobufCustomizedField.java} (61%)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
index 700daf9eaa..aeb387cc9d 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
@@ -3,9 +3,13 @@
* @date: 2024/7/25 上午12:14
*/
-import com.google.protobuf.WireFormat;
-
import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.WildcardType;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* @author: FengYe
@@ -14,9 +18,229 @@
*/
public class ProtobufField {
+ /**
+ * 序号
+ */
private int order;
+ /**
+ * protobuf 字段类型
+ */
+ private ProtobufFieldTypeEnum protobufFieldType;
+
+ /**
+ * java 字段类型
+ */
private Field javaField;
- private ProtobufFieldType protobufFieldType;
+ /**
+ * 是否为 List
+ */
+ private boolean isList;
+
+ /**
+ * 是否为 Map
+ */
+ private boolean isMap;
+
+ /**
+ * List & Map key 的泛型类型
+ */
+ private Class> genericKeyType;
+
+ /**
+ * Map value 的泛型类型
+ */
+ private Class> genericValueType;
+
+ /**
+ * 是否是通配符类型
+ */
+ private boolean wildcardType;
+
+ /**
+ * 处理 List 和 Map 类型字段
+ *
+ * @param field
+ */
+ public void parseListOrMap(Field field) {
+ Class> cls = field.getType();
+ boolean needCheckGenericType = false;
+ if (List.class.isAssignableFrom(cls) || Set.class.isAssignableFrom(cls)) {
+ isList = true;
+ needCheckGenericType = true;
+ }
+ if (Map.class.isAssignableFrom(cls)) {
+ isMap = true;
+ needCheckGenericType = true;
+ }
+
+ if (!needCheckGenericType) {
+ return;
+ }
+
+ Type type = field.getGenericType();
+ if (type instanceof ParameterizedType) {
+ ParameterizedType ptype = (ParameterizedType) type;
+
+ Type[] actualTypeArguments = ptype.getActualTypeArguments();
+
+ if (actualTypeArguments != null) {
+
+ int length = actualTypeArguments.length;
+ if (isList) {
+ if (length != 1) {
+ throw new RuntimeException(
+ "List must use generic definiation like List, please check field name '"
+ + field.getName() + " at class " + field.getDeclaringClass().getName());
+ }
+ } else if (isMap) {
+ if (length != 2) {
+ throw new RuntimeException(
+ "Map must use generic definiation like Map, please check field name '"
+ + field.getName() + " at class " + field.getDeclaringClass().getName());
+ }
+ }
+
+ Type targetType = actualTypeArguments[0];
+ if (targetType instanceof Class) {
+ genericKeyType = (Class) targetType;
+ } else if (targetType instanceof ParameterizedType) {
+ boolean mapKey = false;
+ if (isMap) {
+ mapKey = true;
+ }
+ throw new RuntimeException(noSubParameterizedType(field, mapKey));
+ } else if (WildcardType.class.isAssignableFrom(targetType.getClass())) {
+ wildcardType = true;
+ WildcardType wildcardType = (WildcardType) targetType;
+
+ Type[] upperBounds = wildcardType.getUpperBounds();
+ if (upperBounds != null && upperBounds.length == 1) {
+ if (upperBounds[0] instanceof Class) {
+ genericKeyType = (Class) upperBounds[0];
+ }
+ }
+ }
+
+ if (actualTypeArguments.length > 1) {
+ targetType = actualTypeArguments[1];
+ if (targetType instanceof Class) {
+ genericValueType = (Class) targetType;
+ } else if (targetType instanceof ParameterizedType) {
+ boolean mapKey = false;
+ if (isMap) {
+ mapKey = true;
+ }
+ throw new RuntimeException(noSubParameterizedType(field, mapKey));
+ } else if (WildcardType.class.isAssignableFrom(targetType.getClass())) {
+ wildcardType = true;
+ WildcardType wildcardType = (WildcardType) targetType;
+
+ Type[] upperBounds = wildcardType.getUpperBounds();
+ if (upperBounds != null && upperBounds.length == 1) {
+ if (upperBounds[0] instanceof Class) {
+ genericValueType = (Class) upperBounds[0];
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ /**
+ * No sub parameterized type.
+ *
+ * @param field the field
+ * @param listOrMap the list or map
+ * @return the string
+ */
+ private String noSubParameterizedType(Field field, boolean listOrMap) {
+ String key = "List";
+ if (listOrMap) {
+ key = "Map";
+ }
+ return key + " can not has sub parameterized type please check field name '" + field.getName() + " at class "
+ + field.getDeclaringClass().getName();
+
+ }
+
+ public int getOrder() {
+ return order;
+ }
+
+ public void setOrder(int order) {
+ this.order = order;
+ }
+
+ public ProtobufFieldTypeEnum getProtobufFieldType() {
+ return protobufFieldType;
+ }
+
+ public void setProtobufFieldType(ProtobufFieldTypeEnum protobufFieldType) {
+ this.protobufFieldType = protobufFieldType;
+ }
+
+ public boolean isList() {
+ return isList;
+ }
+
+ public void setList(boolean list) {
+ isList = list;
+ }
+
+ public boolean isMap() {
+ return isMap;
+ }
+
+ public void setMap(boolean map) {
+ isMap = map;
+ }
+
+ public Class> getGenericKeyType() {
+ return genericKeyType;
+ }
+
+ public void setGenericKeyType(Class> genericKeyType) {
+ this.genericKeyType = genericKeyType;
+ }
+
+ public Class> getGenericValueType() {
+ return genericValueType;
+ }
+
+ public void setGenericValueType(Class> genericValueType) {
+ this.genericValueType = genericValueType;
+ }
+
+ public Field getJavaField() {
+ return javaField;
+ }
+
+ public void setJavaField(Field javaField) {
+ this.javaField = javaField;
+ }
+
+ public boolean isWildcardType() {
+ return wildcardType;
+ }
+
+ public void setWildcardType(boolean wildcardType) {
+ this.wildcardType = wildcardType;
+ }
+
+ @Override
+ public String toString() {
+ return "ProtobufField{" +
+ "order=" + order +
+ ", protobufFieldType=" + protobufFieldType +
+ ", isList=" + isList +
+ ", isMap=" + isMap +
+ ", genericKeyType=" + genericKeyType +
+ ", genericValueType=" + genericValueType +
+ ", wildcardType=" + wildcardType +
+ '}';
+ }
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufFieldType.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufFieldTypeEnum.java
similarity index 94%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufFieldType.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufFieldTypeEnum.java
index a59ad2b814..2cde8ee9f8 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufFieldType.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufFieldTypeEnum.java
@@ -10,7 +10,7 @@
* @date: 2024/7/17 下午10:02
* @description: ProtoBufFieldType
*/
-public enum ProtobufFieldType {
+public enum ProtobufFieldTypeEnum {
/**
* types defined in .proto file.
*/
@@ -128,7 +128,7 @@ public String getType() {
* @return java original type
*/
public String getJavaType() {
- if (this == ProtobufFieldType.ENUM) {
+ if (this == ProtobufFieldTypeEnum.ENUM) {
return Enum.class.getName();
}
return javaType;
@@ -141,8 +141,8 @@ public String getJavaType() {
* @param type protobuf type
* @param wireFormat protobuf wire format type
*/
- ProtobufFieldType(String javaType, String type, String wireFormat,
- String toPrimitiveType, WireFormat.FieldType internalFieldType, String defaultValue) {
+ ProtobufFieldTypeEnum(String javaType, String type, String wireFormat,
+ String toPrimitiveType, WireFormat.FieldType internalFieldType, String defaultValue) {
this.javaType = javaType;
this.type = type;
this.wireFormat = wireFormat;
@@ -161,7 +161,7 @@ public boolean isPrimitive() {
|| this == FIXED64 || this == FLOAT
|| this == INT64 || this == SFIXED32
|| this == SFIXED64 || this == SINT32
- || this == SINT64 || this == BOOL || this == ProtobufFieldType.UINT32 || this == ProtobufFieldType.UINT64) {
+ || this == SINT64 || this == BOOL || this == ProtobufFieldTypeEnum.UINT32 || this == ProtobufFieldTypeEnum.UINT64) {
return true;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index 5015128756..b5b85e6abd 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -5,8 +5,11 @@
import com.baidu.bjf.remoting.protobuf.Codec;
+import com.taobao.arthas.protobuf.annotation.EnableZigZap;
import com.taobao.arthas.protobuf.annotation.ProtobufClass;
+import com.taobao.arthas.protobuf.utils.FieldUtil;
import com.taobao.arthas.protobuf.utils.MiniTemplator;
+import com.taobao.arthas.service.req.ArthasSampleRequest;
import java.io.IOException;
import java.lang.reflect.Field;
@@ -31,11 +34,14 @@ public class ProtobufProxy {
public ProtobufProxy(Class> clazz) {
Objects.requireNonNull(clazz);
+ if (clazz.getAnnotation(ProtobufClass.class) == null) {
+ throw new IllegalArgumentException("class is not annotated with @ProtobufClass");
+ }
this.clazz = clazz;
loadProtobufField();
}
- public ProtobufCodec getCodecCacheSide(Class> clazz) {
+ public ProtobufCodec getCodecCacheSide() {
ProtobufCodec codec = codecCache.get(clazz.getName());
if (codec != null) {
return codec;
@@ -50,7 +56,7 @@ public ProtobufCodec getCodecCacheSide(Class> clazz) {
}
}
- public ProtobufCodec create(Class> clazz) throws Exception {
+ private ProtobufCodec create(Class> clazz) throws Exception {
String path = Objects.requireNonNull(clazz.getResource(TEMPLATE_FILE)).getPath();
miniTemplator = new MiniTemplator(path);
@@ -84,17 +90,33 @@ private void processImportBlock() {
}
public void processEncodeBlock() {
-
+ for (ProtobufField protobufField : protobufFields) {
+ boolean isList = protobufField.isList();
+ boolean isMap = protobufField.isMap();
+
+ ProtobufFieldTypeEnum protobufFieldType = protobufField.getProtobufFieldType();
+ String encodeFieldGetter = FieldUtil.getAccessMethod("target", protobufField.getJavaField(), clazz, protobufField.isWildcardType());
+ String encodeFileType = isList ? "Collection" : protobufField.getProtobufFieldType().getJavaType();
+ String encodeFieldName = "f_" + protobufField.getOrder();
+
+ miniTemplator.setVariable("encodeFileType",encodeFileType);
+ miniTemplator.setVariable("encodeFieldName",encodeFieldName);
+ miniTemplator.setVariable("encodeFieldGetter",encodeFieldGetter);
+ }
}
private void loadProtobufField() {
- List fields = new ArrayList<>();
- ProtobufClass annotation = clazz.getAnnotation(ProtobufClass.class);
- if (annotation != null) {
+ protobufFields = FieldUtil.getProtobufFieldList(clazz,
+ clazz.getAnnotation(EnableZigZap.class) != null
+ );
+ }
- } else {
- //todo 添加指定字段映射关系
+ public static void main(String[] args) {
+ List protobufFieldList = FieldUtil.getProtobufFieldList(ArthasSampleRequest.class, false);
+ for (ProtobufField protobufField : protobufFieldList) {
+ String target = FieldUtil.getAccessMethod("target", protobufField.getJavaField(), ArthasSampleRequest.class, protobufField.isWildcardType());
+ System.out.println(target);
}
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/EnableZigZap.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/EnableZigZap.java
new file mode 100644
index 0000000000..b9d3ac83b1
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/EnableZigZap.java
@@ -0,0 +1,19 @@
+package com.taobao.arthas.protobuf.annotation;/**
+ * @author: 風楪
+ * @date: 2024/7/28 下午7:27
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author: FengYe
+ * @date: 2024/7/28 下午7:27
+ * @description: EnableZigZap 是否启用 zigzap 编码
+ */
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnableZigZap {
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomedField.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomizedField.java
similarity index 61%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomedField.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomizedField.java
index 7a50de6336..ec3124299a 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomedField.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomizedField.java
@@ -3,7 +3,7 @@
* @date: 2024/7/25 上午12:21
*/
-import com.baidu.bjf.remoting.protobuf.FieldType;
+import com.taobao.arthas.protobuf.ProtobufFieldTypeEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -13,11 +13,11 @@
/**
* @author: FengYe
* @date: 2024/7/25 上午12:21
- * @description: ProtobufField 用于自定义标识字段;当类上添加 ProtobufClass 时,该注解不生效
+ * @description: ProtobufField 用于自定义标识字段
*/
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
-public @interface ProtobufCustomedField {
+public @interface ProtobufCustomizedField {
int order() default 0;
- FieldType fieldType() default FieldType.DEFAULT;
+ ProtobufFieldTypeEnum protoBufFieldType() default ProtobufFieldTypeEnum.DEFAULT;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
index c96d00eca1..6f7acc27bb 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
@@ -4,14 +4,22 @@
*/
import com.baidu.bjf.remoting.protobuf.annotation.Ignore;
-import com.sun.org.apache.bcel.internal.generic.RETURN;
+import com.baidu.bjf.remoting.protobuf.code.CodedConstant;
+import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
+import com.baidu.bjf.remoting.protobuf.utils.FieldInfo;
+import com.baidu.bjf.remoting.protobuf.utils.FieldUtils;
import com.taobao.arthas.protobuf.ProtobufField;
-import com.taobao.arthas.protobuf.annotation.ProtobufCustomedField;
+import com.taobao.arthas.protobuf.ProtobufFieldTypeEnum;
+import com.taobao.arthas.protobuf.annotation.ProtobufCustomizedField;
+import com.taobao.arthas.protobuf.annotation.ProtobufIgnore;
+import com.taobao.arthas.service.req.ArthasSampleRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.List;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.*;
+import java.util.logging.Level;
/**
* @author: FengYe
@@ -20,31 +28,71 @@
*/
public class FieldUtil {
- public static List getProtobufFieldList(Class> clazz, boolean enableCustomedField) {
+ public static final String PACKAGE_SEPARATOR = ".";
+
+ public static final Map, ProtobufFieldTypeEnum> TYPE_MAPPER;
+
+ static {
+ TYPE_MAPPER = new HashMap, ProtobufFieldTypeEnum>();
+
+ TYPE_MAPPER.put(int.class, ProtobufFieldTypeEnum.INT32);
+ TYPE_MAPPER.put(Integer.class, ProtobufFieldTypeEnum.INT32);
+ TYPE_MAPPER.put(short.class, ProtobufFieldTypeEnum.INT32);
+ TYPE_MAPPER.put(Short.class, ProtobufFieldTypeEnum.INT32);
+ TYPE_MAPPER.put(Byte.class, ProtobufFieldTypeEnum.INT32);
+ TYPE_MAPPER.put(byte.class, ProtobufFieldTypeEnum.INT32);
+ TYPE_MAPPER.put(long.class, ProtobufFieldTypeEnum.INT64);
+ TYPE_MAPPER.put(Long.class, ProtobufFieldTypeEnum.INT64);
+ TYPE_MAPPER.put(String.class, ProtobufFieldTypeEnum.STRING);
+ TYPE_MAPPER.put(byte[].class, ProtobufFieldTypeEnum.BYTES);
+ TYPE_MAPPER.put(Byte[].class, ProtobufFieldTypeEnum.BYTES);
+ TYPE_MAPPER.put(Float.class, ProtobufFieldTypeEnum.FLOAT);
+ TYPE_MAPPER.put(float.class, ProtobufFieldTypeEnum.FLOAT);
+ TYPE_MAPPER.put(double.class, ProtobufFieldTypeEnum.DOUBLE);
+ TYPE_MAPPER.put(Double.class, ProtobufFieldTypeEnum.DOUBLE);
+ TYPE_MAPPER.put(Boolean.class, ProtobufFieldTypeEnum.BOOL);
+ TYPE_MAPPER.put(boolean.class, ProtobufFieldTypeEnum.BOOL);
+ TYPE_MAPPER.put(Date.class, ProtobufFieldTypeEnum.DATE);
+ TYPE_MAPPER.put(BigDecimal.class, ProtobufFieldTypeEnum.BIGDECIMAL);
+ TYPE_MAPPER.put(BigInteger.class, ProtobufFieldTypeEnum.BIGINTEGER);
+ }
+
+
+ /**
+ * 将指定类的所有 java 字段转化为 protobuf 字段
+ * 字段编号逻辑:优先处理自定义的字段,其余字段在最大的自定义字段基础上递增
+ *
+ * @param clazz
+ * @param enableZigZap
+ * @return
+ */
+ public static List getProtobufFieldList(Class> clazz, boolean enableZigZap) {
// 获取所有的 java field
List fields = new ArrayList<>();
- Field[] fieldsArray = clazz.getFields();
+ Field[] fieldsArray = clazz.getDeclaredFields();
for (Field field : fieldsArray) {
- if (enableCustomedField) {
- ProtobufCustomedField annotation = field.getAnnotation(ProtobufCustomedField.class);
- if (annotation != null) {
- fields.add(field);
- }
- } else {
+ if (field.getAnnotation(ProtobufIgnore.class) == null) {
fields.add(field);
}
}
// 转化为 protobuf field
- List protobufFields = new ArrayList<>();
+ List res = new ArrayList<>();
+ List unOrderFields = new ArrayList<>();
+ Set orders = new HashSet<>();
+ int maxOrder = 0;
+
for (Field field : fields) {
+ Class> fieldType = field.getType();
+ String fieldName = field.getName();
+ String filedTypeName = fieldType.getName();
+ ProtobufCustomizedField customizedField = field.getAnnotation(ProtobufCustomizedField.class);
+ int order = 0;
+
if (field.getAnnotation(Ignore.class) != null || Modifier.isTransient(field.getModifiers())) {
continue;
}
- String fieldName = field.getName();
- String filedTypeName = field.getType().getName();
-
// protobuf 不支持除字节数组以外任何数组
if (filedTypeName.startsWith("[")) {
if ((!filedTypeName.equals(byte[].class.getName())) && (!filedTypeName.equals(Byte[].class.getName()))) {
@@ -53,9 +101,153 @@ public static List getProtobufFieldList(Class> clazz, boolean e
}
}
+ ProtobufField protobufField = new ProtobufField();
+ protobufField.parseListOrMap(field);
+ protobufField.setJavaField(field);
+
+ ProtobufFieldTypeEnum protobufFieldType = ProtobufFieldTypeEnum.DEFAULT;
+ if (customizedField != null) {
+ order = customizedField.order();
+ protobufFieldType = customizedField.protoBufFieldType();
+ }
+
+ // 如果不是自定义字段,则通过 javaType 和 protobufType 映射关系来决定
+ if (protobufFieldType == ProtobufFieldTypeEnum.DEFAULT) {
+ if (protobufField.isList()) {
+ fieldType = protobufField.getGenericKeyType();
+ }
+ if (fieldType == null) {
+ fieldType = Object.class;
+ }
+
+ protobufFieldType = TYPE_MAPPER.get(fieldType);
+ if (protobufFieldType == null) {
+ if (Enum.class.isAssignableFrom(fieldType)) {
+ protobufFieldType = ProtobufFieldTypeEnum.ENUM;
+ } else if (protobufField.isMap()) {
+ protobufFieldType = ProtobufFieldTypeEnum.MAP;
+ } else {
+ protobufFieldType = ProtobufFieldTypeEnum.OBJECT;
+ }
+ }
+
+ // 处理 zigzap 编码
+ if (enableZigZap) {
+ if (protobufFieldType == ProtobufFieldTypeEnum.INT32) {
+ protobufFieldType = ProtobufFieldTypeEnum.SINT32; // to convert to sint32 to enable zagzip
+ } else if (protobufFieldType == ProtobufFieldTypeEnum.INT64) {
+ protobufFieldType = ProtobufFieldTypeEnum.SINT64; // to convert to sint64 to enable zagzip
+ }
+ }
+ }
+ protobufField.setProtobufFieldType(protobufFieldType);
+
+ // 如果是自定义字段,则取自定义值中的order,否则记录到未排序的 list 中,等待后续处理
+ if (order > 0) {
+ if (orders.contains(order)) {
+ throw new RuntimeException(
+ "order id '" + order + "' from field name '" + fieldName + "' is duplicate");
+ }
+ orders.add(order);
+ protobufField.setOrder(order);
+ maxOrder = Math.max(maxOrder, order);
+ } else {
+ unOrderFields.add(protobufField);
+ }
+
+ res.add(protobufField);
+ }
+
+ if (unOrderFields.isEmpty()) {
+ return res;
+ }
+
+ for (ProtobufField protobufField : unOrderFields) {
+ protobufField.setOrder(++maxOrder);
+ }
+
+ return res;
+ }
+
+ public static Field findField(Class clazz, String name, Class type) {
+ if (clazz == null) {
+ throw new IllegalArgumentException("Class must not be null");
+ }
+ if (name == null && type == null) {
+ throw new IllegalArgumentException(
+ "Either name or type of the field must be specified");
+ }
+ Class searchType = clazz;
+ while (!Object.class.equals(searchType) && searchType != null) {
+ Field[] fields = searchType.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+ if ((name == null || name.equals(field.getName()))
+ && (type == null || type.equals(field.getType()))) {
+ return field;
+ }
+ }
+ searchType = searchType.getSuperclass();
+ }
+ return null;
+ }
+
+ public static Object getField(Object t, String name) {
+ Field field = findField(t.getClass(), name, null);
+ if (field == null) {
+ return null;
+ }
+ field.setAccessible(true);
+ try {
+ return field.get(t);
+ } catch (Exception e) {
+ //todo log
+ }
+ return null;
+ }
+
+ /**
+ * 获取目标的访问方法字符串,如果目标已经声明 getter 则返回 getter,否则使用 FieldUtil.getField
+ *
+ * @param target
+ * @param field
+ * @param clazz
+ * @param wildcardType
+ * @return
+ */
+ public static String getAccessMethod(String target, Field field, Class> clazz, boolean wildcardType) {
+ if (field.getModifiers() == Modifier.PUBLIC && !wildcardType) {
+ return target + PACKAGE_SEPARATOR + field.getName();
+ }
+
+ String getter;
+ if ("boolean".equalsIgnoreCase(field.getType().getCanonicalName())) {
+ getter = "is" + CodedConstant.capitalize(field.getName());
+ } else {
+ getter = "get" + CodedConstant.capitalize(field.getName());
+ }
+
+ try {
+ clazz.getMethod(getter, new Class>[0]);
+ return target + PACKAGE_SEPARATOR + getter + "()";
+ } catch (Exception e) {
+ //todo log
+ }
+ String type = field.getType().getCanonicalName();
+ if ("[B".equals(type) || "[Ljava.lang.Byte;".equals(type) || "java.lang.Byte[]".equals(type)) {
+ type = "byte[]";
}
- //TODO
+
+ // use reflection to get value
+ String code = "(" + FieldUtils.toObjectType(type) + ") ";
+ code += "FieldUtils.getField(" + target + ", \"" + field.getName() + "\")";
+
+ return code;
+ }
+
+ public static String getMappedTypeSize(){
+ //todo
return null;
}
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
index 5f2eb61b51..d818e7ac10 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
@@ -3,11 +3,16 @@
* @date: 2024/7/14 上午4:28
*/
+import com.baidu.bjf.remoting.protobuf.annotation.Protobuf;
import com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass;
import com.google.protobuf.*;
+import com.taobao.arthas.protobuf.annotation.ProtobufCustomizedField;
+import com.taobao.arthas.protobuf.annotation.ProtobufIgnore;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
/**
* @author: FengYe
@@ -16,91 +21,8 @@
*/
@ProtobufClass
public class ArthasSampleRequest{
- @Override
- public String toString() {
- return "ArthasSampleRequest{" +
-// "name='" + name + '\'' +
- ", age=" + age +
- ", price=" + price +
- ", man=" + man +
- '}';
- }
-//
-// public String getName() {
-// return name;
-// }
-//
-// public void setName(String name) {
-// this.name = name;
-// }
- public Double getAge() {
- return age;
- }
-
- public void setAge(Double age) {
- this.age = age;
- }
-
- public Long getPrice() {
- return price;
- }
-
- public void setPrice(Long price) {
- this.price = price;
- }
-
- public Float getMan() {
- return man;
- }
-
- public void setMan(Float man) {
- this.man = man;
- }
-
-// private String name;
- private Double age;
- private Long price;
- private Float man;
-
-// public ArthasSampleRequest(ByteBuffer byteBuffer){
-// CodedInputStream codedInputStream = CodedInputStream.newInstance(byteBuffer);
-// try {
-// // 读取标签
-// int tag;
-// while ((tag = codedInputStream.readTag()) != 0) {
-// int fieldNumber = WireFormat.getTagFieldNumber(tag);
-// int wireType = WireFormat.getTagWireType(tag);
-//
-// System.out.println("Field Number: " + fieldNumber);
-// System.out.println("Wire Type: " + wireType);
-//
-//
-// // 根据字段编号和类型读取对应的数据
-// switch (wireType) {
-// case WireFormat.WIRETYPE_VARINT:
-// long varintValue = codedInputStream.readInt64();
-// System.out.println("Varint Value: " + varintValue);
-// break;
-// case WireFormat.WIRETYPE_FIXED32:
-// int fixed32Value = codedInputStream.readFixed32();
-// System.out.println("Fixed32 Value: " + fixed32Value);
-// break;
-// case WireFormat.WIRETYPE_FIXED64:
-// long fixed64Value = codedInputStream.readFixed64();
-// System.out.println("Fixed64 Value: " + fixed64Value);
-// break;
-// case WireFormat.WIRETYPE_LENGTH_DELIMITED:
-// int length = codedInputStream.readRawVarint32();
-// byte[] bytes = codedInputStream.readRawBytes(length);
-// System.out.println("Length-delimited Value: " + new String(bytes));
-// break;
-// default:
-// throw new IOException("Unsupported wire type: " + wireType);
-// }
-// }
-// } catch (IOException e) {
-// e.printStackTrace();
-// }
-// }
+ private String name;
+ private double age;
+ private long price;
}
diff --git a/arthas-grpc-server/src/main/resources/class_template.tpl b/arthas-grpc-server/src/main/resources/class_template.tpl
index 76ea118627..0ef374c117 100644
--- a/arthas-grpc-server/src/main/resources/class_template.tpl
+++ b/arthas-grpc-server/src/main/resources/class_template.tpl
@@ -9,9 +9,17 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
public static final long serialVersionUID = 1L;
private ${descriptorClsName} descriptor;
- public byte[] encode(${targetProxyClassName} t) throws IOException {
+ public byte[] encode(${targetProxyClassName} target) throws IOException {
CodecOutputByteArray output = CodecOutputByteArray.get();
- doWriteTo(t, output.getCodedOutputStream());
+
+
+ ${encodeFieldType} ${encodeFieldName} = null;
+ if (!CodedConstant.isNull(${encodeFieldGetter})) {
+ ${encodeFieldName} = ${writeValueToField};
+ ${encodeWriteFieldValue}
+ }
+
+
return output.getData();
}
@@ -20,35 +28,18 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
return readFrom(input);
}
- public int size(${targetProxyClassName} t) throws IOException {
+ public int size(${targetProxyClassName} target) throws IOException {
int size = 0;
${encodeFieldType} ${encodeFieldName} = null;
if (!CodedConstant.isNull(${encodeFieldGetter})) {
- ${encodeFieldName} = ${writeValueToField};
+ ${encodeFieldName} = ${encodeFieldGetter};
size += ${calcSize}
}
- ${checkNull}
return size;
}
- public void doWriteTo(${targetProxyClassName} t, CodedOutputStream output)
- throws IOException {
-
- ${encodeFieldType} ${encodeFieldName} = null;
- if (!CodedConstant.isNull(${encodeFieldGetter})) {
- ${encodeFieldName} = ${writeValueToField};
- ${encodeWriteFieldValue}
- }
-
- }
-
- public void writeTo(${targetProxyClassName} t, CodedOutputStream output)
- throws IOException {
- doWriteTo(t, output);
- }
-
public ${targetProxyClassName} readFrom(CodedInputStream input) throws IOException {
${targetProxyClassName} ret = new ${targetProxyClassName}();
From faff33fa54a24c0dd07dfb21158cc4fa50b5897b Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Tue, 30 Jul 2024 02:16:33 +0800
Subject: [PATCH 11/48] update: add protobuf codec
---
.../taobao/arthas/protobuf/ProtobufCodec.java | 4 +
.../taobao/arthas/protobuf/ProtobufField.java | 10 ++
.../taobao/arthas/protobuf/ProtobufProxy.java | 37 +++---
...eZigZap.java => ProtobufEnableZigZap.java} | 2 +-
.../protobuf/annotation/ProtobufPacked.java | 20 +++
.../arthas/protobuf/utils/FieldUtil.java | 123 ++++++++++++++++--
6 files changed, 168 insertions(+), 28 deletions(-)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/{EnableZigZap.java => ProtobufEnableZigZap.java} (91%)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufPacked.java
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufCodec.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufCodec.java
index 3f4ce336a2..38648013da 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufCodec.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufCodec.java
@@ -3,6 +3,8 @@
* @date: 2024/7/17 下午9:44
*/
+import java.io.IOException;
+
/**
* @author: FengYe
* @date: 2024/7/17 下午9:44
@@ -12,4 +14,6 @@ public interface ProtobufCodec {
byte[] encode(T t);
T decode(byte[] bytes);
+
+ int size(T t) throws IOException;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
index aeb387cc9d..34dcedf536 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
@@ -58,6 +58,8 @@ public class ProtobufField {
*/
private boolean wildcardType;
+ private boolean packed;
+
/**
* 处理 List 和 Map 类型字段
*
@@ -231,6 +233,14 @@ public void setWildcardType(boolean wildcardType) {
this.wildcardType = wildcardType;
}
+ public boolean isPacked() {
+ return packed;
+ }
+
+ public void setPacked(boolean packed) {
+ this.packed = packed;
+ }
+
@Override
public String toString() {
return "ProtobufField{" +
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index b5b85e6abd..dc7885a5b1 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -4,15 +4,12 @@
*/
-import com.baidu.bjf.remoting.protobuf.Codec;
-import com.taobao.arthas.protobuf.annotation.EnableZigZap;
+import com.taobao.arthas.protobuf.annotation.ProtobufEnableZigZap;
import com.taobao.arthas.protobuf.annotation.ProtobufClass;
import com.taobao.arthas.protobuf.utils.FieldUtil;
import com.taobao.arthas.protobuf.utils.MiniTemplator;
import com.taobao.arthas.service.req.ArthasSampleRequest;
-import java.io.IOException;
-import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -26,22 +23,17 @@ public class ProtobufProxy {
private static final Map codecCache = new ConcurrentHashMap();
- private Class> clazz;
+ private static Class> clazz;
- private MiniTemplator miniTemplator;
+ private static MiniTemplator miniTemplator;
- private List protobufFields;
+ private static List protobufFields;
public ProtobufProxy(Class> clazz) {
- Objects.requireNonNull(clazz);
- if (clazz.getAnnotation(ProtobufClass.class) == null) {
- throw new IllegalArgumentException("class is not annotated with @ProtobufClass");
- }
- this.clazz = clazz;
- loadProtobufField();
+
}
- public ProtobufCodec getCodecCacheSide() {
+ public ProtobufCodec getCodecCacheSide(Class> clazz) {
ProtobufCodec codec = codecCache.get(clazz.getName());
if (codec != null) {
return codec;
@@ -56,7 +48,14 @@ public ProtobufCodec getCodecCacheSide() {
}
}
- private ProtobufCodec create(Class> clazz) throws Exception {
+ public static ProtobufCodec create(Class> clazz) throws Exception {
+ Objects.requireNonNull(clazz);
+ if (clazz.getAnnotation(ProtobufClass.class) == null) {
+ throw new IllegalArgumentException("class is not annotated with @ProtobufClass");
+ }
+ ProtobufProxy.clazz = clazz;
+ loadProtobufField();
+
String path = Objects.requireNonNull(clazz.getResource(TEMPLATE_FILE)).getPath();
miniTemplator = new MiniTemplator(path);
@@ -72,7 +71,7 @@ private ProtobufCodec create(Class> clazz) throws Exception {
return null;
}
- private void processImportBlock() {
+ private static void processImportBlock() {
Set imports = new HashSet<>();
imports.add("java.util.*");
imports.add("java.io.IOException");
@@ -89,7 +88,7 @@ private void processImportBlock() {
}
}
- public void processEncodeBlock() {
+ private static void processEncodeBlock() {
for (ProtobufField protobufField : protobufFields) {
boolean isList = protobufField.isList();
boolean isMap = protobufField.isMap();
@@ -106,9 +105,9 @@ public void processEncodeBlock() {
}
- private void loadProtobufField() {
+ private static void loadProtobufField() {
protobufFields = FieldUtil.getProtobufFieldList(clazz,
- clazz.getAnnotation(EnableZigZap.class) != null
+ clazz.getAnnotation(ProtobufEnableZigZap.class) != null
);
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/EnableZigZap.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufEnableZigZap.java
similarity index 91%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/EnableZigZap.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufEnableZigZap.java
index b9d3ac83b1..c6566dccbd 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/EnableZigZap.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufEnableZigZap.java
@@ -15,5 +15,5 @@
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
-public @interface EnableZigZap {
+public @interface ProtobufEnableZigZap {
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufPacked.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufPacked.java
new file mode 100644
index 0000000000..65a7ba270e
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufPacked.java
@@ -0,0 +1,20 @@
+package com.taobao.arthas.protobuf.annotation;/**
+ * @author: 風楪
+ * @date: 2024/7/30 上午2:01
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author: FengYe
+ * @date: 2024/7/30 上午2:01
+ * @description: Packed 是否将 List 打包。对于基础类型的 List,打包可以减少无意义的 tag,提高压缩率
+ *
+ */
+@Target({ ElementType.FIELD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ProtobufPacked {
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
index 6f7acc27bb..ee2dbed203 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
@@ -3,23 +3,29 @@
* @date: 2024/7/25 上午12:33
*/
+
+import com.baidu.bjf.remoting.protobuf.EnumReadable;
import com.baidu.bjf.remoting.protobuf.annotation.Ignore;
import com.baidu.bjf.remoting.protobuf.code.CodedConstant;
-import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
-import com.baidu.bjf.remoting.protobuf.utils.FieldInfo;
import com.baidu.bjf.remoting.protobuf.utils.FieldUtils;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.CodedOutputStream;
+import com.google.protobuf.MapEntry;
+import com.google.protobuf.WireFormat;
+import com.taobao.arthas.protobuf.ProtobufCodec;
import com.taobao.arthas.protobuf.ProtobufField;
import com.taobao.arthas.protobuf.ProtobufFieldTypeEnum;
+import com.taobao.arthas.protobuf.ProtobufProxy;
+import com.taobao.arthas.protobuf.annotation.ProtobufPacked;
import com.taobao.arthas.protobuf.annotation.ProtobufCustomizedField;
import com.taobao.arthas.protobuf.annotation.ProtobufIgnore;
-import com.taobao.arthas.service.req.ArthasSampleRequest;
+
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
-import java.util.logging.Level;
/**
* @author: FengYe
@@ -89,7 +95,7 @@ public static List getProtobufFieldList(Class> clazz, boolean e
ProtobufCustomizedField customizedField = field.getAnnotation(ProtobufCustomizedField.class);
int order = 0;
- if (field.getAnnotation(Ignore.class) != null || Modifier.isTransient(field.getModifiers())) {
+ if (field.getAnnotation(ProtobufIgnore.class) != null || Modifier.isTransient(field.getModifiers())) {
continue;
}
@@ -156,6 +162,11 @@ public static List getProtobufFieldList(Class> clazz, boolean e
}
res.add(protobufField);
+
+ // 如果使用 packed 注解则打包
+ if (protobufField.isList() && (protobufField.getProtobufFieldType().isPrimitive() || protobufField.getProtobufFieldType().isEnum())) {
+ protobufField.setPacked(field.getAnnotation(ProtobufPacked.class) != null);
+ }
}
if (unOrderFields.isEmpty()) {
@@ -241,13 +252,109 @@ public static String getAccessMethod(String target, Field field, Class> clazz,
// use reflection to get value
String code = "(" + FieldUtils.toObjectType(type) + ") ";
- code += "FieldUtils.getField(" + target + ", \"" + field.getName() + "\")";
+ code += "FieldUtil.getField(" + target + ", \"" + field.getName() + "\")";
return code;
}
- public static String getMappedTypeSize(){
- //todo
+ public static String getMappedTypeSize(ProtobufField field) {
+ ProtobufFieldTypeEnum protobufFieldType = field.getProtobufFieldType();
+ int order = field.getOrder();
+ boolean isList = field.isList();
+ boolean isMap = field.isMap();
+ boolean packed = field.isPacked();
+ String type = protobufFieldType.getType().toUpperCase();
+
+ if (isList) {
+ //todo
+ }
+
return null;
}
+
+ public static int getListSize(int order, Collection> list, ProtobufFieldTypeEnum type, boolean packed) {
+ int size = 0;
+ if (list == null || list.isEmpty()) {
+ return size;
+ }
+
+ int dataSize = 0;
+ for (Object object : list) {
+ dataSize += getObjectSize(order, object, type);
+ }
+ size += dataSize;
+ if (type != ProtobufFieldTypeEnum.OBJECT) {
+ if (packed) {
+ size += com.google.protobuf.CodedOutputStream.computeInt32SizeNoTag(dataSize);
+ int tag = CodedConstant.makeTag(order, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ size += com.google.protobuf.CodedOutputStream.computeUInt32SizeNoTag(tag);
+ } else {
+ size += list.size() * CodedOutputStream.computeTagSize(order);
+ }
+ }
+ return size;
+ }
+
+ public static int getMapSize(int order, Map map,com.google.protobuf.WireFormat.FieldType keyType,
+ K defaultKey, com.google.protobuf.WireFormat.FieldType valueType, V defalutValue) {
+ int size = 0;
+ for (java.util.Map.Entry entry : map.entrySet()) {
+ MapEntry valuesDefaultEntry = MapEntry
+ . newDefaultInstance(null, keyType, defaultKey, valueType, defalutValue);
+
+ MapEntry values =
+ valuesDefaultEntry.newBuilderForType().setKey(entry.getKey()).setValue(entry.getValue()).build();
+
+ size += com.google.protobuf.CodedOutputStream.computeMessageSize(order, values);
+ }
+ return size;
+ }
+
+ public static int getObjectSize(int order, Object object, ProtobufFieldTypeEnum type) {
+ int size = 0;
+ if (object == null) {
+ return size;
+ }
+
+ if (type == ProtobufFieldTypeEnum.OBJECT) {
+ try {
+ Class cls = object.getClass();
+ ProtobufCodec target = ProtobufProxy.create(cls);
+ size = target.size(object);
+ size = size + CodedOutputStream.computeRawVarint32Size(size);
+ return size + CodedOutputStream.computeTagSize(order);
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ if (type == ProtobufFieldTypeEnum.STRING) {
+ size = CodedOutputStream.computeStringSizeNoTag(String.valueOf(object));
+ } else if (type == ProtobufFieldTypeEnum.BOOL) {
+ size = CodedOutputStream.computeBoolSizeNoTag(Boolean.valueOf(String.valueOf(object)));
+ } else if (type == ProtobufFieldTypeEnum.BYTES) {
+ byte[] bb = (byte[]) object;
+ size = CodedOutputStream.computeBytesSizeNoTag(ByteString.copyFrom(bb));
+ } else if (type == ProtobufFieldTypeEnum.DOUBLE) {
+ size = CodedOutputStream.computeDoubleSizeNoTag(Double.valueOf(object.toString()));
+ } else if (type == ProtobufFieldTypeEnum.FIXED32 || type == ProtobufFieldTypeEnum.SFIXED32) {
+ size = CodedOutputStream.computeFixed32SizeNoTag(Integer.valueOf(object.toString()));
+ } else if (type == ProtobufFieldTypeEnum.INT32 || type == ProtobufFieldTypeEnum.SINT32 || type == ProtobufFieldTypeEnum.UINT32) {
+ size = CodedOutputStream.computeInt32SizeNoTag(Integer.valueOf(object.toString()));
+ } else if (type == ProtobufFieldTypeEnum.FIXED64 || type == ProtobufFieldTypeEnum.SFIXED64) {
+ size = CodedOutputStream.computeSFixed64SizeNoTag(Long.valueOf(object.toString()));
+ } else if (type == ProtobufFieldTypeEnum.INT64 || type == ProtobufFieldTypeEnum.SINT64 || type == ProtobufFieldTypeEnum.UINT64) {
+ size = CodedOutputStream.computeInt64SizeNoTag(Long.valueOf(object.toString()));
+ } else if (type == ProtobufFieldTypeEnum.FLOAT) {
+ size = CodedOutputStream.computeFloatSizeNoTag(Float.valueOf(object.toString()));
+ } else if (type == ProtobufFieldTypeEnum.ENUM) {
+ if (object instanceof EnumReadable) {
+ size = CodedOutputStream.computeInt32SizeNoTag(((EnumReadable) object).value());
+ } else if (object instanceof Enum) {
+ size = CodedOutputStream.computeInt32SizeNoTag(((Enum) object).ordinal());
+ }
+ }
+
+ return size;
+ }
}
From 900c89f6c689a081ded0c3358095108b4b9da4d1 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Thu, 1 Aug 2024 00:51:16 +0800
Subject: [PATCH 12/48] update: add protobuf codec
---
.../taobao/arthas/protobuf/ProtobufProxy.java | 6 +-
.../arthas/protobuf/utils/FieldUtil.java | 202 ++++++++++++++++--
2 files changed, 184 insertions(+), 24 deletions(-)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index dc7885a5b1..58a221c64c 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -94,9 +94,9 @@ private static void processEncodeBlock() {
boolean isMap = protobufField.isMap();
ProtobufFieldTypeEnum protobufFieldType = protobufField.getProtobufFieldType();
- String encodeFieldGetter = FieldUtil.getAccessMethod("target", protobufField.getJavaField(), clazz, protobufField.isWildcardType());
+ String encodeFieldGetter = FieldUtil.getGetterDynamicString("target", protobufField.getJavaField(), clazz, protobufField.isWildcardType());
String encodeFileType = isList ? "Collection" : protobufField.getProtobufFieldType().getJavaType();
- String encodeFieldName = "f_" + protobufField.getOrder();
+ String encodeFieldName = FieldUtil.getDynamicFieldName(protobufField.getOrder());
miniTemplator.setVariable("encodeFileType",encodeFileType);
miniTemplator.setVariable("encodeFieldName",encodeFieldName);
@@ -114,7 +114,7 @@ private static void loadProtobufField() {
public static void main(String[] args) {
List protobufFieldList = FieldUtil.getProtobufFieldList(ArthasSampleRequest.class, false);
for (ProtobufField protobufField : protobufFieldList) {
- String target = FieldUtil.getAccessMethod("target", protobufField.getJavaField(), ArthasSampleRequest.class, protobufField.isWildcardType());
+ String target = FieldUtil.getGetterDynamicString("target", protobufField.getJavaField(), ArthasSampleRequest.class, protobufField.isWildcardType());
System.out.println(target);
}
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
index ee2dbed203..90a52adde6 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
@@ -5,9 +5,9 @@
import com.baidu.bjf.remoting.protobuf.EnumReadable;
-import com.baidu.bjf.remoting.protobuf.annotation.Ignore;
-import com.baidu.bjf.remoting.protobuf.code.CodedConstant;
-import com.baidu.bjf.remoting.protobuf.utils.FieldUtils;
+import com.baidu.bjf.remoting.protobuf.FieldType;
+import com.baidu.bjf.remoting.protobuf.code.ICodeGenerator;
+import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
import com.google.protobuf.ByteString;
import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.MapEntry;
@@ -38,6 +38,22 @@ public class FieldUtil {
public static final Map, ProtobufFieldTypeEnum> TYPE_MAPPER;
+ private static final Map PRIMITIVE_TYPE_MAPPING;
+
+ static {
+
+ PRIMITIVE_TYPE_MAPPING = new HashMap();
+
+ PRIMITIVE_TYPE_MAPPING.put(int.class.getSimpleName(), Integer.class.getSimpleName());
+ PRIMITIVE_TYPE_MAPPING.put(long.class.getSimpleName(), Long.class.getSimpleName());
+ PRIMITIVE_TYPE_MAPPING.put(short.class.getSimpleName(), Short.class.getSimpleName());
+ PRIMITIVE_TYPE_MAPPING.put(boolean.class.getSimpleName(), Boolean.class.getSimpleName());
+ PRIMITIVE_TYPE_MAPPING.put(double.class.getSimpleName(), Double.class.getSimpleName());
+ PRIMITIVE_TYPE_MAPPING.put(float.class.getSimpleName(), Float.class.getSimpleName());
+ PRIMITIVE_TYPE_MAPPING.put(char.class.getSimpleName(), Character.class.getSimpleName());
+ PRIMITIVE_TYPE_MAPPING.put(byte.class.getSimpleName(), Byte.class.getSimpleName());
+ }
+
static {
TYPE_MAPPER = new HashMap, ProtobufFieldTypeEnum>();
@@ -226,16 +242,16 @@ public static Object getField(Object t, String name) {
* @param wildcardType
* @return
*/
- public static String getAccessMethod(String target, Field field, Class> clazz, boolean wildcardType) {
+ public static String getGetterDynamicString(String target, Field field, Class> clazz, boolean wildcardType) {
if (field.getModifiers() == Modifier.PUBLIC && !wildcardType) {
return target + PACKAGE_SEPARATOR + field.getName();
}
String getter;
if ("boolean".equalsIgnoreCase(field.getType().getCanonicalName())) {
- getter = "is" + CodedConstant.capitalize(field.getName());
+ getter = "is" + capitalize(field.getName());
} else {
- getter = "get" + CodedConstant.capitalize(field.getName());
+ getter = "get" + capitalize(field.getName());
}
try {
@@ -250,26 +266,138 @@ public static String getAccessMethod(String target, Field field, Class> clazz,
type = "byte[]";
}
- // use reflection to get value
- String code = "(" + FieldUtils.toObjectType(type) + ") ";
+ String code = "(" + toObjectType(type) + ") ";
code += "FieldUtil.getField(" + target + ", \"" + field.getName() + "\")";
return code;
}
- public static String getMappedTypeSize(ProtobufField field) {
+ public static String getSizeDynamicString(ProtobufField field) {
ProtobufFieldTypeEnum protobufFieldType = field.getProtobufFieldType();
int order = field.getOrder();
boolean isList = field.isList();
boolean isMap = field.isMap();
boolean packed = field.isPacked();
- String type = protobufFieldType.getType().toUpperCase();
+ String typeName = protobufFieldType.getType().toUpperCase();
+ String dynamicFieldName = getDynamicFieldName(order);
+
if (isList) {
- //todo
+ return "FieldUtil.getListSize(" + order + "," + dynamicFieldName + "," + ProtobufFieldTypeEnum.class.getName() + "." + typeName
+ + "," + field.isPacked() + ");\n";
+ } else if (isMap) {
+ return "FieldUtil.getMapSize(" + order + "," + dynamicFieldName + "," + getMapFieldGenericParameterString(field) + ");\n";
}
- return null;
+ if (protobufFieldType == ProtobufFieldTypeEnum.OBJECT) {
+ return "FieldUtil.getObjectSize(" + order + "," + dynamicFieldName + ", " + ProtobufFieldTypeEnum.class.getName() + "."
+ + typeName + ");\n";
+ }
+
+ String javaType = protobufFieldType.getType();
+ if (protobufFieldType == ProtobufFieldTypeEnum.STRING) {
+ javaType = "String";
+ }
+
+ if (protobufFieldType == ProtobufFieldTypeEnum.BYTES) {
+ javaType = "ByteArray";
+ }
+ javaType = capitalize(javaType);
+ dynamicFieldName = dynamicFieldName + protobufFieldType.getToPrimitiveType();
+ //todo check 感觉上面这个有点问题,测试的时候看下
+ return "com.google.protobuf.CodedOutputStream.compute" + javaType + "Size(" + order + "," + dynamicFieldName + ")"
+ + ");\n";
+ }
+
+ private static String getMapFieldGenericParameterString(ProtobufField field) {
+ String wireFormatClassName = WireFormat.FieldType.class.getCanonicalName();
+ ProtobufFieldTypeEnum fieldType = TYPE_MAPPER.get(field.getGenericKeyType());
+ String keyClass;
+ String defaultKeyValue;
+ if (fieldType == null) {
+ if (Enum.class.isAssignableFrom(field.getGenericKeyType())) {
+ keyClass = wireFormatClassName + ".ENUM";
+ Class> declaringClass = field.getGenericKeyType();
+ Field[] fields = declaringClass.getFields();
+ if (fields.length > 0) {
+ defaultKeyValue = field.getGenericKeyType().getCanonicalName() + "."
+ + fields[0].getName();
+ } else {
+ defaultKeyValue = "0";
+ }
+
+ } else {
+ keyClass = wireFormatClassName + ".MESSAGE";
+ boolean hasDefaultConstructor = hasDefaultConstructor(field.getGenericKeyType());
+ if (!hasDefaultConstructor) {
+ throw new IllegalArgumentException("Class '" + field.getGenericKeyType().getCanonicalName()
+ + "' must has default constructor method with no parameters.");
+ }
+ defaultKeyValue =
+ "new " + field.getGenericKeyType().getCanonicalName() + "()";
+ }
+ } else {
+ keyClass = wireFormatClassName + "." + fieldType.toString();
+
+ defaultKeyValue = fieldType.getDefaultValue();
+ }
+
+ fieldType = TYPE_MAPPER.get(field.getGenericValueType());
+ String valueClass;
+ String defaultValueValue;
+ if (fieldType == null) {
+ if (Enum.class.isAssignableFrom(field.getGenericValueType())) {
+ valueClass = wireFormatClassName + ".ENUM";
+ Class> declaringClass = field.getGenericValueType();
+ Field[] fields = declaringClass.getFields();
+ if (fields.length > 0) {
+ defaultValueValue = field.getGenericValueType().getCanonicalName()
+ + "." + fields[0].getName();
+ } else {
+ defaultValueValue = "0";
+ }
+
+ } else {
+ valueClass = wireFormatClassName + ".MESSAGE";
+ // check constructor
+ boolean hasDefaultConstructor = hasDefaultConstructor(field.getGenericValueType());
+ if (!hasDefaultConstructor) {
+ throw new IllegalArgumentException("Class '" + field.getGenericValueType().getCanonicalName()
+ + "' must has default constructor method with no parameters.");
+ }
+ defaultValueValue =
+ "new " + field.getGenericValueType().getCanonicalName() + "()";
+ }
+ } else {
+ valueClass = wireFormatClassName + "." + fieldType;
+ defaultValueValue = fieldType.getDefaultValue();
+ }
+ String joinedSentence = keyClass + "," + defaultKeyValue + "," + valueClass + "," + defaultValueValue;
+ return joinedSentence;
+ }
+
+ public static boolean hasDefaultConstructor(Class> cls) {
+ if (cls == null) {
+ return false;
+ }
+ try {
+ cls.getConstructor(new Class>[0]);
+ } catch (NoSuchMethodException e) {
+ return false;
+ } catch (SecurityException e) {
+ throw new IllegalArgumentException(e.getMessage(), e);
+ }
+ return true;
+ }
+
+ /**
+ * 通过 order 获取动态生成的字段名
+ *
+ * @param order
+ * @return
+ */
+ public static String getDynamicFieldName(int order) {
+ return "f_" + order;
}
public static int getListSize(int order, Collection> list, ProtobufFieldTypeEnum type, boolean packed) {
@@ -286,7 +414,7 @@ public static int getListSize(int order, Collection> list, ProtobufFieldTypeEn
if (type != ProtobufFieldTypeEnum.OBJECT) {
if (packed) {
size += com.google.protobuf.CodedOutputStream.computeInt32SizeNoTag(dataSize);
- int tag = CodedConstant.makeTag(order, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ int tag = makeTag(order, WireFormat.WIRETYPE_LENGTH_DELIMITED);
size += com.google.protobuf.CodedOutputStream.computeUInt32SizeNoTag(tag);
} else {
size += list.size() * CodedOutputStream.computeTagSize(order);
@@ -295,12 +423,12 @@ public static int getListSize(int order, Collection> list, ProtobufFieldTypeEn
return size;
}
- public static int getMapSize(int order, Map map,com.google.protobuf.WireFormat.FieldType keyType,
+ public static int getMapSize(int order, Map map, com.google.protobuf.WireFormat.FieldType keyType,
K defaultKey, com.google.protobuf.WireFormat.FieldType valueType, V defalutValue) {
int size = 0;
for (java.util.Map.Entry entry : map.entrySet()) {
MapEntry valuesDefaultEntry = MapEntry
- . newDefaultInstance(null, keyType, defaultKey, valueType, defalutValue);
+ .newDefaultInstance(null, keyType, defaultKey, valueType, defalutValue);
MapEntry values =
valuesDefaultEntry.newBuilderForType().setKey(entry.getKey()).setValue(entry.getValue()).build();
@@ -348,13 +476,45 @@ public static int getObjectSize(int order, Object object, ProtobufFieldTypeEnum
} else if (type == ProtobufFieldTypeEnum.FLOAT) {
size = CodedOutputStream.computeFloatSizeNoTag(Float.valueOf(object.toString()));
} else if (type == ProtobufFieldTypeEnum.ENUM) {
- if (object instanceof EnumReadable) {
- size = CodedOutputStream.computeInt32SizeNoTag(((EnumReadable) object).value());
- } else if (object instanceof Enum) {
- size = CodedOutputStream.computeInt32SizeNoTag(((Enum) object).ordinal());
- }
+ size = CodedOutputStream.computeInt32SizeNoTag(((Enum) object).ordinal());
}
-
return size;
}
+
+ /**
+ * 首字母大写
+ *
+ * @param str
+ * @return
+ */
+ public static String capitalize(String str) {
+ if (str == null || str.isEmpty()) {
+ return str;
+ }
+ return Character.toTitleCase(str.charAt(0)) + str.substring(1);
+ }
+
+ /**
+ * 生成 protobuf tag
+ *
+ * @param fieldNumber
+ * @param wireType
+ * @return
+ */
+ public static int makeTag(final int fieldNumber, final int wireType) {
+ return (fieldNumber << 3) | wireType;
+ }
+
+ /**
+ * 基础类型转为包装对象
+ *
+ * @param primitiveType
+ * @return
+ */
+ public static String toObjectType(String primitiveType) {
+ if (PRIMITIVE_TYPE_MAPPING.containsKey(primitiveType)) {
+ return PRIMITIVE_TYPE_MAPPING.get(primitiveType);
+ }
+ return primitiveType;
+ }
}
From 8dd4c42a5d65ce32742a0cf402d39b2ae7eb32b5 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Fri, 2 Aug 2024 01:43:09 +0800
Subject: [PATCH 13/48] update: add protobuf codec
---
.../taobao/arthas/protobuf/ProtobufProxy.java | 18 ++++++----
.../arthas/protobuf/utils/FieldUtil.java | 34 ++++++++++++++++++-
.../src/main/resources/class_template.tpl | 14 ++++----
3 files changed, 52 insertions(+), 14 deletions(-)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index 58a221c64c..4e0c7b2562 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -94,13 +94,19 @@ private static void processEncodeBlock() {
boolean isMap = protobufField.isMap();
ProtobufFieldTypeEnum protobufFieldType = protobufField.getProtobufFieldType();
- String encodeFieldGetter = FieldUtil.getGetterDynamicString("target", protobufField.getJavaField(), clazz, protobufField.isWildcardType());
- String encodeFileType = isList ? "Collection" : protobufField.getProtobufFieldType().getJavaType();
- String encodeFieldName = FieldUtil.getDynamicFieldName(protobufField.getOrder());
+ String dynamicFieldGetter = FieldUtil.getGetterDynamicString("target", protobufField.getJavaField(), clazz, protobufField.isWildcardType());
+ String dynamicFieldType = isList ? "Collection" : protobufField.getProtobufFieldType().getJavaType();
+ String dynamicFieldName = FieldUtil.getDynamicFieldName(protobufField.getOrder());
- miniTemplator.setVariable("encodeFileType",encodeFileType);
- miniTemplator.setVariable("encodeFieldName",encodeFieldName);
- miniTemplator.setVariable("encodeFieldGetter",encodeFieldGetter);
+ miniTemplator.setVariable("dynamicFieldType", dynamicFieldType);
+ miniTemplator.setVariable("dynamicFieldName", dynamicFieldName);
+ miniTemplator.setVariable("dynamicFieldGetter", dynamicFieldGetter);
+ String sizeDynamicString = FieldUtil.getSizeDynamicString(protobufField);
+ miniTemplator.setVariable("sizeDynamicString", sizeDynamicString);
+
+ //todo
+
+ miniTemplator.addBlock("encodeFields");
}
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
index 90a52adde6..04e2770f6f 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
@@ -277,7 +277,6 @@ public static String getSizeDynamicString(ProtobufField field) {
int order = field.getOrder();
boolean isList = field.isList();
boolean isMap = field.isMap();
- boolean packed = field.isPacked();
String typeName = protobufFieldType.getType().toUpperCase();
String dynamicFieldName = getDynamicFieldName(order);
@@ -517,4 +516,37 @@ public static String toObjectType(String primitiveType) {
}
return primitiveType;
}
+
+
+ public static boolean isNull(Object o) {
+ return o == null;
+ }
+
+ public static boolean isNull(double o) {
+ return false;
+ }
+
+ public static boolean isNull(int o) {
+ return false;
+ }
+
+ public static boolean isNull(byte o) {
+ return false;
+ }
+
+ public static boolean isNull(short o) {
+ return false;
+ }
+
+ public static boolean isNull(long o) {
+ return false;
+ }
+
+ public static boolean isNull(float o) {
+ return false;
+ }
+
+ public static boolean isNull(char o) {
+ return false;
+ }
}
diff --git a/arthas-grpc-server/src/main/resources/class_template.tpl b/arthas-grpc-server/src/main/resources/class_template.tpl
index 0ef374c117..68c7cf3974 100644
--- a/arthas-grpc-server/src/main/resources/class_template.tpl
+++ b/arthas-grpc-server/src/main/resources/class_template.tpl
@@ -13,9 +13,9 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
CodecOutputByteArray output = CodecOutputByteArray.get();
- ${encodeFieldType} ${encodeFieldName} = null;
- if (!CodedConstant.isNull(${encodeFieldGetter})) {
- ${encodeFieldName} = ${writeValueToField};
+ ${dynamicFieldType} ${dynamicFieldName} = null;
+ if (!FieldUtil.isNull(${dynamicFieldGetter})) {
+ ${dynamicFieldName} = ${dynamicFieldGetter};
${encodeWriteFieldValue}
}
@@ -31,10 +31,10 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
public int size(${targetProxyClassName} target) throws IOException {
int size = 0;
- ${encodeFieldType} ${encodeFieldName} = null;
- if (!CodedConstant.isNull(${encodeFieldGetter})) {
- ${encodeFieldName} = ${encodeFieldGetter};
- size += ${calcSize}
+ ${dynamicFieldType} ${dynamicFieldName} = null;
+ if (!CodedConstant.isNull(${dynamicFieldGetter})) {
+ ${dynamicFieldName} = ${dynamicFieldGetter};
+ size += ${sizeDynamicString}
}
return size;
From bc81e9837f62e0b074f14abb86b8678a906b1dee Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Sat, 3 Aug 2024 20:53:03 +0800
Subject: [PATCH 14/48] update: add protobuf codec
---
.../taobao/arthas/protobuf/ProtobufProxy.java | 29 +-
.../utils/CodedOutputStreamCache.java | 52 ++++
.../arthas/protobuf/utils/FieldUtil.java | 288 ++++++++++++++++--
.../src/main/resources/class_template.tpl | 9 +-
4 files changed, 344 insertions(+), 34 deletions(-)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/CodedOutputStreamCache.java
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index 4e0c7b2562..57528c8150 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -4,12 +4,14 @@
*/
+import com.baidu.bjf.remoting.protobuf.code.CodedConstant;
import com.taobao.arthas.protobuf.annotation.ProtobufEnableZigZap;
import com.taobao.arthas.protobuf.annotation.ProtobufClass;
import com.taobao.arthas.protobuf.utils.FieldUtil;
import com.taobao.arthas.protobuf.utils.MiniTemplator;
import com.taobao.arthas.service.req.ArthasSampleRequest;
+import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -48,7 +50,7 @@ public ProtobufCodec getCodecCacheSide(Class> clazz) {
}
}
- public static ProtobufCodec create(Class> clazz) throws Exception {
+ public static ProtobufCodec create(Class> clazz) {
Objects.requireNonNull(clazz);
if (clazz.getAnnotation(ProtobufClass.class) == null) {
throw new IllegalArgumentException("class is not annotated with @ProtobufClass");
@@ -57,7 +59,11 @@ public static ProtobufCodec create(Class> clazz) throws Exception {
loadProtobufField();
String path = Objects.requireNonNull(clazz.getResource(TEMPLATE_FILE)).getPath();
- miniTemplator = new MiniTemplator(path);
+ try {
+ miniTemplator = new MiniTemplator(path);
+ } catch (Exception e) {
+ throw new RuntimeException("miniTemplator init failed. " + path, e);
+ }
miniTemplator.setVariable("package", "package " + clazz.getPackage().getName() + ";");
@@ -66,7 +72,8 @@ public static ProtobufCodec create(Class> clazz) throws Exception {
miniTemplator.setVariable("className", clazz.getName() + "$$ProxyClass");
miniTemplator.setVariable("codecClassName", ProtobufCodec.class.getName());
miniTemplator.setVariable("targetProxyClassName", clazz.getName());
-
+ processEncodeBlock();
+ processDecodeBlock();
return null;
}
@@ -90,12 +97,8 @@ private static void processImportBlock() {
private static void processEncodeBlock() {
for (ProtobufField protobufField : protobufFields) {
- boolean isList = protobufField.isList();
- boolean isMap = protobufField.isMap();
-
- ProtobufFieldTypeEnum protobufFieldType = protobufField.getProtobufFieldType();
- String dynamicFieldGetter = FieldUtil.getGetterDynamicString("target", protobufField.getJavaField(), clazz, protobufField.isWildcardType());
- String dynamicFieldType = isList ? "Collection" : protobufField.getProtobufFieldType().getJavaType();
+ String dynamicFieldGetter = FieldUtil.getGetterDynamicString(protobufField, clazz);
+ String dynamicFieldType = protobufField.isList() ? "Collection" : protobufField.getProtobufFieldType().getJavaType();
String dynamicFieldName = FieldUtil.getDynamicFieldName(protobufField.getOrder());
miniTemplator.setVariable("dynamicFieldType", dynamicFieldType);
@@ -103,13 +106,15 @@ private static void processEncodeBlock() {
miniTemplator.setVariable("dynamicFieldGetter", dynamicFieldGetter);
String sizeDynamicString = FieldUtil.getSizeDynamicString(protobufField);
miniTemplator.setVariable("sizeDynamicString", sizeDynamicString);
-
- //todo
-
+ miniTemplator.setVariable("encodeWriteFieldValue", FieldUtil.getWriteByteDynamicString(protobufField));
miniTemplator.addBlock("encodeFields");
}
}
+ private static void processDecodeBlock() {
+
+ }
+
private static void loadProtobufField() {
protobufFields = FieldUtil.getProtobufFieldList(clazz,
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/CodedOutputStreamCache.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/CodedOutputStreamCache.java
new file mode 100644
index 0000000000..756943f602
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/CodedOutputStreamCache.java
@@ -0,0 +1,52 @@
+package com.taobao.arthas.protobuf.utils;/**
+ * @author: 風楪
+ * @date: 2024/8/3 下午7:20
+ */
+
+import com.google.protobuf.CodedOutputStream;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Stack;
+
+/**
+ * @author: FengYe
+ * @date: 2024/8/3 下午7:20
+ * @description: 针对 CodedOutputStream 的缓存处理,避免创建大量 CodedOutputStream;使用 threadLocal 中的 stack 来缓存对象
+ */
+public class CodedOutputStreamCache {
+ private static final ThreadLocal> instanceGetter = ThreadLocal.withInitial(Stack::new);
+ private final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ private final CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(byteArrayOutputStream, 0);
+
+ // 每个线程 stack 中最多存储的 buffer 数量
+ private static final int MAX_ELEMENT = 5;
+
+ public static CodedOutputStreamCache get() {
+ Stack stack = instanceGetter.get();
+ if (!stack.isEmpty()) {
+ return stack.pop();
+ }
+ return new CodedOutputStreamCache();
+ }
+
+ public byte[] getData() throws IOException {
+ this.codedOutputStream.flush();
+ byte[] bytes = this.byteArrayOutputStream.toByteArray();
+ this.recycle();
+ return bytes;
+ }
+
+ public CodedOutputStream getCodedOutputStream() {
+ return codedOutputStream;
+ }
+
+ private void recycle(){
+ this.byteArrayOutputStream.reset();
+ Stack stack = instanceGetter.get();
+ if (stack.size() >= MAX_ELEMENT) {
+ return;
+ }
+ stack.push(this);
+ }
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
index 04e2770f6f..00cc942a24 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
@@ -4,8 +4,10 @@
*/
+import com.baidu.bjf.remoting.protobuf.Codec;
import com.baidu.bjf.remoting.protobuf.EnumReadable;
import com.baidu.bjf.remoting.protobuf.FieldType;
+import com.baidu.bjf.remoting.protobuf.code.CodecOutputByteArray;
import com.baidu.bjf.remoting.protobuf.code.ICodeGenerator;
import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
import com.google.protobuf.ByteString;
@@ -21,6 +23,7 @@
import com.taobao.arthas.protobuf.annotation.ProtobufIgnore;
+import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
@@ -34,12 +37,19 @@
*/
public class FieldUtil {
- public static final String PACKAGE_SEPARATOR = ".";
public static final Map, ProtobufFieldTypeEnum> TYPE_MAPPER;
private static final Map PRIMITIVE_TYPE_MAPPING;
+ private static final String dynamicTarget = "target";
+
+ public static final String PACKAGE_SEPARATOR = ".";
+
+ private static final String LINE_BREAK = "\n";
+
+ private static final String CODE_OUTPUT_STREAM_OBJ_NAME = "output";
+
static {
PRIMITIVE_TYPE_MAPPING = new HashMap();
@@ -233,18 +243,13 @@ public static Object getField(Object t, String name) {
return null;
}
- /**
- * 获取目标的访问方法字符串,如果目标已经声明 getter 则返回 getter,否则使用 FieldUtil.getField
- *
- * @param target
- * @param field
- * @param clazz
- * @param wildcardType
- * @return
- */
- public static String getGetterDynamicString(String target, Field field, Class> clazz, boolean wildcardType) {
+
+ public static String getGetterDynamicString(ProtobufField protobufField, Class> dynamicTargetClass) {
+ Field field = protobufField.getJavaField();
+ boolean wildcardType = protobufField.isWildcardType();
+
if (field.getModifiers() == Modifier.PUBLIC && !wildcardType) {
- return target + PACKAGE_SEPARATOR + field.getName();
+ return dynamicTarget + PACKAGE_SEPARATOR + field.getName();
}
String getter;
@@ -255,8 +260,8 @@ public static String getGetterDynamicString(String target, Field field, Class>
}
try {
- clazz.getMethod(getter, new Class>[0]);
- return target + PACKAGE_SEPARATOR + getter + "()";
+ dynamicTargetClass.getMethod(getter, new Class>[0]);
+ return dynamicTarget + PACKAGE_SEPARATOR + getter + "()";
} catch (Exception e) {
//todo log
}
@@ -267,11 +272,17 @@ public static String getGetterDynamicString(String target, Field field, Class>
}
String code = "(" + toObjectType(type) + ") ";
- code += "FieldUtil.getField(" + target + ", \"" + field.getName() + "\")";
+ code += "FieldUtil.getField(" + dynamicTarget + ", \"" + field.getName() + "\")";
return code;
}
+ /**
+ * 获取计算 size 动态字符串
+ *
+ * @param field
+ * @return
+ */
public static String getSizeDynamicString(ProtobufField field) {
ProtobufFieldTypeEnum protobufFieldType = field.getProtobufFieldType();
int order = field.getOrder();
@@ -283,14 +294,14 @@ public static String getSizeDynamicString(ProtobufField field) {
if (isList) {
return "FieldUtil.getListSize(" + order + "," + dynamicFieldName + "," + ProtobufFieldTypeEnum.class.getName() + "." + typeName
- + "," + field.isPacked() + ");\n";
+ + "," + field.isPacked() + ");" + LINE_BREAK;
} else if (isMap) {
- return "FieldUtil.getMapSize(" + order + "," + dynamicFieldName + "," + getMapFieldGenericParameterString(field) + ");\n";
+ return "FieldUtil.getMapSize(" + order + "," + dynamicFieldName + "," + getMapFieldGenericParameterString(field) + ");" + LINE_BREAK;
}
if (protobufFieldType == ProtobufFieldTypeEnum.OBJECT) {
return "FieldUtil.getObjectSize(" + order + "," + dynamicFieldName + ", " + ProtobufFieldTypeEnum.class.getName() + "."
- + typeName + ");\n";
+ + typeName + ");" + LINE_BREAK;
}
String javaType = protobufFieldType.getType();
@@ -305,7 +316,246 @@ public static String getSizeDynamicString(ProtobufField field) {
dynamicFieldName = dynamicFieldName + protobufFieldType.getToPrimitiveType();
//todo check 感觉上面这个有点问题,测试的时候看下
return "com.google.protobuf.CodedOutputStream.compute" + javaType + "Size(" + order + "," + dynamicFieldName + ")"
- + ");\n";
+ + ");" + LINE_BREAK;
+ }
+
+ /**
+ * 获取写入 CodedOutputStream 动态字符串
+ *
+ * @param protobufField
+ * @return
+ */
+ public static String getWriteByteDynamicString(ProtobufField protobufField) {
+ ProtobufFieldTypeEnum protobufFieldType = protobufField.getProtobufFieldType();
+ int order = protobufField.getOrder();
+ String dynamicFieldName = getDynamicFieldName(protobufField.getOrder());
+ StringBuilder sb = new StringBuilder();
+ sb.append("if (").append(dynamicFieldName).append(" != null){").append(LINE_BREAK);
+
+ if (protobufField.isList()) {
+ String typeString = protobufFieldType.getType().toUpperCase();
+ sb.append("Field.writeList(").append(CODE_OUTPUT_STREAM_OBJ_NAME).append(",");
+ sb.append(order).append(",").append(ProtobufFieldTypeEnum.class.getName()).append(".").append(typeString);
+ sb.append(",").append(dynamicFieldName).append(",").append(Boolean.valueOf(protobufField.isPacked())).append(")")
+ .append(";" + LINE_BREAK).append("}").append(LINE_BREAK);
+ return sb.toString();
+ } else if (protobufField.isMap()) {
+ sb.append("Field.writeMap(").append(CODE_OUTPUT_STREAM_OBJ_NAME).append(",");
+ sb.append(order).append(",").append(dynamicFieldName);
+
+ String joinedSentence = getMapFieldGenericParameterString(protobufField);
+ sb.append(",").append(joinedSentence);
+
+ sb.append(")").append(";" + LINE_BREAK).append("}").append(LINE_BREAK);
+ return sb.toString();
+ } else {
+ dynamicFieldName = dynamicFieldName + protobufFieldType.getToPrimitiveType();
+ }
+
+ if (protobufFieldType == ProtobufFieldTypeEnum.OBJECT) {
+ String typeString = protobufFieldType.getType().toUpperCase();
+ sb.append("Field.writeObject(").append(CODE_OUTPUT_STREAM_OBJ_NAME).append(",");
+ sb.append(order).append(",").append(ProtobufFieldTypeEnum.class.getName()).append(".").append(typeString);
+ sb.append(",").append(dynamicFieldName).append(", false)").append(";" + LINE_BREAK).append("}")
+ .append(LINE_BREAK);
+ return sb.toString();
+ }
+
+ if (protobufFieldType == ProtobufFieldTypeEnum.STRING) {
+ sb.append(CODE_OUTPUT_STREAM_OBJ_NAME).append(".writeString(").append(order);
+ sb.append(", ").append(dynamicFieldName).append(")").append(";" + LINE_BREAK).append("}")
+ .append(LINE_BREAK);
+ return sb.toString();
+ }
+
+ if (protobufFieldType == ProtobufFieldTypeEnum.BYTES) {
+ sb.append(CODE_OUTPUT_STREAM_OBJ_NAME).append(".writeByteArray(").append(order);
+ sb.append(", ").append(dynamicFieldName).append(")").append(";" + LINE_BREAK).append("}")
+ .append(LINE_BREAK);
+ return sb.toString();
+ }
+
+ String t = protobufFieldType.getType();
+ t = capitalize(t);
+
+ sb.append(CODE_OUTPUT_STREAM_OBJ_NAME).append(".write").append(t).append("(").append(order);
+ sb.append(", ").append(dynamicFieldName).append(")").append(";" + LINE_BREAK).append("}")
+ .append(LINE_BREAK);
+ return sb.toString();
+ }
+
+ public static void writeList(CodedOutputStream out, int order, ProtobufFieldTypeEnum type, Collection list)
+ throws IOException {
+ writeList(out, order, type, list, false);
+ }
+
+ /**
+ * java list 写入 CodedOutputStream
+ */
+ public static void writeList(CodedOutputStream out, int order, ProtobufFieldTypeEnum type, Collection list, boolean packed)
+ throws IOException {
+ if (list == null || list.isEmpty()) {
+ return;
+ }
+
+ CodedOutputStreamCache output = CodedOutputStreamCache.get();
+ for (Object object : list) {
+ if (object == null) {
+ throw new NullPointerException("List can not include Null value.");
+ }
+ writeObject(output.getCodedOutputStream(), order, type, object, true, !packed);
+ }
+ byte[] byteArray = output.getData();
+
+ if (packed) {
+ out.writeUInt32NoTag(makeTag(order, WireFormat.WIRETYPE_LENGTH_DELIMITED));
+ out.writeUInt32NoTag(byteArray.length);
+ }
+
+ out.write(byteArray, 0, byteArray.length);
+
+ }
+
+ /**
+ * java map 写入 output
+ */
+ public static void writeMap(CodedOutputStream output, int order, Map map,
+ com.google.protobuf.WireFormat.FieldType keyType, K defaultKey,
+ com.google.protobuf.WireFormat.FieldType valueType, V defalutValue) throws IOException {
+ MapEntry valuesDefaultEntry = MapEntry
+ .newDefaultInstance(null, keyType, defaultKey, valueType, defalutValue);
+ for (java.util.Map.Entry entry : map.entrySet()) {
+ MapEntry values =
+ valuesDefaultEntry.newBuilderForType().setKey(entry.getKey()).setValue(entry.getValue()).build();
+ output.writeMessage(order, values);
+ }
+ }
+
+ /**
+ * java object 写入 CodedOutputStream
+ */
+ public static void writeObject(CodedOutputStream out, int order, ProtobufFieldTypeEnum type, Object o, boolean list,
+ boolean withTag) throws IOException {
+ if (o == null) {
+ return;
+ }
+
+ if (type == ProtobufFieldTypeEnum.OBJECT) {
+
+ Class cls = o.getClass();
+ ProtobufCodec target = ProtobufProxy.create(cls);
+
+ if (withTag) {
+ out.writeUInt32NoTag(makeTag(order, WireFormat.WIRETYPE_LENGTH_DELIMITED));
+ }
+
+ byte[] byteArray = target.encode(o);
+ out.writeUInt32NoTag(byteArray.length);
+ out.write(byteArray, 0, byteArray.length);
+
+ return;
+ }
+
+ if (type == ProtobufFieldTypeEnum.BOOL) {
+ if (withTag) {
+ out.writeBool(order, (Boolean) o);
+ } else {
+ out.writeBoolNoTag((Boolean) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.BYTES) {
+ byte[] bb = (byte[]) o;
+ if (withTag) {
+ out.writeBytes(order, ByteString.copyFrom(bb));
+ } else {
+ out.writeBytesNoTag(ByteString.copyFrom(bb));
+ }
+ } else if (type == ProtobufFieldTypeEnum.DOUBLE) {
+ if (withTag) {
+ out.writeDouble(order, (Double) o);
+ } else {
+ out.writeDoubleNoTag((Double) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.FIXED32) {
+ if (withTag) {
+ out.writeFixed32(order, (Integer) o);
+ } else {
+ out.writeFixed32NoTag((Integer) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.FIXED64) {
+ if (withTag) {
+ out.writeFixed64(order, (Long) o);
+ } else {
+ out.writeFixed64NoTag((Long) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.FLOAT) {
+ if (withTag) {
+ out.writeFloat(order, (Float) o);
+ } else {
+ out.writeFloatNoTag((Float) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.INT32) {
+ if (withTag) {
+ out.writeInt32(order, (Integer) o);
+ } else {
+ out.writeInt32NoTag((Integer) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.INT64) {
+ if (withTag) {
+ out.writeInt64(order, (Long) o);
+ } else {
+ out.writeInt64NoTag((Long) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.SFIXED32) {
+ if (withTag) {
+ out.writeSFixed32(order, (Integer) o);
+ } else {
+ out.writeSFixed32NoTag((Integer) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.SFIXED64) {
+ if (withTag) {
+ out.writeSFixed64(order, (Long) o);
+ } else {
+ out.writeSFixed64NoTag((Long) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.SINT32) {
+ if (withTag) {
+ out.writeSInt32(order, (Integer) o);
+ } else {
+ out.writeSInt32NoTag((Integer) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.SINT64) {
+ if (withTag) {
+ out.writeSInt64(order, (Long) o);
+ } else {
+ out.writeSInt64NoTag((Long) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.STRING) {
+ if (withTag) {
+ out.writeBytes(order, ByteString.copyFromUtf8(String.valueOf(o)));
+ } else {
+ out.writeBytesNoTag(ByteString.copyFromUtf8(String.valueOf(o)));
+ }
+ } else if (type == ProtobufFieldTypeEnum.UINT32) {
+ if (withTag) {
+ out.writeUInt32(order, (Integer) o);
+ } else {
+ out.writeUInt32NoTag((Integer) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.UINT64) {
+ if (withTag) {
+ out.writeUInt64(order, (Long) o);
+ } else {
+ out.writeUInt64NoTag((Long) o);
+ }
+ } else if (type == ProtobufFieldTypeEnum.ENUM) {
+ int value;
+ value = ((Enum) o).ordinal();
+ if (withTag) {
+ out.writeEnum(order, value);
+ } else {
+ out.writeEnumNoTag(value);
+ }
+ }
}
private static String getMapFieldGenericParameterString(ProtobufField field) {
diff --git a/arthas-grpc-server/src/main/resources/class_template.tpl b/arthas-grpc-server/src/main/resources/class_template.tpl
index 68c7cf3974..c04e8ba504 100644
--- a/arthas-grpc-server/src/main/resources/class_template.tpl
+++ b/arthas-grpc-server/src/main/resources/class_template.tpl
@@ -10,8 +10,13 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
private ${descriptorClsName} descriptor;
public byte[] encode(${targetProxyClassName} target) throws IOException {
- CodecOutputByteArray output = CodecOutputByteArray.get();
+ CodedOutputStreamCache outputCache = CodedOutputStreamCache.get();
+ doWriteTo(target, outputCache.getCodedOutputStream());
+ return outputCache.getData();
+ }
+ public void doWriteTo(${targetProxyClassName} t, CodedOutputStream output)
+ throws IOException {
${dynamicFieldType} ${dynamicFieldName} = null;
if (!FieldUtil.isNull(${dynamicFieldGetter})) {
@@ -19,8 +24,6 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
${encodeWriteFieldValue}
}
-
- return output.getData();
}
public ${targetProxyClassName} decode(byte[] bb) throws IOException {
From 1640f19f810710c7eb6b7d7909be08aabcfbce1e Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Sun, 4 Aug 2024 06:10:00 +0800
Subject: [PATCH 15/48] update: add protobuf codec
---
.../taobao/arthas/protobuf/ProtobufProxy.java | 47 +++-
.../arthas/protobuf/utils/FieldUtil.java | 225 ++++++++++++++++--
.../service/req/ArthasSampleRequest.java | 16 ++
arthas-grpc-server/src/main/proto/Test.proto | 10 +-
.../src/main/resources/class_template.tpl | 4 +-
5 files changed, 277 insertions(+), 25 deletions(-)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index 57528c8150..dcd6c49b6d 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -4,7 +4,11 @@
*/
+import com.baidu.bjf.remoting.protobuf.FieldType;
+import com.baidu.bjf.remoting.protobuf.code.ClassCode;
import com.baidu.bjf.remoting.protobuf.code.CodedConstant;
+import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
+import com.baidu.bjf.remoting.protobuf.utils.FieldInfo;
import com.taobao.arthas.protobuf.annotation.ProtobufEnableZigZap;
import com.taobao.arthas.protobuf.annotation.ProtobufClass;
import com.taobao.arthas.protobuf.utils.FieldUtil;
@@ -112,7 +116,40 @@ private static void processEncodeBlock() {
}
private static void processDecodeBlock() {
+ // 初始化 list、map、enum
+ StringBuilder initListMapFields = new StringBuilder();
+ for (ProtobufField protobufField : protobufFields) {
+ boolean isList = protobufField.isList();
+ boolean isMap = protobufField.isMap();
+ String e = "";
+ if (isList) {
+ if (FieldInfo.isListType(protobufField.getJavaField())) {
+ e = "new ArrayList()";
+ } else if (FieldInfo.isSetType(protobufField.getJavaField())) {
+ e = "new HashSet()";
+ }
+ } else if (isMap) {
+ e = "new HashMap()";
+ }
+ if (isList || isMap) {
+ initListMapFields.append(FieldUtil.getInitListMapFieldDynamicString(protobufField, e));
+ }
+
+ if (protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.ENUM) {
+ String clsName = protobufField.getJavaField().getType().getCanonicalName();
+ if (!isList) {
+ String express =
+ "CodedConstant.getEnumValue(" + clsName + ".class, " + clsName + ".values()[0].name())";
+ // add set get method
+ String setToField = getSetToField("ret", field.getField(), cls, express, isList, field.isMap(),
+ false, field.isWildcardType());
+ miniTemplator.setVariable("enumInitialize", setToField);
+ miniTemplator.addBlock("enumFields");
+ }
+ }
+ }
+ miniTemplator.setVariable("initListMapFields", initListMapFields.toString());
}
@@ -123,11 +160,11 @@ private static void loadProtobufField() {
}
public static void main(String[] args) {
- List protobufFieldList = FieldUtil.getProtobufFieldList(ArthasSampleRequest.class, false);
- for (ProtobufField protobufField : protobufFieldList) {
- String target = FieldUtil.getGetterDynamicString("target", protobufField.getJavaField(), ArthasSampleRequest.class, protobufField.isWildcardType());
- System.out.println(target);
- }
+// List protobufFieldList = FieldUtil.getProtobufFieldList(ArthasSampleRequest.class, false);
+// for (ProtobufField protobufField : protobufFieldList) {
+// String target = FieldUtil.getGetterDynamicString("target", protobufField.getJavaField(), ArthasSampleRequest.class, protobufField.isWildcardType());
+// System.out.println(target);
+// }
}
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
index 00cc942a24..77d4a46123 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
@@ -4,12 +4,6 @@
*/
-import com.baidu.bjf.remoting.protobuf.Codec;
-import com.baidu.bjf.remoting.protobuf.EnumReadable;
-import com.baidu.bjf.remoting.protobuf.FieldType;
-import com.baidu.bjf.remoting.protobuf.code.CodecOutputByteArray;
-import com.baidu.bjf.remoting.protobuf.code.ICodeGenerator;
-import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
import com.google.protobuf.ByteString;
import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.MapEntry;
@@ -42,12 +36,14 @@ public class FieldUtil {
private static final Map PRIMITIVE_TYPE_MAPPING;
- private static final String dynamicTarget = "target";
+ private static final String DYNAMIC_TARGET = "target";
public static final String PACKAGE_SEPARATOR = ".";
private static final String LINE_BREAK = "\n";
+ private static final String JAVA_LINE_BREAK = ";" + LINE_BREAK;
+
private static final String CODE_OUTPUT_STREAM_OBJ_NAME = "output";
static {
@@ -206,6 +202,25 @@ public static List getProtobufFieldList(Class> clazz, boolean e
return res;
}
+ /**
+ * 在 clazz 上寻找字段名为 name 的字段
+ *
+ * @param clazz
+ * @param name
+ * @return
+ */
+ public static Field findField(Class clazz, String name) {
+ return findField(clazz, name, null);
+ }
+
+ /**
+ * 在 clazz 上寻找字段名为 name、字段类型为 type 的字段
+ *
+ * @param clazz
+ * @param name
+ * @param type
+ * @return
+ */
public static Field findField(Class clazz, String name, Class type) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
@@ -229,6 +244,13 @@ public static Field findField(Class clazz, String name, Class type) {
return null;
}
+ /**
+ * 获取对象 t 上的字段名为 name 的字段值
+ *
+ * @param t
+ * @param name
+ * @return
+ */
public static Object getField(Object t, String name) {
Field field = findField(t.getClass(), name, null);
if (field == null) {
@@ -243,13 +265,26 @@ public static Object getField(Object t, String name) {
return null;
}
+ public static void setField(Object t, String name, Object value) {
+ Field field = findField(t.getClass(), name);
+ if (field == null) {
+ return;
+ }
+ field.setAccessible(true);
+ try {
+ field.set(t, value);
+ } catch (Exception e) {
+ //todo log
+ }
+ }
+
public static String getGetterDynamicString(ProtobufField protobufField, Class> dynamicTargetClass) {
Field field = protobufField.getJavaField();
boolean wildcardType = protobufField.isWildcardType();
if (field.getModifiers() == Modifier.PUBLIC && !wildcardType) {
- return dynamicTarget + PACKAGE_SEPARATOR + field.getName();
+ return DYNAMIC_TARGET + PACKAGE_SEPARATOR + field.getName();
}
String getter;
@@ -261,7 +296,7 @@ public static String getGetterDynamicString(ProtobufField protobufField, Class
try {
dynamicTargetClass.getMethod(getter, new Class>[0]);
- return dynamicTarget + PACKAGE_SEPARATOR + getter + "()";
+ return DYNAMIC_TARGET + PACKAGE_SEPARATOR + getter + "()";
} catch (Exception e) {
//todo log
}
@@ -272,7 +307,7 @@ public static String getGetterDynamicString(ProtobufField protobufField, Class
}
String code = "(" + toObjectType(type) + ") ";
- code += "FieldUtil.getField(" + dynamicTarget + ", \"" + field.getName() + "\")";
+ code += "FieldUtil.getField(" + DYNAMIC_TARGET + ", \"" + field.getName() + "\")";
return code;
}
@@ -337,7 +372,7 @@ public static String getWriteByteDynamicString(ProtobufField protobufField) {
sb.append("Field.writeList(").append(CODE_OUTPUT_STREAM_OBJ_NAME).append(",");
sb.append(order).append(",").append(ProtobufFieldTypeEnum.class.getName()).append(".").append(typeString);
sb.append(",").append(dynamicFieldName).append(",").append(Boolean.valueOf(protobufField.isPacked())).append(")")
- .append(";" + LINE_BREAK).append("}").append(LINE_BREAK);
+ .append(JAVA_LINE_BREAK).append("}").append(LINE_BREAK);
return sb.toString();
} else if (protobufField.isMap()) {
sb.append("Field.writeMap(").append(CODE_OUTPUT_STREAM_OBJ_NAME).append(",");
@@ -346,7 +381,7 @@ public static String getWriteByteDynamicString(ProtobufField protobufField) {
String joinedSentence = getMapFieldGenericParameterString(protobufField);
sb.append(",").append(joinedSentence);
- sb.append(")").append(";" + LINE_BREAK).append("}").append(LINE_BREAK);
+ sb.append(")").append(JAVA_LINE_BREAK).append("}").append(LINE_BREAK);
return sb.toString();
} else {
dynamicFieldName = dynamicFieldName + protobufFieldType.getToPrimitiveType();
@@ -356,21 +391,21 @@ public static String getWriteByteDynamicString(ProtobufField protobufField) {
String typeString = protobufFieldType.getType().toUpperCase();
sb.append("Field.writeObject(").append(CODE_OUTPUT_STREAM_OBJ_NAME).append(",");
sb.append(order).append(",").append(ProtobufFieldTypeEnum.class.getName()).append(".").append(typeString);
- sb.append(",").append(dynamicFieldName).append(", false)").append(";" + LINE_BREAK).append("}")
+ sb.append(",").append(dynamicFieldName).append(", false)").append(JAVA_LINE_BREAK).append("}")
.append(LINE_BREAK);
return sb.toString();
}
if (protobufFieldType == ProtobufFieldTypeEnum.STRING) {
sb.append(CODE_OUTPUT_STREAM_OBJ_NAME).append(".writeString(").append(order);
- sb.append(", ").append(dynamicFieldName).append(")").append(";" + LINE_BREAK).append("}")
+ sb.append(", ").append(dynamicFieldName).append(")").append(JAVA_LINE_BREAK).append("}")
.append(LINE_BREAK);
return sb.toString();
}
if (protobufFieldType == ProtobufFieldTypeEnum.BYTES) {
sb.append(CODE_OUTPUT_STREAM_OBJ_NAME).append(".writeByteArray(").append(order);
- sb.append(", ").append(dynamicFieldName).append(")").append(";" + LINE_BREAK).append("}")
+ sb.append(", ").append(dynamicFieldName).append(")").append(JAVA_LINE_BREAK).append("}")
.append(LINE_BREAK);
return sb.toString();
}
@@ -379,7 +414,7 @@ public static String getWriteByteDynamicString(ProtobufField protobufField) {
t = capitalize(t);
sb.append(CODE_OUTPUT_STREAM_OBJ_NAME).append(".write").append(t).append("(").append(order);
- sb.append(", ").append(dynamicFieldName).append(")").append(";" + LINE_BREAK).append("}")
+ sb.append(", ").append(dynamicFieldName).append(")").append(JAVA_LINE_BREAK).append("}")
.append(LINE_BREAK);
return sb.toString();
}
@@ -649,6 +684,155 @@ public static String getDynamicFieldName(int order) {
return "f_" + order;
}
+ /**
+ * 获取 set 指定对象指定字段的方法
+ *
+ * @param protobufField
+ * @param dynamicTargetClass
+ * @param express
+ * @return
+ */
+ public static String getSetFieldDynamicString(ProtobufField protobufField, Class> dynamicTargetClass, String express) {
+ StringBuilder sb = new StringBuilder();
+ boolean isMap = protobufField.isMap();
+ boolean isList = protobufField.isList();
+ boolean isWildcardType = protobufField.isWildcardType();
+ boolean isPacked = protobufField.isPacked();
+ Field javaField = protobufField.getJavaField();
+
+
+ if (isList || isMap) {
+ sb.append("if ((").append(getGetterDynamicString(protobufField, dynamicTargetClass)).append(") == null) {")
+ .append(LINE_BREAK);
+ }
+
+ String collectionTypetoCreate = "";
+ String collectionType = "";
+ if (List.class.isAssignableFrom(javaField.getType())) {
+ collectionTypetoCreate = "new ArrayList()";
+ collectionType = "List";
+ } else if (Set.class.isAssignableFrom(javaField.getType())) {
+ collectionTypetoCreate = "new HashSet()";
+ collectionType = "Set";
+ }
+
+ // if field of public modifier we can access directly
+ if (Modifier.isPublic(javaField.getModifiers()) && !isWildcardType) {
+ if (isList) {
+ // should initialize list
+ sb.append(DYNAMIC_TARGET).append(PACKAGE_SEPARATOR).append(javaField.getName()).append("= ")
+ .append(collectionTypetoCreate).append(JAVA_LINE_BREAK).append("}")
+ .append(LINE_BREAK);
+ if (express != null) {
+ if (isPacked) {
+ sb.append("while (input.getBytesUntilLimit() > 0) {").append(LINE_BREAK);
+ }
+ sb.append(DYNAMIC_TARGET).append(PACKAGE_SEPARATOR).append(javaField.getName()).append(".add(")
+ .append(express).append(")");
+ if (isPacked) {
+ sb.append(";}").append(LINE_BREAK);
+ }
+ }
+ return sb.toString();
+ } else if (isMap) {
+ sb.append(DYNAMIC_TARGET).append(PACKAGE_SEPARATOR).append(javaField.getName())
+ .append("= new HashMap()").append(JAVA_LINE_BREAK).append("}")
+ .append(LINE_BREAK);
+ return sb.append(express).toString();
+ }
+ // if date type
+ if (javaField.getType().equals(Date.class)) {
+ express = "new Date(" + express + ")";
+ }
+ return DYNAMIC_TARGET + PACKAGE_SEPARATOR + javaField.getName() + "=" + express + LINE_BREAK;
+ }
+ String setter = "set" + capitalize(javaField.getName());
+ // check method exist
+ try {
+ dynamicTargetClass.getMethod(setter, new Class>[]{javaField.getType()});
+ if (isList) {
+ sb.append(collectionType).append(" __list = ").append(collectionTypetoCreate)
+ .append(JAVA_LINE_BREAK);
+ sb.append(DYNAMIC_TARGET).append(PACKAGE_SEPARATOR).append(setter).append("(__list)")
+ .append(JAVA_LINE_BREAK).append("}").append(LINE_BREAK);
+
+ if (express != null) {
+ if (isPacked) {
+ sb.append("while (input.getBytesUntilLimit() > 0) {").append(LINE_BREAK);
+ }
+ sb.append("(").append(getGetterDynamicString(protobufField, dynamicTargetClass)).append(").add(")
+ .append(express).append(")");
+ if (isPacked) {
+ sb.append(";}").append(LINE_BREAK);
+ }
+ }
+ return sb.toString();
+ } else if (isMap) {
+ sb.append("Map __map = new HashMap()").append(JAVA_LINE_BREAK);
+ sb.append(DYNAMIC_TARGET).append(PACKAGE_SEPARATOR).append(setter).append("(__map)")
+ .append(JAVA_LINE_BREAK).append("}").append(LINE_BREAK);
+ return sb + express;
+ }
+
+ // fix date type
+ if (javaField.getType().equals(Date.class)) {
+ express = "new Date(" + express + ")";
+ }
+
+ return DYNAMIC_TARGET + PACKAGE_SEPARATOR + setter + "(" + express + ")\n";
+ } catch (Exception e) {
+ //todo log
+ }
+
+ if (isList) {
+ sb.append(collectionType).append(" __list = ").append(collectionTypetoCreate)
+ .append(JAVA_LINE_BREAK);
+ sb.append("FieldUtil.setField(").append(DYNAMIC_TARGET).append(", \"").append(javaField.getName())
+ .append("\", __list)").append(JAVA_LINE_BREAK).append("}").append(LINE_BREAK);
+ if (express != null) {
+ if (isPacked) {
+ sb.append("while (input.getBytesUntilLimit() > 0) {").append(LINE_BREAK);
+ }
+ sb.append("(").append(getGetterDynamicString(protobufField, dynamicTargetClass)).append(").add(")
+ .append(express).append(")");
+ if (isPacked) {
+ sb.append(";}").append(LINE_BREAK);
+ }
+ }
+ return sb.toString();
+ } else if (isMap) {
+ sb.append("Map __map = new HashMap()").append(JAVA_LINE_BREAK);
+ sb.append("FieldUtil.setField(").append(DYNAMIC_TARGET).append(", \"").append(javaField.getName())
+ .append("\", __map)").append(JAVA_LINE_BREAK).append("}").append(LINE_BREAK);
+ return sb + express;
+ }
+
+ // use reflection to get value
+ String code = "";
+ if (express != null) {
+ // if date type
+ if (javaField.getType().equals(Date.class)) {
+ express = "new Date(" + express + ")";
+ }
+
+ code = "FieldUtil.setField(" + DYNAMIC_TARGET + ", \"" + javaField.getName() + "\", " + express + ")"
+ + LINE_BREAK;
+ }
+ return code;
+ }
+
+ /**
+ * 获取初始化 list、map 字段的动态字符串
+ *
+ * @param protobufField
+ * @return
+ */
+ public static String getInitListMapFieldDynamicString(ProtobufField protobufField, String express) {
+ return "FieldUtil.setField(" + DYNAMIC_TARGET + ", \"" + protobufField.getJavaField().getName() + "\", " + express + ");"
+ + LINE_BREAK;
+ }
+
+
public static int getListSize(int order, Collection> list, ProtobufFieldTypeEnum type, boolean packed) {
int size = 0;
if (list == null || list.isEmpty()) {
@@ -687,6 +871,14 @@ public static int getMapSize(int order, Map map, com.google.protobu
return size;
}
+ /**
+ * 获取 object protobuf size
+ *
+ * @param order
+ * @param object
+ * @param type
+ * @return
+ */
public static int getObjectSize(int order, Object object, ProtobufFieldTypeEnum type) {
int size = 0;
if (object == null) {
@@ -767,7 +959,6 @@ public static String toObjectType(String primitiveType) {
return primitiveType;
}
-
public static boolean isNull(Object o) {
return o == null;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
index d818e7ac10..9b23f66b59 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
@@ -25,4 +25,20 @@ public class ArthasSampleRequest{
private String name;
private double age;
private long price;
+ private StatusEnum status;
+ private List testList;
+
+
+ enum StatusEnum{
+ START(1,"开始"),
+ STOP(2,"结束");
+
+ StatusEnum(int code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ private int code;
+ private String desc;
+ }
}
diff --git a/arthas-grpc-server/src/main/proto/Test.proto b/arthas-grpc-server/src/main/proto/Test.proto
index ec613de843..f9ffe3d740 100644
--- a/arthas-grpc-server/src/main/proto/Test.proto
+++ b/arthas-grpc-server/src/main/proto/Test.proto
@@ -2,6 +2,12 @@ syntax = "proto3";
package helloworld;
+
+enum StatusEnum {
+ START = 0;
+ STOP = 1;
+}
+
service HelloService {
rpc SayHello(HelloRequest) returns (HelloReply);
}
@@ -10,9 +16,11 @@ message HelloRequest {
string name = 1;
double age = 2;
int64 price = 3;
- float man = 4;
+ StatusEnum status = 4;
+ repeated string testList = 5;
}
+
message HelloReply {
string message = 1;
}
diff --git a/arthas-grpc-server/src/main/resources/class_template.tpl b/arthas-grpc-server/src/main/resources/class_template.tpl
index c04e8ba504..dbe84651cb 100644
--- a/arthas-grpc-server/src/main/resources/class_template.tpl
+++ b/arthas-grpc-server/src/main/resources/class_template.tpl
@@ -44,7 +44,7 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
}
public ${targetProxyClassName} readFrom(CodedInputStream input) throws IOException {
- ${targetProxyClassName} ret = new ${targetProxyClassName}();
+ ${targetProxyClassName} target = new ${targetProxyClassName}();
${initListMapFields}
@@ -78,7 +78,7 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
throw e;
}
- return ret;
+ return target;
}
From 4d960aeb196667606e991802dcd4a43c7d968c18 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Mon, 5 Aug 2024 02:37:50 +0800
Subject: [PATCH 16/48] update: add protobuf codec
---
.../taobao/arthas/protobuf/ProtobufField.java | 14 ++
.../taobao/arthas/protobuf/ProtobufProxy.java | 229 +++++++++++++++++-
.../arthas/protobuf/utils/FieldUtil.java | 53 +++-
.../src/main/resources/class_template.tpl | 1 -
4 files changed, 278 insertions(+), 19 deletions(-)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
index 34dcedf536..e2b3b9a353 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
@@ -169,6 +169,20 @@ private String noSubParameterizedType(Field field, boolean listOrMap) {
}
+ public boolean isEnumValueType() {
+ if (genericValueType != null) {
+ return Enum.class.isAssignableFrom(genericValueType);
+ }
+ return false;
+ }
+
+ public boolean isEnumKeyType() {
+ if (genericKeyType != null) {
+ return Enum.class.isAssignableFrom(genericKeyType);
+ }
+ return false;
+ }
+
public int getOrder() {
return order;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index dcd6c49b6d..ff866bf1a5 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -9,6 +9,7 @@
import com.baidu.bjf.remoting.protobuf.code.CodedConstant;
import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
import com.baidu.bjf.remoting.protobuf.utils.FieldInfo;
+import com.google.protobuf.WireFormat;
import com.taobao.arthas.protobuf.annotation.ProtobufEnableZigZap;
import com.taobao.arthas.protobuf.annotation.ProtobufClass;
import com.taobao.arthas.protobuf.utils.FieldUtil;
@@ -121,35 +122,239 @@ private static void processDecodeBlock() {
for (ProtobufField protobufField : protobufFields) {
boolean isList = protobufField.isList();
boolean isMap = protobufField.isMap();
- String e = "";
+ String express = "";
if (isList) {
if (FieldInfo.isListType(protobufField.getJavaField())) {
- e = "new ArrayList()";
+ express = "new ArrayList()";
} else if (FieldInfo.isSetType(protobufField.getJavaField())) {
- e = "new HashSet()";
+ express = "new HashSet()";
}
} else if (isMap) {
- e = "new HashMap()";
+ express = "new HashMap()";
}
if (isList || isMap) {
- initListMapFields.append(FieldUtil.getInitListMapFieldDynamicString(protobufField, e));
+ initListMapFields.append(FieldUtil.getInitListMapFieldDynamicString(protobufField, express));
}
if (protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.ENUM) {
String clsName = protobufField.getJavaField().getType().getCanonicalName();
if (!isList) {
- String express =
- "CodedConstant.getEnumValue(" + clsName + ".class, " + clsName + ".values()[0].name())";
+ express = "FieldUtil.getEnumValue(" + clsName + ".class, " + clsName + ".values()[0].name())";
// add set get method
- String setToField = getSetToField("ret", field.getField(), cls, express, isList, field.isMap(),
- false, field.isWildcardType());
+ String setToField = FieldUtil.getSetFieldDynamicString(protobufField,clazz,express);
miniTemplator.setVariable("enumInitialize", setToField);
miniTemplator.addBlock("enumFields");
}
}
}
-
miniTemplator.setVariable("initListMapFields", initListMapFields.toString());
+
+ //todo 继续看下
+
+ //处理字段赋值
+ StringBuilder code = new StringBuilder();
+ // 处理field解析
+ for (ProtobufField protobufField : protobufFields) {
+ boolean isList = protobufField.isList();
+ String t = protobufField.getProtobufFieldType().getType();
+ t = FieldUtil.capitalize(t);
+
+ boolean listTypeCheck = false;
+ String express;
+ String objectDecodeExpress = "";
+ String objectDecodeExpressSuffix = "";
+
+ String decodeOrder = "-1";
+ if (protobufField.getProtobufFieldType() != ProtobufFieldTypeEnum.DEFAULT) {
+ decodeOrder = FieldUtil.makeTag(protobufField.getOrder(),
+ protobufField.getProtobufFieldType().getInternalFieldType().getWireType()) + "";
+ } else {
+ decodeOrder = "FieldUtil.makeTag(" + protobufField.getOrder() + ",WireFormat."
+ + protobufField.getProtobufFieldType().getWireFormat() + ")";
+ }
+ miniTemplator.setVariable("decodeOrder", decodeOrder);
+
+ // enumeration type
+ if (protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.ENUM) {
+ String clsName = ClassHelper.getInternalName(protobufField.getJavaField().getType().getCanonicalName());
+ if (isList) {
+ if (protobufField.getGenericKeyType() != null) {
+ Class cls = protobufField.getGenericKeyType();
+ clsName = ClassHelper.getInternalName(cls.getCanonicalName());
+ }
+ }
+ express = "FieldUtil.getEnumValue(" + clsName + ".class, FieldUtil.getEnumName(" + clsName
+ + ".values()," + "input.read" + t + "()))";
+ } else {
+ // here is the trick way to process BigDecimal and BigInteger
+ if (protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.BIGDECIMAL || protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.BIGINTEGER) {
+ express = "new " + protobufField.getProtobufFieldType().getJavaType() + "(input.read" + t + "())";
+ } else {
+ express = "input.read" + t + "()";
+ }
+
+ }
+
+ // if List type and element is object message type
+ if (isList && protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.OBJECT) {
+ if (protobufField.getGenericKeyType() != null) {
+ Class cls = protobufField.getGenericKeyType();
+
+ checkObjectType(protobufField, cls);
+
+ code.append("codec = ProtobufProxy.create(").append(cls.getCanonicalName()).append(".class");
+ String spath = "ProtobufProxy.OUTPUT_PATH.get()";
+ code.append(",").append(spath);
+ code.append(")").append(ClassCode.JAVA_LINE_BREAK);
+ objectDecodeExpress = code.toString();
+ code.setLength(0);
+
+ objectDecodeExpress += "int length = input.readRawVarint32()" + ClassCode.JAVA_LINE_BREAK;
+ objectDecodeExpress += "final int oldLimit = input.pushLimit(length)" + ClassCode.JAVA_LINE_BREAK;
+ listTypeCheck = true;
+ express = "(" + cls.getCanonicalName() + ") codec.readFrom(input)";
+
+ }
+ } else if (protobufField.isMap()) {
+
+ String getMapCommand = getMapCommand(protobufField);
+
+ if (protobufField.isEnumKeyType()) {
+ String enumClassName = protobufField.getGenericKeyType().getCanonicalName();
+ code.append("EnumHandler<").append(enumClassName).append("> keyhandler");
+ code.append("= new EnumHandler");
+ code.append("<").append(enumClassName).append(">() {");
+ code.append(ClassCode.LINE_BREAK);
+ code.append("public ").append(enumClassName).append(" handle(int value) {");
+ code.append(ClassCode.LINE_BREAK);
+ code.append("String enumName = FieldUtil.getEnumName(").append(enumClassName)
+ .append(".values(), value)");
+ code.append(ClassCode.JAVA_LINE_BREAK);
+ code.append("return ").append(enumClassName).append(".valueOf(enumName)");
+ code.append(ClassCode.JAVA_LINE_BREAK);
+ code.append("}}");
+ code.append(ClassCode.JAVA_LINE_BREAK);
+ }
+
+ if (protobufField.isEnumValueType()) {
+ String enumClassName = protobufField.getGenericValueType().getCanonicalName();
+ code.append("EnumHandler<").append(enumClassName).append("> handler");
+ code.append("= new EnumHandler");
+ code.append("<").append(enumClassName).append(">() {");
+ code.append(ClassCode.LINE_BREAK);
+ code.append("public ").append(enumClassName).append(" handle(int value) {");
+ code.append(ClassCode.LINE_BREAK);
+ code.append("String enumName = FieldUtil.getEnumName(").append(enumClassName)
+ .append(".values(), value)");
+ code.append(ClassCode.JAVA_LINE_BREAK);
+ code.append("return ").append(enumClassName).append(".valueOf(enumName)");
+ code.append(ClassCode.JAVA_LINE_BREAK);
+ code.append("}}");
+ code.append(ClassCode.JAVA_LINE_BREAK);
+ }
+
+ objectDecodeExpress = code.toString();
+ code.setLength(0);
+
+ express = "CodedConstant.putMapValue(input, " + getMapCommand + ",";
+ express += FieldUtil.getMapFieldGenericParameterString(protobufField);
+ if (protobufField.isEnumKeyType()) {
+ express += ", keyhandler";
+ } else {
+ express += ", null";
+ }
+ if (protobufField.isEnumValueType()) {
+ express += ", handler";
+ } else {
+ express += ", null";
+ }
+ express += ")";
+
+ } else if (protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.OBJECT) { // if object
+ // message
+ // type
+ Class cls = protobufField.getJavaField().getType();
+ checkObjectType(protobufField, cls);
+ String name = ClassHelper.getInternalName(cls.getCanonicalName()); // need
+ // to
+ // parse
+ // nested
+ // class
+ code.append("codec = ProtobufProxy.create(").append(name).append(".class");
+
+ String spath = "ProtobufProxy.OUTPUT_PATH.get()";
+ code.append(",").append(spath);
+ code.append(")").append(ClassCode.JAVA_LINE_BREAK);
+ objectDecodeExpress = code.toString();
+ code.setLength(0);
+
+ objectDecodeExpress += "int length = input.readRawVarint32()" + ClassCode.JAVA_LINE_BREAK;
+ objectDecodeExpress += "final int oldLimit = input.pushLimit(length)" + ClassCode.JAVA_LINE_BREAK;
+
+ listTypeCheck = true;
+ express = "(" + name + ") codec.readFrom(input)";
+ }
+
+ if (protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.BYTES) {
+ express += ".toByteArray()";
+ }
+
+ String decodeFieldSetValue = FieldUtil.getSetFieldDynamicString(protobufField,clazz,express) + FieldUtil.JAVA_LINE_BREAK;
+
+ if (listTypeCheck) {
+ objectDecodeExpressSuffix += "input.checkLastTagWas(0)" + ClassCode.JAVA_LINE_BREAK;
+ objectDecodeExpressSuffix += "input.popLimit(oldLimit)" + ClassCode.JAVA_LINE_BREAK;
+ }
+
+ String objectPackedDecodeExpress = "";
+ // read packed type
+ if (isList) {
+ ProtobufFieldTypeEnum protobufFieldType = protobufField.getProtobufFieldType();
+ if (protobufFieldType.isPrimitive() || protobufFieldType.isEnum()) {
+ code.append("if (tag == ")
+ .append(FieldUtil.makeTag(protobufField.getOrder(), WireFormat.WIRETYPE_LENGTH_DELIMITED));
+ code.append(") {").append(ClassCode.LINE_BREAK);
+
+ code.append("int length = input.readRawVarint32()").append(ClassCode.JAVA_LINE_BREAK);
+ code.append("int limit = input.pushLimit(length)").append(ClassCode.JAVA_LINE_BREAK);
+
+ code.append(FieldUtil.getSetFieldDynamicString(protobufField,clazz,express));
+
+ code.append("input.popLimit(limit)").append(ClassCode.JAVA_LINE_BREAK);
+
+ code.append("continue").append(ClassCode.JAVA_LINE_BREAK);
+ code.append("}").append(ClassCode.LINE_BREAK);
+
+ objectPackedDecodeExpress = code.toString();
+ }
+ }
+ miniTemplator.setVariable("objectPackedDecodeExpress", objectPackedDecodeExpress);
+ miniTemplator.setVariable("objectDecodeExpress", objectDecodeExpress);
+ miniTemplator.setVariable("objectDecodeExpressSuffix", objectDecodeExpressSuffix);
+ miniTemplator.setVariable("decodeFieldSetValue", decodeFieldSetValue);
+ miniTemplator.addBlock("decodeFields");
+ }
+
+ }
+
+ private static void checkObjectType(ProtobufField protobufField, Class cls) {
+ if (FieldInfo.isPrimitiveType(cls)) {
+ throw new RuntimeException("invalid generic type for List as Object type, current type is '" + cls.getName()
+ + "' on field name '" + protobufField.getJavaField().getDeclaringClass().getName() + "#"
+ + protobufField.getJavaField().getName());
+ }
+ }
+
+ private static String getMapCommand(ProtobufField protobufField) {
+ String keyGeneric;
+ keyGeneric = protobufField.getGenericKeyType().getCanonicalName();
+
+ String valueGeneric;
+ valueGeneric = protobufField.getGenericValueType().getCanonicalName();
+ String getMapCommand = "(Map<" + keyGeneric;
+ getMapCommand = getMapCommand + ", " + valueGeneric + ">)";
+ getMapCommand = getMapCommand + FieldUtil.getGetterDynamicString(protobufField, clazz);
+ return getMapCommand;
}
@@ -159,12 +364,12 @@ private static void loadProtobufField() {
);
}
- public static void main(String[] args) {
+// public static void main(String[] args) {
// List protobufFieldList = FieldUtil.getProtobufFieldList(ArthasSampleRequest.class, false);
// for (ProtobufField protobufField : protobufFieldList) {
// String target = FieldUtil.getGetterDynamicString("target", protobufField.getJavaField(), ArthasSampleRequest.class, protobufField.isWildcardType());
// System.out.println(target);
// }
- }
+// }
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
index 77d4a46123..f241c32a5a 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
@@ -4,6 +4,12 @@
*/
+import com.baidu.bjf.remoting.protobuf.EnumReadable;
+import com.baidu.bjf.remoting.protobuf.FieldType;
+import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
+import com.baidu.bjf.remoting.protobuf.utils.FieldInfo;
+import com.baidu.bjf.remoting.protobuf.utils.ProtobufProxyUtils;
+import com.baidu.bjf.remoting.protobuf.utils.StringUtils;
import com.google.protobuf.ByteString;
import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.MapEntry;
@@ -34,17 +40,19 @@ public class FieldUtil {
public static final Map, ProtobufFieldTypeEnum> TYPE_MAPPER;
- private static final Map PRIMITIVE_TYPE_MAPPING;
+ public static final Map PRIMITIVE_TYPE_MAPPING;
- private static final String DYNAMIC_TARGET = "target";
+ public static final String DYNAMIC_TARGET = "target";
public static final String PACKAGE_SEPARATOR = ".";
- private static final String LINE_BREAK = "\n";
+ public static final String LINE_BREAK = "\n";
- private static final String JAVA_LINE_BREAK = ";" + LINE_BREAK;
+ public static final String JAVA_LINE_BREAK = ";" + LINE_BREAK;
- private static final String CODE_OUTPUT_STREAM_OBJ_NAME = "output";
+ public static final String CODE_OUTPUT_STREAM_OBJ_NAME = "output";
+
+ public static final String WIREFORMAT_CLSNAME = com.google.protobuf.WireFormat.FieldType.class.getCanonicalName();
static {
@@ -593,7 +601,7 @@ public static void writeObject(CodedOutputStream out, int order, ProtobufFieldTy
}
}
- private static String getMapFieldGenericParameterString(ProtobufField field) {
+ public static String getMapFieldGenericParameterString(ProtobufField field) {
String wireFormatClassName = WireFormat.FieldType.class.getCanonicalName();
ProtobufFieldTypeEnum fieldType = TYPE_MAPPER.get(field.getGenericKeyType());
String keyClass;
@@ -821,6 +829,39 @@ public static String getSetFieldDynamicString(ProtobufField protobufField, Class
return code;
}
+ public static int getEnumOrdinal(Enum en) {
+ if (en != null) {
+ return en.ordinal();
+ }
+ return -1;
+ }
+
+ public static > T getEnumValue(Class enumType, String name) {
+ if (StringUtils.isEmpty(name)) {
+ return null;
+ }
+
+ try {
+ T v = Enum.valueOf(enumType, name);
+ return v;
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
+ public static String getEnumName(Enum[] e, int value) {
+ if (e != null) {
+ int toCompareValue;
+ for (Enum en : e) {
+ toCompareValue = en.ordinal();
+ if (value == toCompareValue) {
+ return en.name();
+ }
+ }
+ }
+ return "";
+ }
+
/**
* 获取初始化 list、map 字段的动态字符串
*
diff --git a/arthas-grpc-server/src/main/resources/class_template.tpl b/arthas-grpc-server/src/main/resources/class_template.tpl
index dbe84651cb..dc12228468 100644
--- a/arthas-grpc-server/src/main/resources/class_template.tpl
+++ b/arthas-grpc-server/src/main/resources/class_template.tpl
@@ -64,7 +64,6 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
${objectDecodeExpress}
${decodeFieldSetValue}
${objectDecodeExpressSuffix}
- ${deocdeCheckNull}
continue;
}
${objectPackedDecodeExpress}
From f72022201bda44802dfc7e1003a15dd9a0a91e29 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Tue, 6 Aug 2024 01:30:15 +0800
Subject: [PATCH 17/48] update: add protobuf codec
---
.../taobao/arthas/protobuf/ProtobufField.java | 18 +++++
.../taobao/arthas/protobuf/ProtobufProxy.java | 71 ++++++++-----------
.../arthas/protobuf/utils/EnumHandler.java | 13 ++++
.../arthas/protobuf/utils/FieldUtil.java | 54 ++++++++++++--
.../service/req/ArthasSampleRequest.java | 6 +-
arthas-grpc-server/src/main/proto/Test.proto | 5 +-
6 files changed, 121 insertions(+), 46 deletions(-)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/EnumHandler.java
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
index e2b3b9a353..6203b88d5e 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
@@ -183,6 +183,24 @@ public boolean isEnumKeyType() {
return false;
}
+ public static boolean isListType(Field field) {
+ return List.class.isAssignableFrom(field.getType());
+ }
+
+ public static boolean isSetType(Field field) {
+ return Set.class.isAssignableFrom(field.getType());
+ }
+
+ public static boolean isPrimitiveType(Class c) {
+ if (c.isPrimitive()) {
+ return true;
+ }
+ if (c.getName().equals(String.class.getName())) {
+ return true;
+ }
+ return false;
+ }
+
public int getOrder() {
return order;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index ff866bf1a5..e90dcec6b4 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -4,11 +4,6 @@
*/
-import com.baidu.bjf.remoting.protobuf.FieldType;
-import com.baidu.bjf.remoting.protobuf.code.ClassCode;
-import com.baidu.bjf.remoting.protobuf.code.CodedConstant;
-import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
-import com.baidu.bjf.remoting.protobuf.utils.FieldInfo;
import com.google.protobuf.WireFormat;
import com.taobao.arthas.protobuf.annotation.ProtobufEnableZigZap;
import com.taobao.arthas.protobuf.annotation.ProtobufClass;
@@ -124,9 +119,9 @@ private static void processDecodeBlock() {
boolean isMap = protobufField.isMap();
String express = "";
if (isList) {
- if (FieldInfo.isListType(protobufField.getJavaField())) {
+ if (ProtobufField.isListType(protobufField.getJavaField())) {
express = "new ArrayList()";
- } else if (FieldInfo.isSetType(protobufField.getJavaField())) {
+ } else if (ProtobufField.isSetType(protobufField.getJavaField())) {
express = "new HashSet()";
}
} else if (isMap) {
@@ -176,11 +171,11 @@ private static void processDecodeBlock() {
// enumeration type
if (protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.ENUM) {
- String clsName = ClassHelper.getInternalName(protobufField.getJavaField().getType().getCanonicalName());
+ String clsName = protobufField.getJavaField().getType().getCanonicalName();
if (isList) {
if (protobufField.getGenericKeyType() != null) {
Class cls = protobufField.getGenericKeyType();
- clsName = ClassHelper.getInternalName(cls.getCanonicalName());
+ clsName = cls.getCanonicalName();
}
}
express = "FieldUtil.getEnumValue(" + clsName + ".class, FieldUtil.getEnumName(" + clsName
@@ -203,14 +198,12 @@ private static void processDecodeBlock() {
checkObjectType(protobufField, cls);
code.append("codec = ProtobufProxy.create(").append(cls.getCanonicalName()).append(".class");
- String spath = "ProtobufProxy.OUTPUT_PATH.get()";
- code.append(",").append(spath);
- code.append(")").append(ClassCode.JAVA_LINE_BREAK);
+ code.append(")").append(FieldUtil.JAVA_LINE_BREAK);
objectDecodeExpress = code.toString();
code.setLength(0);
- objectDecodeExpress += "int length = input.readRawVarint32()" + ClassCode.JAVA_LINE_BREAK;
- objectDecodeExpress += "final int oldLimit = input.pushLimit(length)" + ClassCode.JAVA_LINE_BREAK;
+ objectDecodeExpress += "int length = input.readRawVarint32()" + FieldUtil.JAVA_LINE_BREAK;
+ objectDecodeExpress += "final int oldLimit = input.pushLimit(length)" + FieldUtil.JAVA_LINE_BREAK;
listTypeCheck = true;
express = "(" + cls.getCanonicalName() + ") codec.readFrom(input)";
@@ -224,16 +217,16 @@ private static void processDecodeBlock() {
code.append("EnumHandler<").append(enumClassName).append("> keyhandler");
code.append("= new EnumHandler");
code.append("<").append(enumClassName).append(">() {");
- code.append(ClassCode.LINE_BREAK);
+ code.append(FieldUtil.LINE_BREAK);
code.append("public ").append(enumClassName).append(" handle(int value) {");
- code.append(ClassCode.LINE_BREAK);
+ code.append(FieldUtil.LINE_BREAK);
code.append("String enumName = FieldUtil.getEnumName(").append(enumClassName)
.append(".values(), value)");
- code.append(ClassCode.JAVA_LINE_BREAK);
+ code.append(FieldUtil.JAVA_LINE_BREAK);
code.append("return ").append(enumClassName).append(".valueOf(enumName)");
- code.append(ClassCode.JAVA_LINE_BREAK);
+ code.append(FieldUtil.JAVA_LINE_BREAK);
code.append("}}");
- code.append(ClassCode.JAVA_LINE_BREAK);
+ code.append(FieldUtil.JAVA_LINE_BREAK);
}
if (protobufField.isEnumValueType()) {
@@ -241,22 +234,22 @@ private static void processDecodeBlock() {
code.append("EnumHandler<").append(enumClassName).append("> handler");
code.append("= new EnumHandler");
code.append("<").append(enumClassName).append(">() {");
- code.append(ClassCode.LINE_BREAK);
+ code.append(FieldUtil.LINE_BREAK);
code.append("public ").append(enumClassName).append(" handle(int value) {");
- code.append(ClassCode.LINE_BREAK);
+ code.append(FieldUtil.LINE_BREAK);
code.append("String enumName = FieldUtil.getEnumName(").append(enumClassName)
.append(".values(), value)");
- code.append(ClassCode.JAVA_LINE_BREAK);
+ code.append(FieldUtil.JAVA_LINE_BREAK);
code.append("return ").append(enumClassName).append(".valueOf(enumName)");
- code.append(ClassCode.JAVA_LINE_BREAK);
+ code.append(FieldUtil.JAVA_LINE_BREAK);
code.append("}}");
- code.append(ClassCode.JAVA_LINE_BREAK);
+ code.append(FieldUtil.JAVA_LINE_BREAK);
}
objectDecodeExpress = code.toString();
code.setLength(0);
- express = "CodedConstant.putMapValue(input, " + getMapCommand + ",";
+ express = "Field.putMapValue(input, " + getMapCommand + ",";
express += FieldUtil.getMapFieldGenericParameterString(protobufField);
if (protobufField.isEnumKeyType()) {
express += ", keyhandler";
@@ -275,21 +268,19 @@ private static void processDecodeBlock() {
// type
Class cls = protobufField.getJavaField().getType();
checkObjectType(protobufField, cls);
- String name = ClassHelper.getInternalName(cls.getCanonicalName()); // need
+ String name = cls.getCanonicalName(); // need
// to
// parse
// nested
// class
code.append("codec = ProtobufProxy.create(").append(name).append(".class");
- String spath = "ProtobufProxy.OUTPUT_PATH.get()";
- code.append(",").append(spath);
- code.append(")").append(ClassCode.JAVA_LINE_BREAK);
+ code.append(")").append(FieldUtil.JAVA_LINE_BREAK);
objectDecodeExpress = code.toString();
code.setLength(0);
- objectDecodeExpress += "int length = input.readRawVarint32()" + ClassCode.JAVA_LINE_BREAK;
- objectDecodeExpress += "final int oldLimit = input.pushLimit(length)" + ClassCode.JAVA_LINE_BREAK;
+ objectDecodeExpress += "int length = input.readRawVarint32()" + FieldUtil.JAVA_LINE_BREAK;
+ objectDecodeExpress += "final int oldLimit = input.pushLimit(length)" + FieldUtil.JAVA_LINE_BREAK;
listTypeCheck = true;
express = "(" + name + ") codec.readFrom(input)";
@@ -302,8 +293,8 @@ private static void processDecodeBlock() {
String decodeFieldSetValue = FieldUtil.getSetFieldDynamicString(protobufField,clazz,express) + FieldUtil.JAVA_LINE_BREAK;
if (listTypeCheck) {
- objectDecodeExpressSuffix += "input.checkLastTagWas(0)" + ClassCode.JAVA_LINE_BREAK;
- objectDecodeExpressSuffix += "input.popLimit(oldLimit)" + ClassCode.JAVA_LINE_BREAK;
+ objectDecodeExpressSuffix += "input.checkLastTagWas(0)" + FieldUtil.JAVA_LINE_BREAK;
+ objectDecodeExpressSuffix += "input.popLimit(oldLimit)" + FieldUtil.JAVA_LINE_BREAK;
}
String objectPackedDecodeExpress = "";
@@ -313,17 +304,17 @@ private static void processDecodeBlock() {
if (protobufFieldType.isPrimitive() || protobufFieldType.isEnum()) {
code.append("if (tag == ")
.append(FieldUtil.makeTag(protobufField.getOrder(), WireFormat.WIRETYPE_LENGTH_DELIMITED));
- code.append(") {").append(ClassCode.LINE_BREAK);
+ code.append(") {").append(FieldUtil.LINE_BREAK);
- code.append("int length = input.readRawVarint32()").append(ClassCode.JAVA_LINE_BREAK);
- code.append("int limit = input.pushLimit(length)").append(ClassCode.JAVA_LINE_BREAK);
+ code.append("int length = input.readRawVarint32()").append(FieldUtil.JAVA_LINE_BREAK);
+ code.append("int limit = input.pushLimit(length)").append(FieldUtil.JAVA_LINE_BREAK);
code.append(FieldUtil.getSetFieldDynamicString(protobufField,clazz,express));
- code.append("input.popLimit(limit)").append(ClassCode.JAVA_LINE_BREAK);
+ code.append("input.popLimit(limit)").append(FieldUtil.JAVA_LINE_BREAK);
- code.append("continue").append(ClassCode.JAVA_LINE_BREAK);
- code.append("}").append(ClassCode.LINE_BREAK);
+ code.append("continue").append(FieldUtil.JAVA_LINE_BREAK);
+ code.append("}").append(FieldUtil.LINE_BREAK);
objectPackedDecodeExpress = code.toString();
}
@@ -338,7 +329,7 @@ private static void processDecodeBlock() {
}
private static void checkObjectType(ProtobufField protobufField, Class cls) {
- if (FieldInfo.isPrimitiveType(cls)) {
+ if (ProtobufField.isPrimitiveType(cls)) {
throw new RuntimeException("invalid generic type for List as Object type, current type is '" + cls.getName()
+ "' on field name '" + protobufField.getJavaField().getDeclaringClass().getName() + "#"
+ protobufField.getJavaField().getName());
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/EnumHandler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/EnumHandler.java
new file mode 100644
index 0000000000..90064ad05c
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/EnumHandler.java
@@ -0,0 +1,13 @@
+package com.taobao.arthas.protobuf.utils;/**
+ * @author: 風楪
+ * @date: 2024/8/6 上午1:19
+ */
+
+/**
+ * @author: FengYe
+ * @date: 2024/8/6 上午1:19
+ * @description: EnumHandler 处理 enum 泛型类型
+ */
+public interface EnumHandler {
+ V handle(int value);
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
index f241c32a5a..8275957ce6 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
@@ -10,10 +10,7 @@
import com.baidu.bjf.remoting.protobuf.utils.FieldInfo;
import com.baidu.bjf.remoting.protobuf.utils.ProtobufProxyUtils;
import com.baidu.bjf.remoting.protobuf.utils.StringUtils;
-import com.google.protobuf.ByteString;
-import com.google.protobuf.CodedOutputStream;
-import com.google.protobuf.MapEntry;
-import com.google.protobuf.WireFormat;
+import com.google.protobuf.*;
import com.taobao.arthas.protobuf.ProtobufCodec;
import com.taobao.arthas.protobuf.ProtobufField;
import com.taobao.arthas.protobuf.ProtobufFieldTypeEnum;
@@ -24,6 +21,7 @@
import java.io.IOException;
+import java.lang.Enum;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
@@ -286,6 +284,54 @@ public static void setField(Object t, String name, Object value) {
}
}
+ /**
+ * 读取 input put 进 map
+ * @param input
+ * @param map
+ * @param keyType
+ * @param defaultKey
+ * @param valueType
+ * @param defalutValue
+ * @param
+ * @param
+ * @throws IOException
+ */
+ public static void putMapValue(CodedInputStream input, Map map,
+ com.google.protobuf.WireFormat.FieldType keyType, K defaultKey,
+ com.google.protobuf.WireFormat.FieldType valueType, V defalutValue) throws IOException {
+ putMapValue(input, map, keyType, defaultKey, valueType, defalutValue, null);
+ }
+
+ public static void putMapValue(CodedInputStream input, Map map,
+ com.google.protobuf.WireFormat.FieldType keyType, K defaultKey,
+ com.google.protobuf.WireFormat.FieldType valueType, V defalutValue, EnumHandler handler)
+ throws IOException {
+ putMapValue(input, map, keyType, defaultKey, valueType, defalutValue, null, handler);
+
+ }
+
+ public static void putMapValue(CodedInputStream input, Map map,
+ com.google.protobuf.WireFormat.FieldType keyType, K defaultKey,
+ com.google.protobuf.WireFormat.FieldType valueType, V defalutValue, EnumHandler keyHandler, EnumHandler valHandler)
+ throws IOException {
+ MapEntry valuesDefaultEntry = MapEntry
+ . newDefaultInstance(null, keyType, defaultKey, valueType, defalutValue);
+
+ MapEntry values =
+ input.readMessage(valuesDefaultEntry.getParserForType(), null);
+
+ Object value = values.getValue();
+ Object key = values.getKey();
+ if (keyHandler != null) {
+ key = keyHandler.handle((int) key);
+ }
+
+ if (valHandler != null) {
+ value = valHandler.handle((int) value);
+ }
+ map.put((K) key, (V) value);
+ }
+
public static String getGetterDynamicString(ProtobufField protobufField, Class> dynamicTargetClass) {
Field field = protobufField.getJavaField();
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
index 9b23f66b59..cef758b1d5 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
@@ -26,7 +26,7 @@ public class ArthasSampleRequest{
private double age;
private long price;
private StatusEnum status;
- private List testList;
+ private List testList;
enum StatusEnum{
@@ -41,4 +41,8 @@ enum StatusEnum{
private int code;
private String desc;
}
+
+ static class TestClass{
+ private String name;
+ }
}
diff --git a/arthas-grpc-server/src/main/proto/Test.proto b/arthas-grpc-server/src/main/proto/Test.proto
index f9ffe3d740..366dd0ea3c 100644
--- a/arthas-grpc-server/src/main/proto/Test.proto
+++ b/arthas-grpc-server/src/main/proto/Test.proto
@@ -17,9 +17,12 @@ message HelloRequest {
double age = 2;
int64 price = 3;
StatusEnum status = 4;
- repeated string testList = 5;
+ repeated TestClass testList = 5;
}
+message TestClass{
+ string name = 1;
+}
message HelloReply {
string message = 1;
From be1d85ba55c6d9b217a5b34f98e79375076131ac Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Thu, 8 Aug 2024 01:45:50 +0800
Subject: [PATCH 18/48] update: add protobuf codec
---
.../src/main/java/com/taobao/arthas/Main.java | 2 ++
.../taobao/arthas/protobuf/ProtobufProxy.java | 21 +++++++------------
.../service/req/ArthasSampleRequest.java | 2 +-
.../src/main/resources/class_template.tpl | 13 +-----------
4 files changed, 11 insertions(+), 27 deletions(-)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java
index c00d2d95e8..7366ab07ae 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java
@@ -1,5 +1,6 @@
package com.taobao.arthas;
+import com.taobao.arthas.protobuf.*;
import com.taobao.arthas.protobuf.utils.MiniTemplator;
import java.io.IOException;
@@ -15,6 +16,7 @@ public class Main {
private static final String TEMPLATE_FILE = "/class_template.tpl";
public static void main(String[] args) throws IOException {
+
String path = Objects.requireNonNull(Main.class.getResource(TEMPLATE_FILE)).getPath();
MiniTemplator miniTemplator = new MiniTemplator(path);
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index e90dcec6b4..d78b11e8fb 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -75,6 +75,8 @@ public static ProtobufCodec create(Class> clazz) {
processEncodeBlock();
processDecodeBlock();
+ String s = miniTemplator.generateOutput();
+
return null;
}
@@ -83,10 +85,7 @@ private static void processImportBlock() {
imports.add("java.util.*");
imports.add("java.io.IOException");
imports.add("java.lang.reflect.*");
-// imports.add("com.baidu.bjf.remoting.protobuf.FieldType"); // fix the class ambiguous of FieldType
-// imports.add("com.baidu.bjf.remoting.protobuf.code.*");
-// imports.add("com.baidu.bjf.remoting.protobuf.utils.*");
-// imports.add("com.baidu.bjf.remoting.protobuf.*");
+ imports.add("import com.taobao.arthas.protobuf.*");
imports.add("com.google.protobuf.*");
imports.add(clazz.getName());
for (String pkg : imports) {
@@ -144,8 +143,6 @@ private static void processDecodeBlock() {
}
miniTemplator.setVariable("initListMapFields", initListMapFields.toString());
- //todo 继续看下
-
//处理字段赋值
StringBuilder code = new StringBuilder();
// 处理field解析
@@ -249,7 +246,7 @@ private static void processDecodeBlock() {
objectDecodeExpress = code.toString();
code.setLength(0);
- express = "Field.putMapValue(input, " + getMapCommand + ",";
+ express = "FieldUtil.putMapValue(input, " + getMapCommand + ",";
express += FieldUtil.getMapFieldGenericParameterString(protobufField);
if (protobufField.isEnumKeyType()) {
express += ", keyhandler";
@@ -355,12 +352,8 @@ private static void loadProtobufField() {
);
}
-// public static void main(String[] args) {
-// List protobufFieldList = FieldUtil.getProtobufFieldList(ArthasSampleRequest.class, false);
-// for (ProtobufField protobufField : protobufFieldList) {
-// String target = FieldUtil.getGetterDynamicString("target", protobufField.getJavaField(), ArthasSampleRequest.class, protobufField.isWildcardType());
-// System.out.println(target);
-// }
-// }
+ public static void main(String[] args) {
+ ProtobufCodec protobufCodec = ProtobufProxy.create(ArthasSampleRequest.class);
+ }
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
index cef758b1d5..0f037d78e2 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
@@ -4,8 +4,8 @@
*/
import com.baidu.bjf.remoting.protobuf.annotation.Protobuf;
-import com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass;
import com.google.protobuf.*;
+import com.taobao.arthas.protobuf.annotation.ProtobufClass;
import com.taobao.arthas.protobuf.annotation.ProtobufCustomizedField;
import com.taobao.arthas.protobuf.annotation.ProtobufIgnore;
diff --git a/arthas-grpc-server/src/main/resources/class_template.tpl b/arthas-grpc-server/src/main/resources/class_template.tpl
index dc12228468..9815d169ba 100644
--- a/arthas-grpc-server/src/main/resources/class_template.tpl
+++ b/arthas-grpc-server/src/main/resources/class_template.tpl
@@ -7,7 +7,6 @@ import ${importBlock};
public class ${className} implements ${codecClassName}<${targetProxyClassName}>, Serializable {
public static final long serialVersionUID = 1L;
- private ${descriptorClsName} descriptor;
public byte[] encode(${targetProxyClassName} target) throws IOException {
CodedOutputStreamCache outputCache = CodedOutputStreamCache.get();
@@ -79,17 +78,7 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
return target;
- }
-
-
- public com.google.protobuf.Descriptors.Descriptor getDescriptor() throws IOException {
- if (this.descriptor != null) {
- return this.descriptor;
- }
- com.google.protobuf.Descriptors.Descriptor descriptor =
- CodedConstant.getDescriptor(${targetProxyClassName}.class);
- return (this.descriptor = descriptor);
- }
+ }
}
\ No newline at end of file
From 5871052bbbbb121e158ac62368f83bc012dd382a Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Fri, 9 Aug 2024 02:27:32 +0800
Subject: [PATCH 19/48] update: add protobuf codec
---
.../taobao/arthas/protobuf/ProtobufCodec.java | 8 +-
.../taobao/arthas/protobuf/ProtobufProxy.java | 35 ++-
.../arthas/protobuf/utils/FieldUtil.java | 40 ++-
.../protobuf/utils/ProtoBufClassCompiler.java | 292 ++++++++++++++++++
.../service/req/ArthasSampleRequest.java | 1 +
.../src/main/resources/class_template.tpl | 6 +-
6 files changed, 369 insertions(+), 13 deletions(-)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/ProtoBufClassCompiler.java
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufCodec.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufCodec.java
index 38648013da..101b07e86e 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufCodec.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufCodec.java
@@ -3,6 +3,8 @@
* @date: 2024/7/17 下午9:44
*/
+import com.google.protobuf.CodedInputStream;
+
import java.io.IOException;
/**
@@ -11,9 +13,11 @@
* @description: Codec
*/
public interface ProtobufCodec {
- byte[] encode(T t);
+ byte[] encode(T t) throws IOException;
- T decode(byte[] bytes);
+ T decode(byte[] bytes) throws IOException;
int size(T t) throws IOException;
+
+ T readFrom(CodedInputStream intput) throws IOException;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index d78b11e8fb..26a72c37cc 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -4,14 +4,20 @@
*/
+import com.baidu.bjf.remoting.protobuf.Codec;
+import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
+import com.baidu.bjf.remoting.protobuf.utils.StringUtils;
import com.google.protobuf.WireFormat;
import com.taobao.arthas.protobuf.annotation.ProtobufEnableZigZap;
import com.taobao.arthas.protobuf.annotation.ProtobufClass;
import com.taobao.arthas.protobuf.utils.FieldUtil;
import com.taobao.arthas.protobuf.utils.MiniTemplator;
+import com.taobao.arthas.protobuf.utils.ProtoBufClassCompiler;
import com.taobao.arthas.service.req.ArthasSampleRequest;
import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -50,7 +56,7 @@ public ProtobufCodec getCodecCacheSide(Class> clazz) {
}
}
- public static ProtobufCodec create(Class> clazz) {
+ public static ProtobufCodec create(Class clazz) {
Objects.requireNonNull(clazz);
if (clazz.getAnnotation(ProtobufClass.class) == null) {
throw new IllegalArgumentException("class is not annotated with @ProtobufClass");
@@ -69,13 +75,31 @@ public static ProtobufCodec create(Class> clazz) {
processImportBlock();
- miniTemplator.setVariable("className", clazz.getName() + "$$ProxyClass");
+ miniTemplator.setVariable("className", FieldUtil.getClassName(clazz) + "$$ProxyClass");
miniTemplator.setVariable("codecClassName", ProtobufCodec.class.getName());
miniTemplator.setVariable("targetProxyClassName", clazz.getName());
processEncodeBlock();
processDecodeBlock();
- String s = miniTemplator.generateOutput();
+ String code = miniTemplator.generateOutput();
+
+ ProtoBufClassCompiler protoBufClassCompiler = new ProtoBufClassCompiler(ProtoBufClassCompiler.class.getClassLoader());
+ String fullClassName = FieldUtil.getFullClassName(clazz)+"$$ProxyClass";
+ Class> newClass = protoBufClassCompiler.compile(fullClassName, code, clazz.getClassLoader());
+
+ try {
+ ProtobufCodec newInstance = (ProtobufCodec)newClass.getDeclaredConstructor(new Class[0]).newInstance(new Object[0]);
+
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+
return null;
}
@@ -85,7 +109,9 @@ private static void processImportBlock() {
imports.add("java.util.*");
imports.add("java.io.IOException");
imports.add("java.lang.reflect.*");
- imports.add("import com.taobao.arthas.protobuf.*");
+ imports.add("com.taobao.arthas.protobuf.*");
+ imports.add("com.taobao.arthas.protobuf.utils.*");
+ imports.add("com.taobao.arthas.protobuf.annotation.*");
imports.add("com.google.protobuf.*");
imports.add(clazz.getName());
for (String pkg : imports) {
@@ -345,7 +371,6 @@ private static String getMapCommand(ProtobufField protobufField) {
return getMapCommand;
}
-
private static void loadProtobufField() {
protobufFields = FieldUtil.getProtobufFieldList(clazz,
clazz.getAnnotation(ProtobufEnableZigZap.class) != null
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
index 8275957ce6..309110b31c 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
@@ -286,6 +286,7 @@ public static void setField(Object t, String name, Object value) {
/**
* 读取 input put 进 map
+ *
* @param input
* @param map
* @param keyType
@@ -315,7 +316,7 @@ public static void putMapValue(CodedInputStream input, Map map,
com.google.protobuf.WireFormat.FieldType valueType, V defalutValue, EnumHandler keyHandler, EnumHandler valHandler)
throws IOException {
MapEntry valuesDefaultEntry = MapEntry
- . newDefaultInstance(null, keyType, defaultKey, valueType, defalutValue);
+ .newDefaultInstance(null, keyType, defaultKey, valueType, defalutValue);
MapEntry values =
input.readMessage(valuesDefaultEntry.getParserForType(), null);
@@ -404,7 +405,7 @@ public static String getSizeDynamicString(ProtobufField field) {
javaType = capitalize(javaType);
dynamicFieldName = dynamicFieldName + protobufFieldType.getToPrimitiveType();
//todo check 感觉上面这个有点问题,测试的时候看下
- return "com.google.protobuf.CodedOutputStream.compute" + javaType + "Size(" + order + "," + dynamicFieldName + ")"
+ return "com.google.protobuf.CodedOutputStream.compute" + javaType + "Size(" + order + "," + dynamicFieldName
+ ");" + LINE_BREAK;
}
@@ -423,7 +424,7 @@ public static String getWriteByteDynamicString(ProtobufField protobufField) {
if (protobufField.isList()) {
String typeString = protobufFieldType.getType().toUpperCase();
- sb.append("Field.writeList(").append(CODE_OUTPUT_STREAM_OBJ_NAME).append(",");
+ sb.append("FieldUtil.writeList(").append(CODE_OUTPUT_STREAM_OBJ_NAME).append(",");
sb.append(order).append(",").append(ProtobufFieldTypeEnum.class.getName()).append(".").append(typeString);
sb.append(",").append(dynamicFieldName).append(",").append(Boolean.valueOf(protobufField.isPacked())).append(")")
.append(JAVA_LINE_BREAK).append("}").append(LINE_BREAK);
@@ -1046,6 +1047,39 @@ public static String toObjectType(String primitiveType) {
return primitiveType;
}
+ public static String getFullClassName(Class> cls) {
+ if (StringUtils.isEmpty(getPackage(cls))) {
+ return getClassName(cls);
+ }
+
+ return getPackage(cls) + ClassHelper.PACKAGE_SEPARATOR + getClassName(cls);
+ }
+
+ public static String getPackage(Class> cls) {
+ Package pkg = cls.getPackage();
+ // maybe null if package is blank or dynamic load class
+ if (pkg == null) {
+ String fullName = cls.getName();
+ int index = fullName.lastIndexOf(PACKAGE_SEPARATOR);
+ if (index != -1) {
+ return fullName.substring(0, index);
+ }
+ return "";
+ }
+
+ return pkg.getName();
+ }
+
+ public static String getClassName(Class> cls) {
+ if (cls.isMemberClass()) {
+ String name = cls.getName();
+ name = StringUtils.substringAfterLast(name, PACKAGE_SEPARATOR);
+ return name;
+ }
+
+ return cls.getSimpleName();
+ }
+
public static boolean isNull(Object o) {
return o == null;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/ProtoBufClassCompiler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/ProtoBufClassCompiler.java
new file mode 100644
index 0000000000..5f60da3749
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/ProtoBufClassCompiler.java
@@ -0,0 +1,292 @@
+package com.taobao.arthas.protobuf.utils;/**
+ * @author: 風楪
+ * @date: 2024/8/9 01:21
+ */
+
+import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
+import com.baidu.bjf.remoting.protobuf.utils.compiler.ClassUtils;
+import com.baidu.bjf.remoting.protobuf.utils.compiler.JdkCompiler;
+import com.taobao.arthas.protobuf.ProtobufProxy;
+
+import javax.tools.*;
+import java.io.*;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+
+/**
+ * @author: FengYe
+ * @date: 2024/8/9 01:21
+ * @description: ProtoBufClassCompiler
+ */
+public class ProtoBufClassCompiler {
+
+ private final Map fileObjects = new HashMap();
+
+ private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+
+ private final ClassLoaderImpl classLoader;
+
+ private final JavaFileManagerImpl javaFileManager;
+
+ private volatile List options;
+
+ private static final String jdkVersion = "1.8";
+
+
+ public ProtoBufClassCompiler(final ClassLoader loader) {
+ options = new ArrayList();
+ options.add("-source");
+ options.add(jdkVersion);
+ options.add("-target");
+ options.add(jdkVersion);
+
+ DiagnosticCollector diagnosticCollector = new DiagnosticCollector();
+ StandardJavaFileManager manager =
+ compiler.getStandardFileManager(diagnosticCollector, null, StandardCharsets.UTF_8);
+
+ classLoader = AccessController.doPrivileged(new PrivilegedAction() {
+ public ClassLoaderImpl run() {
+ return new ClassLoaderImpl(loader);
+ }
+ });
+
+ javaFileManager = new JavaFileManagerImpl(manager, classLoader);
+ }
+
+ public synchronized Class> compile(String className, String code, ClassLoader classLoader) {
+ FileOutputStream fos = null;
+ code = code.trim();
+ try {
+ return Class.forName(className, true, classLoader);
+ } catch (ClassNotFoundException e) {
+ if (!code.endsWith("}")) {
+ throw new IllegalStateException("The java code not endsWith \"}\", code: \n" + code + "\n");
+ }
+ try {
+ return doCompile(className, code);
+ } catch (RuntimeException t) {
+ throw t;
+ } catch (Throwable t) {
+ throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: "
+ + className + ", code: \n" + code + "\n, stack: " + ClassUtils.toString(t));
+ }
+ }
+ }
+
+ public synchronized Class> doCompile(String name, String sourceCode) throws Throwable {
+ int i = name.lastIndexOf('.');
+ String packageName = i < 0 ? "" : name.substring(0, i);
+ String className = i < 0 ? name : name.substring(i + 1);
+ JavaFileObjectImpl javaFileObject = new JavaFileObjectImpl(className, sourceCode);
+ fileObjects.put(new URI(StandardLocation.SOURCE_PATH.getName() + "/" + packageName + "/" + className + ".java"), javaFileObject);
+ javaFileManager.putFileForInput(StandardLocation.SOURCE_PATH, packageName,
+ className + ClassUtils.JAVA_EXTENSION, javaFileObject);
+
+ DiagnosticCollector diagnosticCollector = new DiagnosticCollector();
+ Boolean result = compiler.getTask(null, javaFileManager, diagnosticCollector, options, null,
+ Arrays.asList(new JavaFileObject[]{javaFileObject})).call();
+ if (result == null || !result.booleanValue()) {
+ throw new IllegalStateException(
+ "Compilation failed. class: " + name + ", diagnostics: " + diagnosticCollector.getDiagnostics());
+ }
+
+ Class> retClass = classLoader.loadClass(name);
+
+ return retClass;
+ }
+
+ private static final class JavaFileManagerImpl extends ForwardingJavaFileManager {
+
+ private final ClassLoaderImpl classLoader;
+
+ private final Map fileObjects = new HashMap();
+
+ public JavaFileManagerImpl(JavaFileManager fileManager, ClassLoaderImpl classLoader) {
+ super(fileManager);
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ public FileObject getFileForInput(Location location, String packageName, String relativeName)
+ throws IOException {
+ FileObject o = fileObjects.get(uri(location, packageName, relativeName));
+ if (o != null) {
+ return o;
+ }
+ return super.getFileForInput(location, packageName, relativeName);
+ }
+
+ public void putFileForInput(StandardLocation location, String packageName, String relativeName,
+ JavaFileObject file) {
+ fileObjects.put(uri(location, packageName, relativeName), file);
+ }
+
+ private URI uri(Location location, String packageName, String relativeName) {
+ return ClassUtils.toURI(location.getName() + '/' + packageName + '/' + relativeName);
+ }
+
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location, String qualifiedName, JavaFileObject.Kind kind,
+ FileObject outputFile) throws IOException {
+ JavaFileObject file = new JavaFileObjectImpl(qualifiedName, kind);
+ classLoader.add(qualifiedName, file);
+ return file;
+ }
+
+ @Override
+ public ClassLoader getClassLoader(JavaFileManager.Location location) {
+ return classLoader;
+ }
+
+ @Override
+ public String inferBinaryName(Location loc, JavaFileObject file) {
+ if (file instanceof JavaFileObjectImpl) {
+ return file.getName();
+ }
+ return super.inferBinaryName(loc, file);
+ }
+
+ @Override
+ public Iterable list(Location location, String packageName, Set kinds, boolean recurse)
+ throws IOException {
+ Iterable result = super.list(location, packageName, kinds, recurse);
+
+ ArrayList files = new ArrayList();
+
+ if (location == StandardLocation.CLASS_PATH && kinds.contains(JavaFileObject.Kind.CLASS)) {
+ for (JavaFileObject file : fileObjects.values()) {
+ if (file.getKind() == JavaFileObject.Kind.CLASS && file.getName().startsWith(packageName)) {
+ files.add(file);
+ }
+ }
+
+ files.addAll(classLoader.files());
+ } else if (location == StandardLocation.SOURCE_PATH && kinds.contains(JavaFileObject.Kind.SOURCE)) {
+ for (JavaFileObject file : fileObjects.values()) {
+ if (file.getKind() == JavaFileObject.Kind.SOURCE && file.getName().startsWith(packageName)) {
+ files.add(file);
+ }
+ }
+ }
+
+ for (JavaFileObject file : result) {
+ files.add(file);
+ }
+
+ return files;
+ }
+ }
+
+
+ private final class ClassLoaderImpl extends ClassLoader {
+
+ private final Map classes = new HashMap();
+
+ ClassLoaderImpl(final ClassLoader parentClassLoader) {
+ super(parentClassLoader);
+ }
+
+ Collection files() {
+ return Collections.unmodifiableCollection(classes.values());
+ }
+
+ public byte[] loadClassBytes(final String qualifiedClassName) {
+ JavaFileObject file = classes.get(qualifiedClassName);
+ if (file != null) {
+ byte[] bytes = ((JavaFileObjectImpl) file).getByteCode();
+ return bytes;
+ }
+ return null;
+ }
+
+ @Override
+ protected Class> findClass(final String qualifiedClassName) throws ClassNotFoundException {
+ JavaFileObject file = classes.get(qualifiedClassName);
+ if (file != null) {
+ byte[] bytes = ((JavaFileObjectImpl) file).getByteCode();
+ return defineClass(qualifiedClassName, bytes, 0, bytes.length);
+ }
+ try {
+ return ClassHelper.forNameWithCallerClassLoader(qualifiedClassName, getClass());
+ } catch (ClassNotFoundException nf) {
+ return super.findClass(qualifiedClassName);
+ }
+ }
+
+ void add(final String qualifiedClassName, final JavaFileObject javaFile) {
+ classes.put(qualifiedClassName, javaFile);
+ }
+
+ @Override
+ protected synchronized Class> loadClass(final String name, final boolean resolve)
+ throws ClassNotFoundException {
+ return super.loadClass(name, resolve);
+ }
+
+ @Override
+ public InputStream getResourceAsStream(final String name) {
+ if (name.endsWith(ClassUtils.CLASS_EXTENSION)) {
+ String qualifiedClassName =
+ name.substring(0, name.length() - ClassUtils.CLASS_EXTENSION.length()).replace('/', '.');
+ JavaFileObjectImpl file = (JavaFileObjectImpl) classes.get(qualifiedClassName);
+ if (file != null) {
+ return new ByteArrayInputStream(file.getByteCode());
+ }
+ }
+ return super.getResourceAsStream(name);
+ }
+ }
+
+
+ private static final class JavaFileObjectImpl extends SimpleJavaFileObject {
+
+ private ByteArrayOutputStream bytecode;
+
+ private final CharSequence source;
+
+ public JavaFileObjectImpl(final String baseName, final CharSequence source) throws URISyntaxException {
+ super(new URI(baseName + ClassUtils.JAVA_EXTENSION), Kind.SOURCE);
+ this.source = source;
+ }
+
+ JavaFileObjectImpl(final String name, final Kind kind) {
+ super(ClassUtils.toURI(name), kind);
+ source = null;
+ }
+
+ public JavaFileObjectImpl(URI uri, Kind kind) {
+ super(uri, kind);
+ source = null;
+ }
+
+ @Override
+ public CharSequence getCharContent(final boolean ignoreEncodingErrors) throws UnsupportedOperationException {
+ if (source == null) {
+ throw new UnsupportedOperationException("source == null");
+ }
+ return source;
+ }
+
+ @Override
+ public InputStream openInputStream() {
+ return new ByteArrayInputStream(getByteCode());
+ }
+
+ @Override
+ public OutputStream openOutputStream() {
+ return bytecode = new ByteArrayOutputStream();
+ }
+
+ public byte[] getByteCode() {
+ if (bytecode == null) {
+ return null;
+ }
+ return bytecode.toByteArray();
+ }
+ }
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
index 0f037d78e2..543b3bcebf 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
@@ -20,6 +20,7 @@
* @description: ArthasSampleRequest
*/
@ProtobufClass
+@com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass
public class ArthasSampleRequest{
private String name;
diff --git a/arthas-grpc-server/src/main/resources/class_template.tpl b/arthas-grpc-server/src/main/resources/class_template.tpl
index 9815d169ba..a2ff4bc984 100644
--- a/arthas-grpc-server/src/main/resources/class_template.tpl
+++ b/arthas-grpc-server/src/main/resources/class_template.tpl
@@ -14,7 +14,7 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
return outputCache.getData();
}
- public void doWriteTo(${targetProxyClassName} t, CodedOutputStream output)
+ public void doWriteTo(${targetProxyClassName} target, CodedOutputStream output)
throws IOException {
${dynamicFieldType} ${dynamicFieldName} = null;
@@ -34,7 +34,7 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
int size = 0;
${dynamicFieldType} ${dynamicFieldName} = null;
- if (!CodedConstant.isNull(${dynamicFieldGetter})) {
+ if (!FieldUtil.isNull(${dynamicFieldGetter})) {
${dynamicFieldName} = ${dynamicFieldGetter};
size += ${sizeDynamicString}
}
@@ -52,7 +52,7 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
try {
boolean done = false;
- Codec codec = null;
+ ProtobufCodec codec = null;
while (!done) {
int tag = input.readTag();
if (tag == 0) {
From 500e64a91b2b0820a34816cb0d081b8cb509f353 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Sat, 10 Aug 2024 03:31:22 +0800
Subject: [PATCH 20/48] update: add protobuf codec
---
.../com/taobao/arthas/h2/Http2Handler.java | 13 +++++++++-
.../taobao/arthas/protobuf/ProtobufProxy.java | 24 +++++++++----------
.../service/req/ArthasSampleRequest.java | 20 ++++++++++------
3 files changed, 36 insertions(+), 21 deletions(-)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
index 74f579e80e..5e0a11bff6 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
@@ -6,6 +6,7 @@
import com.baidu.bjf.remoting.protobuf.Codec;
import com.baidu.bjf.remoting.protobuf.ProtobufProxy;
import com.google.protobuf.CodedInputStream;
+import com.taobao.arthas.protobuf.ProtobufCodec;
import com.taobao.arthas.service.ArthasSampleService;
import com.taobao.arthas.service.req.ArthasSampleRequest;
import io.netty.buffer.ByteBuf;
@@ -75,9 +76,19 @@ protected void channelRead0(ChannelHandlerContext ctx, Http2Frame frame) throws
byte[] byteArray = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(byteArray);
- Codec codec = ProtobufProxy.create(ArthasSampleRequest.class);
+ Codec codec = ProtobufProxy.create(ArthasSampleRequest.class,true);
+ ProtobufCodec protobufCodec = com.taobao.arthas.protobuf.ProtobufProxy.create(ArthasSampleRequest.class);
+
ArthasSampleRequest decode = codec.decode(byteArray);
+ ArthasSampleRequest decode1 = protobufCodec.decode(byteArray);
+
+ System.out.println(codec.decode(protobufCodec.encode(decode1)));
+ System.out.println(protobufCodec.decode(protobufCodec.encode(decode)));
+ System.out.println(codec.decode(codec.encode(decode1)));
+ System.out.println(protobufCodec.decode(codec.encode(decode1)));
+
System.out.println(decode);
+ System.out.println(decode1);
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index 26a72c37cc..3717130274 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -59,7 +59,7 @@ public ProtobufCodec getCodecCacheSide(Class> clazz) {
public static ProtobufCodec create(Class clazz) {
Objects.requireNonNull(clazz);
if (clazz.getAnnotation(ProtobufClass.class) == null) {
- throw new IllegalArgumentException("class is not annotated with @ProtobufClass");
+ throw new IllegalArgumentException(clazz + "class is not annotated with @ProtobufClass");
}
ProtobufProxy.clazz = clazz;
loadProtobufField();
@@ -77,19 +77,20 @@ public static ProtobufCodec create(Class clazz) {
miniTemplator.setVariable("className", FieldUtil.getClassName(clazz) + "$$ProxyClass");
miniTemplator.setVariable("codecClassName", ProtobufCodec.class.getName());
- miniTemplator.setVariable("targetProxyClassName", clazz.getName());
+ miniTemplator.setVariable("targetProxyClassName", clazz.getCanonicalName());
processEncodeBlock();
processDecodeBlock();
String code = miniTemplator.generateOutput();
+ System.out.println(code);
ProtoBufClassCompiler protoBufClassCompiler = new ProtoBufClassCompiler(ProtoBufClassCompiler.class.getClassLoader());
- String fullClassName = FieldUtil.getFullClassName(clazz)+"$$ProxyClass";
+ String fullClassName = FieldUtil.getFullClassName(clazz) + "$$ProxyClass";
Class> newClass = protoBufClassCompiler.compile(fullClassName, code, clazz.getClassLoader());
try {
- ProtobufCodec newInstance = (ProtobufCodec)newClass.getDeclaredConstructor(new Class[0]).newInstance(new Object[0]);
-
+ ProtobufCodec newInstance = (ProtobufCodec) newClass.getDeclaredConstructor(new Class[0]).newInstance(new Object[0]);
+ return newInstance;
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
@@ -99,9 +100,6 @@ public static ProtobufCodec create(Class clazz) {
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
-
-
- return null;
}
private static void processImportBlock() {
@@ -113,7 +111,7 @@ private static void processImportBlock() {
imports.add("com.taobao.arthas.protobuf.utils.*");
imports.add("com.taobao.arthas.protobuf.annotation.*");
imports.add("com.google.protobuf.*");
- imports.add(clazz.getName());
+ imports.add(clazz.getCanonicalName());
for (String pkg : imports) {
miniTemplator.setVariable("importBlock", pkg);
miniTemplator.addBlock("imports");
@@ -161,7 +159,7 @@ private static void processDecodeBlock() {
if (!isList) {
express = "FieldUtil.getEnumValue(" + clsName + ".class, " + clsName + ".values()[0].name())";
// add set get method
- String setToField = FieldUtil.getSetFieldDynamicString(protobufField,clazz,express);
+ String setToField = FieldUtil.getSetFieldDynamicString(protobufField, clazz, express);
miniTemplator.setVariable("enumInitialize", setToField);
miniTemplator.addBlock("enumFields");
}
@@ -206,7 +204,7 @@ private static void processDecodeBlock() {
} else {
// here is the trick way to process BigDecimal and BigInteger
if (protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.BIGDECIMAL || protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.BIGINTEGER) {
- express = "new " + protobufField.getProtobufFieldType().getJavaType() + "(input.read" + t + "())";
+ express = "new " + protobufField.getProtobufFieldType().getJavaType() + "(input.read" + t + "())";
} else {
express = "input.read" + t + "()";
}
@@ -313,7 +311,7 @@ private static void processDecodeBlock() {
express += ".toByteArray()";
}
- String decodeFieldSetValue = FieldUtil.getSetFieldDynamicString(protobufField,clazz,express) + FieldUtil.JAVA_LINE_BREAK;
+ String decodeFieldSetValue = FieldUtil.getSetFieldDynamicString(protobufField, clazz, express) + FieldUtil.JAVA_LINE_BREAK;
if (listTypeCheck) {
objectDecodeExpressSuffix += "input.checkLastTagWas(0)" + FieldUtil.JAVA_LINE_BREAK;
@@ -332,7 +330,7 @@ private static void processDecodeBlock() {
code.append("int length = input.readRawVarint32()").append(FieldUtil.JAVA_LINE_BREAK);
code.append("int limit = input.pushLimit(length)").append(FieldUtil.JAVA_LINE_BREAK);
- code.append(FieldUtil.getSetFieldDynamicString(protobufField,clazz,express));
+ code.append(FieldUtil.getSetFieldDynamicString(protobufField, clazz, express));
code.append("input.popLimit(limit)").append(FieldUtil.JAVA_LINE_BREAK);
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
index 543b3bcebf..95128e9ffa 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
@@ -8,6 +8,7 @@
import com.taobao.arthas.protobuf.annotation.ProtobufClass;
import com.taobao.arthas.protobuf.annotation.ProtobufCustomizedField;
import com.taobao.arthas.protobuf.annotation.ProtobufIgnore;
+import lombok.ToString;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -19,9 +20,11 @@
* @date: 2024/7/14 上午4:28
* @description: ArthasSampleRequest
*/
-@ProtobufClass
+
@com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass
-public class ArthasSampleRequest{
+@ProtobufClass
+@ToString
+public class ArthasSampleRequest {
private String name;
private double age;
@@ -29,10 +32,11 @@ public class ArthasSampleRequest{
private StatusEnum status;
private List testList;
-
- enum StatusEnum{
- START(1,"开始"),
- STOP(2,"结束");
+ @com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass
+ @ProtobufClass
+ public enum StatusEnum {
+ START(1, "开始"),
+ STOP(2, "结束");
StatusEnum(int code, String desc) {
this.code = code;
@@ -43,7 +47,9 @@ enum StatusEnum{
private String desc;
}
- static class TestClass{
+ @com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass
+ @ProtobufClass
+ public static class TestClass {
private String name;
}
}
From 2248532f1786dda2419446e1437f40e73eaf646f Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Mon, 12 Aug 2024 01:47:22 +0800
Subject: [PATCH 21/48] update: add grpc handler
---
.../com/taobao/arthas/h2/Http2Handler.java | 123 +++++++++---------
.../taobao/arthas/protobuf/ProtobufProxy.java | 1 -
.../service/req/ArthasSampleRequest.java | 40 ++++++
.../service/res/ArthasSampleResponse.java | 24 ++++
.../proto/{Test.proto => arthasSample.proto} | 10 +-
5 files changed, 129 insertions(+), 69 deletions(-)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/service/res/ArthasSampleResponse.java
rename arthas-grpc-server/src/main/proto/{Test.proto => arthasSample.proto} (59%)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
index 5e0a11bff6..407b955aa1 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
@@ -4,11 +4,11 @@
*/
import com.baidu.bjf.remoting.protobuf.Codec;
-import com.baidu.bjf.remoting.protobuf.ProtobufProxy;
-import com.google.protobuf.CodedInputStream;
import com.taobao.arthas.protobuf.ProtobufCodec;
+import com.taobao.arthas.protobuf.ProtobufProxy;
import com.taobao.arthas.service.ArthasSampleService;
import com.taobao.arthas.service.req.ArthasSampleRequest;
+import com.taobao.arthas.service.res.ArthasSampleResponse;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.channel.ChannelHandlerContext;
@@ -37,82 +37,79 @@ public class Http2Handler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Http2Frame frame) throws IOException {
if (frame instanceof Http2HeadersFrame) {
- System.out.println("header");
- Http2HeadersFrame headersFrame = (Http2HeadersFrame) frame;
- int id = headersFrame.stream().id();
- dataBuffer.put(id, ctx.alloc().buffer());
-
- System.out.println("Received headers: " + headersFrame.headers());
- System.out.println(headersFrame.headers().path().toString());
+ handleGrpcRequest((Http2HeadersFrame) frame, ctx);
+ } else if (frame instanceof Http2DataFrame) {
+ handleGrpcData((Http2DataFrame) frame,ctx);
+ }
+ }
- // Respond to the client with headers
- Http2Headers responseHeaders = new DefaultHttp2Headers()
- .status("200")
- .set("content-type", "text/plain; charset=UTF-8");
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ cause.printStackTrace();
+ ctx.close();
+ }
- // 创建响应数据
- byte[] content = "Hello, HTTP/2 World!".getBytes();
- Http2DataFrame dataFrame = new DefaultHttp2DataFrame(ctx.alloc().buffer().writeBytes(content), true);
+ private void handleGrpcRequest(Http2HeadersFrame headersFrame, ChannelHandlerContext ctx) {
+ int id = headersFrame.stream().id();
+ dataBuffer.put(id, ctx.alloc().buffer());
- // 发送响应头
- ctx.write(new DefaultHttp2HeadersFrame(responseHeaders).stream(headersFrame.stream()));
+ System.out.println("Received headers: " + headersFrame.headers());
+ System.out.println(headersFrame.headers().path().toString());
- // 发送响应数据
- ctx.writeAndFlush(dataFrame.stream(headersFrame.stream()));
+ // Respond to the client with headers
+ Http2Headers responseHeaders = new DefaultHttp2Headers()
+ .status("200")
+ .set("content-type", "text/plain; charset=UTF-8");
- } else if (frame instanceof Http2DataFrame) {
- Http2DataFrame dataFrame = (Http2DataFrame) frame;
- byte[] data = new byte[dataFrame.content().readableBytes()];
- System.out.println(dataFrame.content().readableBytes());
- System.out.println(dataFrame.isEndStream());
- dataFrame.content().readBytes(data);
+ // 创建响应数据
+ byte[] content = "Hello, HTTP/2 World!".getBytes();
+ Http2DataFrame dataFrame = new DefaultHttp2DataFrame(ctx.alloc().buffer().writeBytes(content), true);
-// Decompress if needed
- byte[] decompressedData = decompressGzip(data);
- ByteBuf byteBuf = dataBuffer.get(dataFrame.stream().id());
- byteBuf.writeBytes(decompressedData);
- if (dataFrame.isEndStream()) {
- byteBuf.readBytes(5);
+ // 发送响应头
+ ctx.write(new DefaultHttp2HeadersFrame(responseHeaders).stream(headersFrame.stream()));
- byte[] byteArray = new byte[byteBuf.readableBytes()];
- byteBuf.readBytes(byteArray);
- Codec codec = ProtobufProxy.create(ArthasSampleRequest.class,true);
- ProtobufCodec protobufCodec = com.taobao.arthas.protobuf.ProtobufProxy.create(ArthasSampleRequest.class);
+ // 发送响应数据
+ ctx.writeAndFlush(dataFrame.stream(headersFrame.stream()));
+ }
- ArthasSampleRequest decode = codec.decode(byteArray);
- ArthasSampleRequest decode1 = protobufCodec.decode(byteArray);
+ private void handleGrpcData(Http2DataFrame dataFrame,ChannelHandlerContext ctx) throws IOException {
+ byte[] data = new byte[dataFrame.content().readableBytes()];
+ System.out.println(dataFrame.content().readableBytes());
+ System.out.println(dataFrame.isEndStream());
+ dataFrame.content().readBytes(data);
- System.out.println(codec.decode(protobufCodec.encode(decode1)));
- System.out.println(protobufCodec.decode(protobufCodec.encode(decode)));
- System.out.println(codec.decode(codec.encode(decode1)));
- System.out.println(protobufCodec.decode(codec.encode(decode1)));
+// Decompress if needed
+ byte[] decompressedData = decompressGzip(data);
+ ByteBuf byteBuf = dataBuffer.get(dataFrame.stream().id());
+ byteBuf.writeBytes(decompressedData);
- System.out.println(decode);
- System.out.println(decode1);
+ byte[] responseData = null;
+ if (dataFrame.isEndStream()) {
+ byteBuf.readBytes(5);
- }
+ byte[] byteArray = new byte[byteBuf.readableBytes()];
+ byteBuf.readBytes(byteArray);
+ ProtobufCodec requestCodec = ProtobufProxy.create(ArthasSampleRequest.class);
+ ProtobufCodec responseCodec = ProtobufProxy.create(ArthasSampleResponse.class);
+ ArthasSampleRequest decode = requestCodec.decode(byteArray);
-//
-// byte[] responseData = "hello".getBytes();
-//
-// // Send response
-// Http2Headers responseHeaders = new DefaultHttp2Headers()
-// .status("200")
-// .set("content-type", "application/grpc");
-// ctx.write(new DefaultHttp2HeadersFrame(responseHeaders));
-// ctx.writeAndFlush(new DefaultHttp2DataFrame(ctx.alloc().buffer().writeBytes(responseData)).stream(dataFrame.stream()));
-// System.out.println("finish");
-// if (((Http2DataFrame) frame).isEndStream()) {
-// dataFrame.release();
-// }
+ ArthasSampleResponse arthasSampleResponse = new ArthasSampleResponse();
+ arthasSampleResponse.setMessage(decode.getName());
+ responseData = responseCodec.encode(arthasSampleResponse);
}
- }
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
- cause.printStackTrace();
- ctx.close();
+
+ // Send response
+ Http2Headers responseHeaders = new DefaultHttp2Headers()
+ .status("200")
+ .set("content-type", "application/grpc");
+ ctx.write(new DefaultHttp2HeadersFrame(responseHeaders));
+ ctx.writeAndFlush(new DefaultHttp2DataFrame(ctx.alloc().buffer().writeBytes(responseData)).stream(dataFrame.stream()));
+ System.out.println("finish");
+ if (dataFrame.isEndStream()) {
+ dataFrame.release();
+ }
}
private static byte[] decompressGzip(byte[] compressedData) throws IOException {
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
index 3717130274..3909ec254b 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
@@ -82,7 +82,6 @@ public static ProtobufCodec create(Class clazz) {
processDecodeBlock();
String code = miniTemplator.generateOutput();
- System.out.println(code);
ProtoBufClassCompiler protoBufClassCompiler = new ProtoBufClassCompiler(ProtoBufClassCompiler.class.getClassLoader());
String fullClassName = FieldUtil.getFullClassName(clazz) + "$$ProxyClass";
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
index 95128e9ffa..159b395dd7 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
@@ -52,4 +52,44 @@ public enum StatusEnum {
public static class TestClass {
private String name;
}
+
+ public List getTestList() {
+ return testList;
+ }
+
+ public void setTestList(List testList) {
+ this.testList = testList;
+ }
+
+ public StatusEnum getStatus() {
+ return status;
+ }
+
+ public void setStatus(StatusEnum status) {
+ this.status = status;
+ }
+
+ public long getPrice() {
+ return price;
+ }
+
+ public void setPrice(long price) {
+ this.price = price;
+ }
+
+ public double getAge() {
+ return age;
+ }
+
+ public void setAge(double age) {
+ this.age = age;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/res/ArthasSampleResponse.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/res/ArthasSampleResponse.java
new file mode 100644
index 0000000000..06a357e010
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/res/ArthasSampleResponse.java
@@ -0,0 +1,24 @@
+package com.taobao.arthas.service.res;/**
+ * @author: 風楪
+ * @date: 2024/8/11 22:11
+ */
+
+import com.taobao.arthas.protobuf.annotation.ProtobufClass;
+
+/**
+ * @author: FengYe
+ * @date: 2024/8/11 22:11
+ * @description: ArthasSampleResponse
+ */
+@ProtobufClass
+public class ArthasSampleResponse {
+ private String message;
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/arthas-grpc-server/src/main/proto/Test.proto b/arthas-grpc-server/src/main/proto/arthasSample.proto
similarity index 59%
rename from arthas-grpc-server/src/main/proto/Test.proto
rename to arthas-grpc-server/src/main/proto/arthasSample.proto
index 366dd0ea3c..04c0b869ca 100644
--- a/arthas-grpc-server/src/main/proto/Test.proto
+++ b/arthas-grpc-server/src/main/proto/arthasSample.proto
@@ -1,6 +1,6 @@
syntax = "proto3";
-package helloworld;
+package arthasSample;
enum StatusEnum {
@@ -8,11 +8,11 @@ enum StatusEnum {
STOP = 1;
}
-service HelloService {
- rpc SayHello(HelloRequest) returns (HelloReply);
+service ArthasService {
+ rpc SayHello(ArthasSampleRequest) returns (ArthasSampleResponse);
}
-message HelloRequest {
+message ArthasSampleRequest {
string name = 1;
double age = 2;
int64 price = 3;
@@ -24,6 +24,6 @@ message TestClass{
string name = 1;
}
-message HelloReply {
+message ArthasSampleResponse {
string message = 1;
}
From 77abc18aeda08755a88a58a82f1f8f79b5650127 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Tue, 13 Aug 2024 02:17:07 +0800
Subject: [PATCH 22/48] update: add grpc handler
---
arthas-grpc-server/pom.xml | 49 +++++++++----------
.../src/main/java/com/taobao/arthas/Main.java | 26 +++++++---
.../com/taobao/arthas/h2/Http2Handler.java | 33 +++++++------
.../java/com/taobao/arthas/temp/TempImpl.java | 22 +++++++++
.../src/main/proto/arthasSample.proto | 2 +-
5 files changed, 85 insertions(+), 47 deletions(-)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/temp/TempImpl.java
diff --git a/arthas-grpc-server/pom.xml b/arthas-grpc-server/pom.xml
index 1f98315dbc..7edcc6739d 100644
--- a/arthas-grpc-server/pom.xml
+++ b/arthas-grpc-server/pom.xml
@@ -42,27 +42,29 @@
4.1.111.Final
-
- com.google.protobuf
- protobuf-java
- 4.27.2
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+ io.grpc
+ grpc-netty
+
+
+ io.grpc
+ grpc-services
+
@@ -86,12 +88,6 @@
provided
-
- com.squareup.wire
- wire-runtime
- 4.2.0
-
-
com.baidu
jprotobuf
@@ -110,13 +106,14 @@
${basedir}/src/main/proto
com.google.protobuf:protoc:3.11.0:exe:${os.detected.classifier}
+ grpc-java
+ io.grpc:protoc-gen-grpc-java:1.28.0:exe:${os.detected.classifier}
compile
-
-
+ compile-custom
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java
index 7366ab07ae..a17cdb74bc 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java
@@ -1,7 +1,13 @@
package com.taobao.arthas;
+import arthasSample.ArthasSample;
import com.taobao.arthas.protobuf.*;
import com.taobao.arthas.protobuf.utils.MiniTemplator;
+import com.taobao.arthas.service.ArthasSampleService;
+import com.taobao.arthas.service.impl.ArthasSampleServiceImpl;
+import com.taobao.arthas.temp.TempImpl;
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
import java.io.IOException;
import java.io.InputStream;
@@ -15,14 +21,22 @@ public class Main {
private static final String TEMPLATE_FILE = "/class_template.tpl";
- public static void main(String[] args) throws IOException {
+ private static Server server;
- String path = Objects.requireNonNull(Main.class.getResource(TEMPLATE_FILE)).getPath();
+ public static void main(String[] args) throws Exception {
+ Main service = new Main();
+ service.start();
+ service.blockUntilShutdown();
+ }
- MiniTemplator miniTemplator = new MiniTemplator(path);
+ public static void start() throws IOException {
+ ServerBuilder builder = ServerBuilder.forPort(9090)
+ .addService(new TempImpl());
+ server = builder.build();
+ server.start();
+ }
- miniTemplator.setVariable("importPackage","test");
- miniTemplator.addBlock("imports");
- System.out.println(miniTemplator.generateOutput());
+ public void blockUntilShutdown() throws InterruptedException {
+ server.awaitTermination();
}
}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
index 407b955aa1..0fb2c0a06c 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
@@ -83,9 +83,9 @@ private void handleGrpcData(Http2DataFrame dataFrame,ChannelHandlerContext ctx)
ByteBuf byteBuf = dataBuffer.get(dataFrame.stream().id());
byteBuf.writeBytes(decompressedData);
- byte[] responseData = null;
if (dataFrame.isEndStream()) {
- byteBuf.readBytes(5);
+ int length = byteBuf.readInt();
+ boolean b = byteBuf.readBoolean();
byte[] byteArray = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(byteArray);
@@ -94,21 +94,26 @@ private void handleGrpcData(Http2DataFrame dataFrame,ChannelHandlerContext ctx)
ArthasSampleRequest decode = requestCodec.decode(byteArray);
+ System.out.println(decode);
+
ArthasSampleResponse arthasSampleResponse = new ArthasSampleResponse();
arthasSampleResponse.setMessage(decode.getName());
- responseData = responseCodec.encode(arthasSampleResponse);
- }
-
+ byte[] responseData = responseCodec.encode(arthasSampleResponse);
+
+ // Send response
+ Http2Headers responseHeaders = new DefaultHttp2Headers()
+ .status("200")
+ .set("content-type", "application/grpc");
+ ctx.write(new DefaultHttp2HeadersFrame(responseHeaders));
+ ByteBuf buffer = ctx.alloc().buffer();
+ buffer.writeInt(responseData.length);
+ buffer.writeBoolean(false);
+ buffer.writeBytes(responseData);
+ System.out.println(responseData.length);
+ ctx.writeAndFlush(new DefaultHttp2DataFrame(buffer,true).stream(dataFrame.stream()));
+// dataFrame.retain();
+ } else {
- // Send response
- Http2Headers responseHeaders = new DefaultHttp2Headers()
- .status("200")
- .set("content-type", "application/grpc");
- ctx.write(new DefaultHttp2HeadersFrame(responseHeaders));
- ctx.writeAndFlush(new DefaultHttp2DataFrame(ctx.alloc().buffer().writeBytes(responseData)).stream(dataFrame.stream()));
- System.out.println("finish");
- if (dataFrame.isEndStream()) {
- dataFrame.release();
}
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/temp/TempImpl.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/temp/TempImpl.java
new file mode 100644
index 0000000000..62df4452ee
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/temp/TempImpl.java
@@ -0,0 +1,22 @@
+package com.taobao.arthas.temp;/**
+ * @author: 風楪
+ * @date: 2024/8/13 01:57
+ */
+
+import arthasSample.ArthasSample;
+import arthasSample.ArthasTempServiceGrpc;
+import io.grpc.stub.StreamObserver;
+
+/**
+ * @author: FengYe
+ * @date: 2024/8/13 01:57
+ * @description: TempImpl
+ */
+public class TempImpl extends ArthasTempServiceGrpc.ArthasTempServiceImplBase {
+ @Override
+ public void sayHello(ArthasSample.ArthasSampleRequest request, StreamObserver responseObserver) {
+ ArthasSample.ArthasSampleResponse build = ArthasSample.ArthasSampleResponse.newBuilder().setMessage("Hello ArthasSample!").build();
+ responseObserver.onNext(build);
+ responseObserver.onCompleted();
+ }
+}
diff --git a/arthas-grpc-server/src/main/proto/arthasSample.proto b/arthas-grpc-server/src/main/proto/arthasSample.proto
index 04c0b869ca..c74da27e31 100644
--- a/arthas-grpc-server/src/main/proto/arthasSample.proto
+++ b/arthas-grpc-server/src/main/proto/arthasSample.proto
@@ -8,7 +8,7 @@ enum StatusEnum {
STOP = 1;
}
-service ArthasService {
+service ArthasTempService {
rpc SayHello(ArthasSampleRequest) returns (ArthasSampleResponse);
}
From ec65cb3f4b7cfbc1118458a08cbb14dab1b54892 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Tue, 20 Aug 2024 03:13:52 +0800
Subject: [PATCH 23/48] update: add grpc handler
---
.../src/main/java/com/taobao/arthas/h2/Http2Handler.java | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
index 0fb2c0a06c..3a5fd3bc75 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
@@ -34,6 +34,8 @@ public class Http2Handler extends SimpleChannelInboundHandler {
*/
private ConcurrentHashMap dataBuffer = new ConcurrentHashMap<>();
+ private final Http2FrameWriter frameWriter = new DefaultHttp2FrameWriter();
+
@Override
protected void channelRead0(ChannelHandlerContext ctx, Http2Frame frame) throws IOException {
if (frame instanceof Http2HeadersFrame) {
@@ -104,14 +106,15 @@ private void handleGrpcData(Http2DataFrame dataFrame,ChannelHandlerContext ctx)
Http2Headers responseHeaders = new DefaultHttp2Headers()
.status("200")
.set("content-type", "application/grpc");
- ctx.write(new DefaultHttp2HeadersFrame(responseHeaders));
+ DefaultHttp2HeadersFrame headersFrame = new DefaultHttp2HeadersFrame(responseHeaders);
+ ctx.write(headersFrame);
ByteBuf buffer = ctx.alloc().buffer();
buffer.writeInt(responseData.length);
buffer.writeBoolean(false);
buffer.writeBytes(responseData);
System.out.println(responseData.length);
- ctx.writeAndFlush(new DefaultHttp2DataFrame(buffer,true).stream(dataFrame.stream()));
-// dataFrame.retain();
+ DefaultHttp2DataFrame stream = new DefaultHttp2DataFrame(buffer, true).stream(dataFrame.stream());
+ ctx.writeAndFlush(stream);
} else {
}
From f55e872512568d4531e3e3e23ee967f0b18d78ca Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Wed, 28 Aug 2024 01:35:36 +0800
Subject: [PATCH 24/48] update: add grpc handler implement grpc successfully!!!
---
.../com/taobao/arthas/h2/Http2Handler.java | 75 +++++++++----------
1 file changed, 36 insertions(+), 39 deletions(-)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
index 3a5fd3bc75..4f0501c235 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
@@ -3,22 +3,19 @@
* @date: 2024/7/7 下午9:58
*/
-import com.baidu.bjf.remoting.protobuf.Codec;
import com.taobao.arthas.protobuf.ProtobufCodec;
import com.taobao.arthas.protobuf.ProtobufProxy;
-import com.taobao.arthas.service.ArthasSampleService;
import com.taobao.arthas.service.req.ArthasSampleRequest;
import com.taobao.arthas.service.res.ArthasSampleResponse;
import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufInputStream;
+import io.netty.buffer.PooledByteBufAllocator;
+import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http2.*;
-import io.netty.util.CharsetUtil;
import java.io.*;
-import java.util.HashMap;
-import java.util.Map;
+import java.nio.charset.StandardCharsets;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.GZIPInputStream;
@@ -34,17 +31,23 @@ public class Http2Handler extends SimpleChannelInboundHandler {
*/
private ConcurrentHashMap dataBuffer = new ConcurrentHashMap<>();
- private final Http2FrameWriter frameWriter = new DefaultHttp2FrameWriter();
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ super.channelRead(ctx, msg);
+ }
@Override
protected void channelRead0(ChannelHandlerContext ctx, Http2Frame frame) throws IOException {
- if (frame instanceof Http2HeadersFrame) {
+ if (frame instanceof Http2SettingsFrame) {
+
+ } else if (frame instanceof Http2HeadersFrame) {
handleGrpcRequest((Http2HeadersFrame) frame, ctx);
} else if (frame instanceof Http2DataFrame) {
- handleGrpcData((Http2DataFrame) frame,ctx);
+ handleGrpcData((Http2DataFrame) frame, ctx);
}
}
+
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
@@ -54,30 +57,11 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
private void handleGrpcRequest(Http2HeadersFrame headersFrame, ChannelHandlerContext ctx) {
int id = headersFrame.stream().id();
dataBuffer.put(id, ctx.alloc().buffer());
-
System.out.println("Received headers: " + headersFrame.headers());
- System.out.println(headersFrame.headers().path().toString());
-
- // Respond to the client with headers
- Http2Headers responseHeaders = new DefaultHttp2Headers()
- .status("200")
- .set("content-type", "text/plain; charset=UTF-8");
-
- // 创建响应数据
- byte[] content = "Hello, HTTP/2 World!".getBytes();
- Http2DataFrame dataFrame = new DefaultHttp2DataFrame(ctx.alloc().buffer().writeBytes(content), true);
-
- // 发送响应头
- ctx.write(new DefaultHttp2HeadersFrame(responseHeaders).stream(headersFrame.stream()));
-
- // 发送响应数据
- ctx.writeAndFlush(dataFrame.stream(headersFrame.stream()));
}
- private void handleGrpcData(Http2DataFrame dataFrame,ChannelHandlerContext ctx) throws IOException {
+ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx) throws IOException {
byte[] data = new byte[dataFrame.content().readableBytes()];
- System.out.println(dataFrame.content().readableBytes());
- System.out.println(dataFrame.isEndStream());
dataFrame.content().readBytes(data);
// Decompress if needed
@@ -86,8 +70,11 @@ private void handleGrpcData(Http2DataFrame dataFrame,ChannelHandlerContext ctx)
byteBuf.writeBytes(decompressedData);
if (dataFrame.isEndStream()) {
- int length = byteBuf.readInt();
+
boolean b = byteBuf.readBoolean();
+ int length = byteBuf.readInt();
+ System.out.println(b);
+ System.out.println(length);
byte[] byteArray = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(byteArray);
@@ -99,27 +86,37 @@ private void handleGrpcData(Http2DataFrame dataFrame,ChannelHandlerContext ctx)
System.out.println(decode);
ArthasSampleResponse arthasSampleResponse = new ArthasSampleResponse();
- arthasSampleResponse.setMessage(decode.getName());
+ arthasSampleResponse.setMessage("Hello ArthasSample!");
byte[] responseData = responseCodec.encode(arthasSampleResponse);
- // Send response
- Http2Headers responseHeaders = new DefaultHttp2Headers()
+
+
+ Http2Headers endHeader = new DefaultHttp2Headers()
.status("200")
- .set("content-type", "application/grpc");
- DefaultHttp2HeadersFrame headersFrame = new DefaultHttp2HeadersFrame(responseHeaders);
- ctx.write(headersFrame);
+ .set("content-type", "application/grpc")
+ .set("grpc-encoding", "identity")
+ .set("grpc-accept-encoding", "identity,deflate,gzip");
+ ctx.write(new DefaultHttp2HeadersFrame(endHeader).stream(dataFrame.stream()));
+
ByteBuf buffer = ctx.alloc().buffer();
- buffer.writeInt(responseData.length);
buffer.writeBoolean(false);
+ buffer.writeInt(responseData.length);
buffer.writeBytes(responseData);
System.out.println(responseData.length);
- DefaultHttp2DataFrame stream = new DefaultHttp2DataFrame(buffer, true).stream(dataFrame.stream());
- ctx.writeAndFlush(stream);
+ DefaultHttp2DataFrame resDataFrame = new DefaultHttp2DataFrame(buffer).stream(dataFrame.stream());
+ ctx.write(resDataFrame);
+
+
+ Http2Headers endStream = new DefaultHttp2Headers()
+ .set("grpc-status", "0");
+ DefaultHttp2HeadersFrame endStreamFrame = new DefaultHttp2HeadersFrame(endStream, true).stream(dataFrame.stream());
+ ctx.writeAndFlush(endStreamFrame);
} else {
}
}
+
private static byte[] decompressGzip(byte[] compressedData) throws IOException {
boolean isGzip = (compressedData.length > 2 && (compressedData[0] & 0xff) == 0x1f && (compressedData[1] & 0xff) == 0x8b);
if (isGzip) {
From 5732edd94279552b81ff2103fd39032302ee452d Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Thu, 5 Sep 2024 02:41:02 +0800
Subject: [PATCH 25/48] update: add grpc handler
---
.../com/taobao/arthas/ArthasGrpcServer.java | 2 +-
.../src/main/java/com/taobao/arthas/Main.java | 19 ++-
.../com/taobao/arthas/grpc/GrpcRequest.java | 111 ++++++++++++++++++
.../com/taobao/arthas/grpc/GrpcResponse.java | 12 ++
.../arthas/{h2 => grpc}/Http2Handler.java | 63 +++-------
.../com/taobao/arthas/utils/ByteUtil.java | 29 +++++
6 files changed, 183 insertions(+), 53 deletions(-)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcRequest.java
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcResponse.java
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{h2 => grpc}/Http2Handler.java (62%)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/utils/ByteUtil.java
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/ArthasGrpcServer.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/ArthasGrpcServer.java
index abc7d267b6..91da88ff3d 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/ArthasGrpcServer.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/ArthasGrpcServer.java
@@ -3,7 +3,7 @@
* @date: 2024/7/3 上午12:30
*/
-import com.taobao.arthas.h2.Http2Handler;
+import com.taobao.arthas.grpc.Http2Handler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java
index a17cdb74bc..6885599eac 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java
@@ -8,9 +8,12 @@
import com.taobao.arthas.temp.TempImpl;
import io.grpc.Server;
import io.grpc.ServerBuilder;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
@@ -24,9 +27,19 @@ public class Main {
private static Server server;
public static void main(String[] args) throws Exception {
- Main service = new Main();
- service.start();
- service.blockUntilShutdown();
+// Main service = new Main();
+// service.start();
+// service.blockUntilShutdown();
+
+ ByteBuf buffer = Unpooled.buffer();
+ buffer.writeInt(1);
+ buffer.writeBytes("hello".getBytes(StandardCharsets.UTF_8));
+
+ buffer.readInt();
+ byte[] bytes = new byte[buffer.readableBytes()];
+ buffer.readBytes(bytes);
+
+ System.out.println(new String(bytes, StandardCharsets.UTF_8));
}
public static void start() throws IOException {
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcRequest.java
new file mode 100644
index 0000000000..bce013f62f
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcRequest.java
@@ -0,0 +1,111 @@
+package com.taobao.arthas.grpc;/**
+ * @author: 風楪
+ * @date: 2024/9/4 23:07
+ */
+
+import com.taobao.arthas.utils.ByteUtil;
+import io.netty.buffer.ByteBuf;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/4 23:07
+ * @description: GrpcRequest
+ */
+public class GrpcRequest {
+
+ /**
+ * 请求对应的 streamId
+ */
+ private Integer streamId;
+
+ /**
+ * 请求的方法
+ */
+ private String method;
+
+ /**
+ * 请求的类名(非全限定类名)
+ */
+ private String className;
+
+ /**
+ * protobuf的名称
+ */
+ private String protoName;
+
+ /**
+ * 全限定类名
+ */
+ private String fullyQualifiedClassName;
+
+ /**
+ * 数据
+ */
+ private ByteBuf data;
+
+ int dataLength;
+
+ private static final String fullyQualifiedClassNamePrefix = "com.taobao.arthas.service.";
+
+ public GrpcRequest(Integer streamId, String method, String className, String protoName) {
+ this.streamId = streamId;
+ this.method = method;
+ this.className = className;
+ this.protoName = protoName;
+ this.fullyQualifiedClassName = fullyQualifiedClassNamePrefix + "protoName." + className;
+ this.data = ByteUtil.getByteBuf();
+ }
+
+ public void writeData(ByteBuf byteBuf) {
+ byte[] bytes = ByteUtil.getBytes(byteBuf);
+ if (bytes.length == 0) {
+ return;
+ }
+ byte[] decompressedData = decompressGzip(bytes);
+ if (decompressedData == null) {
+ return;
+ }
+ ByteBuf operateByteBuf = ByteUtil.getByteBuf(decompressedData);
+ boolean compressed = operateByteBuf.readBoolean();
+ int length = operateByteBuf.readInt();
+ dataLength += length;
+ System.out.println(length);
+ System.out.println(operateByteBuf.readableBytes());
+ data.writeBytes(operateByteBuf);
+ }
+
+ public byte[] readData() {
+ System.out.println(dataLength);
+ byte[] res = new byte[dataLength];
+ data.readBytes(res);
+ return res;
+ }
+
+ private byte[] decompressGzip(byte[] compressedData) {
+ boolean isGzip = (compressedData.length > 2 && (compressedData[0] & 0xff) == 0x1f && (compressedData[1] & 0xff) == 0x8b);
+ if (isGzip) {
+ try {
+ InputStream byteStream = new ByteArrayInputStream(compressedData);
+ GZIPInputStream gzipStream = new GZIPInputStream(byteStream);
+ byte[] buffer = new byte[1024];
+ int len;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ while ((len = gzipStream.read(buffer)) != -1) {
+ out.write(buffer, 0, len);
+ }
+ return out.toByteArray();
+ } catch (IOException e) {
+ System.err.println("Failed to decompress GZIP data: " + e.getMessage());
+ }
+ return null;
+ } else {
+ return compressedData;
+ }
+ }
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcResponse.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcResponse.java
new file mode 100644
index 0000000000..f934eacccc
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcResponse.java
@@ -0,0 +1,12 @@
+package com.taobao.arthas.grpc;/**
+ * @author: 風楪
+ * @date: 2024/9/5 02:05
+ */
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/5 02:05
+ * @description: GrpcResponse
+ */
+public class GrpcResponse {
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/Http2Handler.java
similarity index 62%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/Http2Handler.java
index 4f0501c235..0ffc51130d 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/h2/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/Http2Handler.java
@@ -1,4 +1,4 @@
-package com.taobao.arthas.h2;/**
+package com.taobao.arthas.grpc;/**
* @author: 風楪
* @date: 2024/7/7 下午9:58
*/
@@ -8,16 +8,12 @@
import com.taobao.arthas.service.req.ArthasSampleRequest;
import com.taobao.arthas.service.res.ArthasSampleResponse;
import io.netty.buffer.ByteBuf;
-import io.netty.buffer.PooledByteBufAllocator;
-import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http2.*;
import java.io.*;
-import java.nio.charset.StandardCharsets;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.zip.GZIPInputStream;
/**
* @author: FengYe
@@ -29,7 +25,9 @@ public class Http2Handler extends SimpleChannelInboundHandler {
/**
* 暂存收到的所有请求的数据
*/
- private ConcurrentHashMap dataBuffer = new ConcurrentHashMap<>();
+ private ConcurrentHashMap dataBuffer = new ConcurrentHashMap<>();
+
+ private static final String HEADER_PATH = ":path";
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
@@ -38,9 +36,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
@Override
protected void channelRead0(ChannelHandlerContext ctx, Http2Frame frame) throws IOException {
- if (frame instanceof Http2SettingsFrame) {
-
- } else if (frame instanceof Http2HeadersFrame) {
+ if (frame instanceof Http2HeadersFrame) {
handleGrpcRequest((Http2HeadersFrame) frame, ctx);
} else if (frame instanceof Http2DataFrame) {
handleGrpcData((Http2DataFrame) frame, ctx);
@@ -56,32 +52,25 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
private void handleGrpcRequest(Http2HeadersFrame headersFrame, ChannelHandlerContext ctx) {
int id = headersFrame.stream().id();
- dataBuffer.put(id, ctx.alloc().buffer());
+ String path = headersFrame.headers().get(HEADER_PATH).toString();
+ // 去掉前面的斜杠,然后按斜杠分割
+ String[] parts = path.substring(1).split("/");
+ String[] serviceParts = parts[0].split("\\.");
+ dataBuffer.put(id, new GrpcRequest(headersFrame.stream().id(), parts[1], serviceParts[1], serviceParts[0]));
System.out.println("Received headers: " + headersFrame.headers());
}
private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx) throws IOException {
- byte[] data = new byte[dataFrame.content().readableBytes()];
- dataFrame.content().readBytes(data);
-
-// Decompress if needed
- byte[] decompressedData = decompressGzip(data);
- ByteBuf byteBuf = dataBuffer.get(dataFrame.stream().id());
- byteBuf.writeBytes(decompressedData);
+ GrpcRequest grpcRequest = dataBuffer.get(dataFrame.stream().id());
+ grpcRequest.writeData(dataFrame.content());
if (dataFrame.isEndStream()) {
- boolean b = byteBuf.readBoolean();
- int length = byteBuf.readInt();
- System.out.println(b);
- System.out.println(length);
-
- byte[] byteArray = new byte[byteBuf.readableBytes()];
- byteBuf.readBytes(byteArray);
+ byte[] bytes = grpcRequest.readData();
ProtobufCodec requestCodec = ProtobufProxy.create(ArthasSampleRequest.class);
ProtobufCodec responseCodec = ProtobufProxy.create(ArthasSampleResponse.class);
- ArthasSampleRequest decode = requestCodec.decode(byteArray);
+ ArthasSampleRequest decode = requestCodec.decode(bytes);
System.out.println(decode);
@@ -90,7 +79,6 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
byte[] responseData = responseCodec.encode(arthasSampleResponse);
-
Http2Headers endHeader = new DefaultHttp2Headers()
.status("200")
.set("content-type", "application/grpc")
@@ -115,27 +103,4 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
}
}
-
-
- private static byte[] decompressGzip(byte[] compressedData) throws IOException {
- boolean isGzip = (compressedData.length > 2 && (compressedData[0] & 0xff) == 0x1f && (compressedData[1] & 0xff) == 0x8b);
- if (isGzip) {
- try {
- InputStream byteStream = new ByteArrayInputStream(compressedData);
- GZIPInputStream gzipStream = new GZIPInputStream(byteStream);
- byte[] buffer = new byte[1024];
- int len;
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- while ((len = gzipStream.read(buffer)) != -1) {
- out.write(buffer, 0, len);
- }
- return out.toByteArray();
- } catch (IOException e) {
- System.err.println("Failed to decompress GZIP data: " + e.getMessage());
- }
- return null;
- } else {
- return compressedData;
- }
- }
}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/utils/ByteUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/utils/ByteUtil.java
new file mode 100644
index 0000000000..b070c361d0
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/utils/ByteUtil.java
@@ -0,0 +1,29 @@
+package com.taobao.arthas.utils;/**
+ * @author: 風楪
+ * @date: 2024/9/5 00:51
+ */
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.PooledByteBufAllocator;
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/5 00:51
+ * @description: ByteUtil
+ */
+public class ByteUtil {
+
+ public static ByteBuf getByteBuf() {
+ return PooledByteBufAllocator.DEFAULT.buffer();
+ }
+
+ public static ByteBuf getByteBuf(byte[] bytes) {
+ return PooledByteBufAllocator.DEFAULT.buffer(bytes.length).writeBytes(bytes);
+ }
+
+ public static byte[] getBytes(ByteBuf buf) {
+ byte[] bytes = new byte[buf.readableBytes()];
+ buf.readBytes(bytes);
+ return bytes;
+ }
+}
From c8f9310bb635b9636cc2666025d6abab46f33c83 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Fri, 6 Sep 2024 02:36:25 +0800
Subject: [PATCH 26/48] update: add grpc handler
---
.../src/main/java/com/taobao/arthas/Main.java | 55 ----------------
.../com/taobao/arthas/grpc/GrpcResponse.java | 12 ----
.../{ => grpc/server}/ArthasGrpcServer.java | 13 +++-
.../com/taobao/arthas/grpc/server/Main.java | 62 +++++++++++++++++++
.../grpc/server/handler/GrpcDispatcher.java | 52 ++++++++++++++++
.../{ => server/handler}/GrpcRequest.java | 32 +++-------
.../grpc/server/handler/GrpcResponse.java | 42 +++++++++++++
.../{ => server/handler}/Http2Handler.java | 28 +++++----
.../server/handler/annotation/GrpcMethod.java | 20 ++++++
.../handler/annotation/GrpcService.java | 20 ++++++
.../server}/protobuf/ProtobufCodec.java | 2 +-
.../server}/protobuf/ProtobufField.java | 2 +-
.../protobuf/ProtobufFieldTypeEnum.java | 2 +-
.../server}/protobuf/ProtobufProxy.java | 27 ++++----
.../protobuf/annotation/ProtobufClass.java | 2 +-
.../annotation/ProtobufCustomizedField.java | 4 +-
.../annotation/ProtobufEnableZigZap.java | 2 +-
.../protobuf/annotation/ProtobufIgnore.java | 2 +-
.../protobuf/annotation/ProtobufPacked.java | 2 +-
.../utils/CodedOutputStreamCache.java | 2 +-
.../server}/protobuf/utils/EnumHandler.java | 2 +-
.../server}/protobuf/utils/FieldUtil.java | 20 +++---
.../server}/protobuf/utils/MiniTemplator.java | 2 +-
.../protobuf/utils/ProtoBufClassCompiler.java | 5 +-
.../server/service/ArthasSampleService.java | 16 +++++
.../service/impl/ArthasSampleServiceImpl.java | 25 ++++++++
.../service/req/ArthasSampleRequest.java | 14 +----
.../service/res/ArthasSampleResponse.java | 4 +-
.../{ => grpc/server}/temp/TempImpl.java | 2 +-
.../{ => grpc/server}/utils/ByteUtil.java | 2 +-
.../arthas/grpc/server/utils/ReflectUtil.java | 38 ++++++++++++
.../arthas/service/ArthasSampleService.java | 13 ----
.../service/impl/ArthasSampleServiceImpl.java | 21 -------
33 files changed, 350 insertions(+), 197 deletions(-)
delete mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java
delete mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcResponse.java
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/ArthasGrpcServer.java (89%)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/Main.java
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
rename arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/{ => server/handler}/GrpcRequest.java (78%)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
rename arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/{ => server/handler}/Http2Handler.java (83%)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcMethod.java
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcService.java
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/ProtobufCodec.java (89%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/ProtobufField.java (99%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/ProtobufFieldTypeEnum.java (99%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/ProtobufProxy.java (95%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/annotation/ProtobufClass.java (87%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/annotation/ProtobufCustomizedField.java (81%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/annotation/ProtobufEnableZigZap.java (87%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/annotation/ProtobufIgnore.java (87%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/annotation/ProtobufPacked.java (89%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/utils/CodedOutputStreamCache.java (96%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/utils/EnumHandler.java (79%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/utils/FieldUtil.java (98%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/utils/MiniTemplator.java (99%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/protobuf/utils/ProtoBufClassCompiler.java (98%)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/ArthasSampleService.java
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/service/req/ArthasSampleRequest.java (71%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/service/res/ArthasSampleResponse.java (74%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/temp/TempImpl.java (93%)
rename arthas-grpc-server/src/main/java/com/taobao/arthas/{ => grpc/server}/utils/ByteUtil.java (93%)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ReflectUtil.java
delete mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/service/ArthasSampleService.java
delete mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/service/impl/ArthasSampleServiceImpl.java
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java
deleted file mode 100644
index 6885599eac..0000000000
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/Main.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.taobao.arthas;
-
-import arthasSample.ArthasSample;
-import com.taobao.arthas.protobuf.*;
-import com.taobao.arthas.protobuf.utils.MiniTemplator;
-import com.taobao.arthas.service.ArthasSampleService;
-import com.taobao.arthas.service.impl.ArthasSampleServiceImpl;
-import com.taobao.arthas.temp.TempImpl;
-import io.grpc.Server;
-import io.grpc.ServerBuilder;
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Objects;
-
-/**
- * @author: 風楪
- * @date: 2024/6/30 上午1:22
- */
-public class Main {
-
- private static final String TEMPLATE_FILE = "/class_template.tpl";
-
- private static Server server;
-
- public static void main(String[] args) throws Exception {
-// Main service = new Main();
-// service.start();
-// service.blockUntilShutdown();
-
- ByteBuf buffer = Unpooled.buffer();
- buffer.writeInt(1);
- buffer.writeBytes("hello".getBytes(StandardCharsets.UTF_8));
-
- buffer.readInt();
- byte[] bytes = new byte[buffer.readableBytes()];
- buffer.readBytes(bytes);
-
- System.out.println(new String(bytes, StandardCharsets.UTF_8));
- }
-
- public static void start() throws IOException {
- ServerBuilder builder = ServerBuilder.forPort(9090)
- .addService(new TempImpl());
- server = builder.build();
- server.start();
- }
-
- public void blockUntilShutdown() throws InterruptedException {
- server.awaitTermination();
- }
-}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcResponse.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcResponse.java
deleted file mode 100644
index f934eacccc..0000000000
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcResponse.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.taobao.arthas.grpc;/**
- * @author: 風楪
- * @date: 2024/9/5 02:05
- */
-
-/**
- * @author: FengYe
- * @date: 2024/9/5 02:05
- * @description: GrpcResponse
- */
-public class GrpcResponse {
-}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/ArthasGrpcServer.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
similarity index 89%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/ArthasGrpcServer.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
index 91da88ff3d..c94c099f18 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/ArthasGrpcServer.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
@@ -1,9 +1,11 @@
-package com.taobao.arthas;/**
+package com.taobao.arthas.grpc.server;/**
* @author: 風楪
* @date: 2024/7/3 上午12:30
*/
-import com.taobao.arthas.grpc.Http2Handler;
+import com.taobao.arthas.grpc.server.handler.Http2Handler;
+import com.taobao.arthas.grpc.server.handler.annotation.GrpcService;
+import com.taobao.arthas.grpc.server.utils.ReflectUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
@@ -18,8 +20,13 @@
import java.io.File;
import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.URL;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
/**
* @author: FengYe
@@ -27,6 +34,8 @@
* @description: ArthasGrpcServer
*/
public class ArthasGrpcServer {
+
+
public static void main(String[] args) throws Exception {
//自签名生成密钥
SelfSignedCertificate ssc = new SelfSignedCertificate();
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/Main.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/Main.java
new file mode 100644
index 0000000000..8067b02df9
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/Main.java
@@ -0,0 +1,62 @@
+package com.taobao.arthas.grpc.server;
+
+import com.taobao.arthas.grpc.server.temp.TempImpl;
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author: 風楪
+ * @date: 2024/6/30 上午1:22
+ */
+public class Main {
+
+ private static final String TEMPLATE_FILE = "/class_template.tpl";
+
+ private static Server server;
+
+ public static void main(String[] args) throws Exception {
+// Main service = new Main();
+// service.start();
+// service.blockUntilShutdown();
+ findClasses("com.taobao.arthas.grpc.server.service.impl").forEach(System.out::println);
+ }
+
+ private static List> findClasses(String packageName) {
+ List> classes = new ArrayList<>();
+ String path = packageName.replace('.', '/');
+ try {
+ URL resource = Thread.currentThread().getContextClassLoader().getResource(path);
+ if (resource != null) {
+ File directory = new File(resource.toURI());
+ if (directory.exists()) {
+ for (File file : directory.listFiles()) {
+ if (file.isFile() && file.getName().endsWith(".class")) {
+ String className = packageName + '.' + file.getName().replace(".class", "");
+ classes.add(Class.forName(className));
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+
+ }
+ return classes;
+ }
+
+ public static void start() throws IOException {
+ ServerBuilder builder = ServerBuilder.forPort(9090)
+ .addService(new TempImpl());
+ server = builder.build();
+ server.start();
+ }
+
+ public void blockUntilShutdown() throws InterruptedException {
+ server.awaitTermination();
+ }
+}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
new file mode 100644
index 0000000000..562be95027
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
@@ -0,0 +1,52 @@
+package com.taobao.arthas.grpc.server.handler;/**
+ * @author: 風楪
+ * @date: 2024/9/6 01:12
+ */
+
+import com.taobao.arthas.grpc.server.handler.annotation.GrpcService;
+import com.taobao.arthas.grpc.server.utils.ReflectUtil;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/6 01:12
+ * @description: GrpcDelegrate
+ */
+public class GrpcDispatcher {
+
+ private static final String GRPC_SERVICE_PACKAGE_NAME = "com.taobao.arthas.grpc.server.service.impl";
+
+ public static void loadGrpcService(){
+ List> classes = ReflectUtil.findClasses(GRPC_SERVICE_PACKAGE_NAME);
+ for (Class> clazz : classes) {
+ if (clazz.isAnnotationPresent(GrpcService.class)) {
+ try {
+ Object instance = clazz.getDeclaredConstructor().newInstance();
+// Map ;
+ System.out.println("实例化类: " + clazz.getName());
+ // 你可以在这里调用实例的方法或进行其他操作
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public void execute(String serviceName,String methodName, Object[] args){
+// // 创建一个 Lookup 对象
+// MethodHandles.Lookup lookup = MethodHandles.lookup();
+//
+// // 获取方法句柄
+// MethodType methodType = MethodType.methodType(void.class, String.class);
+// MethodHandle methodHandle = lookup.findVirtual(Example.class, "sayHello", methodType);
+//
+// // 调用方法句柄
+// methodHandle.invoke(example, "World"); // 输出: Hello, World
+ }
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
similarity index 78%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcRequest.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
index bce013f62f..edba98ea0a 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/GrpcRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
@@ -1,9 +1,9 @@
-package com.taobao.arthas.grpc;/**
+package com.taobao.arthas.grpc.server.handler;/**
* @author: 風楪
* @date: 2024/9/4 23:07
*/
-import com.taobao.arthas.utils.ByteUtil;
+import com.taobao.arthas.grpc.server.utils.ByteUtil;
import io.netty.buffer.ByteBuf;
import java.io.ByteArrayInputStream;
@@ -25,40 +25,26 @@ public class GrpcRequest {
private Integer streamId;
/**
- * 请求的方法
- */
- private String method;
-
- /**
- * 请求的类名(非全限定类名)
+ * 请求的 path
*/
- private String className;
+ private String path;
/**
- * protobuf的名称
- */
- private String protoName;
-
- /**
- * 全限定类名
+ * 请求的方法
*/
- private String fullyQualifiedClassName;
+ private String method;
/**
* 数据
*/
private ByteBuf data;
- int dataLength;
-
- private static final String fullyQualifiedClassNamePrefix = "com.taobao.arthas.service.";
+ private int dataLength;
- public GrpcRequest(Integer streamId, String method, String className, String protoName) {
+ public GrpcRequest(Integer streamId, String path,String method) {
this.streamId = streamId;
+ this.path = path;
this.method = method;
- this.className = className;
- this.protoName = protoName;
- this.fullyQualifiedClassName = fullyQualifiedClassNamePrefix + "protoName." + className;
this.data = ByteUtil.getByteBuf();
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
new file mode 100644
index 0000000000..59a2214c8f
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
@@ -0,0 +1,42 @@
+package com.taobao.arthas.grpc.server.handler;/**
+ * @author: 風楪
+ * @date: 2024/9/5 02:05
+ */
+
+import io.netty.buffer.ByteBuf;
+import io.netty.handler.codec.http2.DefaultHttp2Headers;
+import io.netty.handler.codec.http2.Http2Headers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/5 02:05
+ * @description: GrpcResponse
+ */
+public class GrpcResponse {
+
+ private Map headers;
+
+ private ByteBuf data;
+
+ private T genericsData;
+
+ {
+ headers = new HashMap<>();
+ headers.put("content-type", "application/grpc");
+ headers.put("grpc-encoding", "identity");
+ headers.put("grpc-accept-encoding", "identity,deflate,gzip");
+ }
+
+ public Http2Headers getEndHeader() {
+ Http2Headers endHeader = new DefaultHttp2Headers().status("200");
+ headers.forEach(endHeader::set);
+ return endHeader;
+ }
+
+ public Http2Headers getEndStreamHeader() {
+ return new DefaultHttp2Headers().set("grpc-status", "0");
+ }
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
similarity index 83%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/Http2Handler.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
index 0ffc51130d..c9f6f94142 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
@@ -1,12 +1,12 @@
-package com.taobao.arthas.grpc;/**
+package com.taobao.arthas.grpc.server.handler;/**
* @author: 風楪
* @date: 2024/7/7 下午9:58
*/
-import com.taobao.arthas.protobuf.ProtobufCodec;
-import com.taobao.arthas.protobuf.ProtobufProxy;
-import com.taobao.arthas.service.req.ArthasSampleRequest;
-import com.taobao.arthas.service.res.ArthasSampleResponse;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
+import com.taobao.arthas.grpc.server.service.req.ArthasSampleRequest;
+import com.taobao.arthas.grpc.server.service.res.ArthasSampleResponse;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
@@ -55,8 +55,7 @@ private void handleGrpcRequest(Http2HeadersFrame headersFrame, ChannelHandlerCon
String path = headersFrame.headers().get(HEADER_PATH).toString();
// 去掉前面的斜杠,然后按斜杠分割
String[] parts = path.substring(1).split("/");
- String[] serviceParts = parts[0].split("\\.");
- dataBuffer.put(id, new GrpcRequest(headersFrame.stream().id(), parts[1], serviceParts[1], serviceParts[0]));
+ dataBuffer.put(id, new GrpcRequest(headersFrame.stream().id(), parts[0], parts[1]));
System.out.println("Received headers: " + headersFrame.headers());
}
@@ -66,6 +65,13 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
if (dataFrame.isEndStream()) {
+
+ try {
+
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
byte[] bytes = grpcRequest.readData();
ProtobufCodec requestCodec = ProtobufProxy.create(ArthasSampleRequest.class);
ProtobufCodec responseCodec = ProtobufProxy.create(ArthasSampleResponse.class);
@@ -80,10 +86,10 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
Http2Headers endHeader = new DefaultHttp2Headers()
- .status("200")
- .set("content-type", "application/grpc")
- .set("grpc-encoding", "identity")
- .set("grpc-accept-encoding", "identity,deflate,gzip");
+ .status("200");
+// .set("content-type", "application/grpc")
+// .set("grpc-encoding", "identity")
+// .set("grpc-accept-encoding", "identity,deflate,gzip");
ctx.write(new DefaultHttp2HeadersFrame(endHeader).stream(dataFrame.stream()));
ByteBuf buffer = ctx.alloc().buffer();
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcMethod.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcMethod.java
new file mode 100644
index 0000000000..ef35716913
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcMethod.java
@@ -0,0 +1,20 @@
+package com.taobao.arthas.grpc.server.handler.annotation;/**
+ * @author: 風楪
+ * @date: 2024/9/6 01:57
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/6 01:57
+ * @description: GrpcMethod
+ */
+@Target({ ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface GrpcMethod {
+ String value() default "";
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcService.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcService.java
new file mode 100644
index 0000000000..c94327a773
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcService.java
@@ -0,0 +1,20 @@
+package com.taobao.arthas.grpc.server.handler.annotation;/**
+ * @author: 風楪
+ * @date: 2024/9/6 01:57
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/6 01:57
+ * @description: GrpcService
+ */
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface GrpcService {
+ String path() default "";
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufCodec.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufCodec.java
similarity index 89%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufCodec.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufCodec.java
index 101b07e86e..0bd6486258 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufCodec.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufCodec.java
@@ -1,4 +1,4 @@
-package com.taobao.arthas.protobuf;/**
+package com.taobao.arthas.grpc.server.protobuf;/**
* @author: 風楪
* @date: 2024/7/17 下午9:44
*/
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufField.java
similarity index 99%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufField.java
index 6203b88d5e..69b1fcb4d9 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufField.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufField.java
@@ -1,4 +1,4 @@
-package com.taobao.arthas.protobuf;/**
+package com.taobao.arthas.grpc.server.protobuf;/**
* @author: 風楪
* @date: 2024/7/25 上午12:14
*/
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufFieldTypeEnum.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufFieldTypeEnum.java
similarity index 99%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufFieldTypeEnum.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufFieldTypeEnum.java
index 2cde8ee9f8..36f3a1d1e7 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufFieldTypeEnum.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufFieldTypeEnum.java
@@ -1,4 +1,4 @@
-package com.taobao.arthas.protobuf;/**
+package com.taobao.arthas.grpc.server.protobuf;/**
* @author: 風楪
* @date: 2024/7/17 下午10:02
*/
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
similarity index 95%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
index 3909ec254b..4a16baa218 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
@@ -1,22 +1,17 @@
-package com.taobao.arthas.protobuf;/**
+package com.taobao.arthas.grpc.server.protobuf;/**
* @author: 風楪
* @date: 2024/7/17 下午9:57
*/
-import com.baidu.bjf.remoting.protobuf.Codec;
-import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
-import com.baidu.bjf.remoting.protobuf.utils.StringUtils;
import com.google.protobuf.WireFormat;
-import com.taobao.arthas.protobuf.annotation.ProtobufEnableZigZap;
-import com.taobao.arthas.protobuf.annotation.ProtobufClass;
-import com.taobao.arthas.protobuf.utils.FieldUtil;
-import com.taobao.arthas.protobuf.utils.MiniTemplator;
-import com.taobao.arthas.protobuf.utils.ProtoBufClassCompiler;
-import com.taobao.arthas.service.req.ArthasSampleRequest;
-
-import java.io.IOException;
-import java.lang.reflect.Field;
+import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufEnableZigZap;
+import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
+import com.taobao.arthas.grpc.server.protobuf.utils.FieldUtil;
+import com.taobao.arthas.grpc.server.protobuf.utils.MiniTemplator;
+import com.taobao.arthas.grpc.server.protobuf.utils.ProtoBufClassCompiler;
+import com.taobao.arthas.grpc.server.service.req.ArthasSampleRequest;
+
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -106,9 +101,9 @@ private static void processImportBlock() {
imports.add("java.util.*");
imports.add("java.io.IOException");
imports.add("java.lang.reflect.*");
- imports.add("com.taobao.arthas.protobuf.*");
- imports.add("com.taobao.arthas.protobuf.utils.*");
- imports.add("com.taobao.arthas.protobuf.annotation.*");
+ imports.add("com.taobao.arthas.grpc.protobuf.*");
+ imports.add("com.taobao.arthas.grpc.protobuf.utils.*");
+ imports.add("com.taobao.arthas.grpc.protobuf.annotation.*");
imports.add("com.google.protobuf.*");
imports.add(clazz.getCanonicalName());
for (String pkg : imports) {
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufClass.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufClass.java
similarity index 87%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufClass.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufClass.java
index 20e50adc99..62482239c7 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufClass.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufClass.java
@@ -1,4 +1,4 @@
-package com.taobao.arthas.protobuf.annotation;/**
+package com.taobao.arthas.grpc.server.protobuf.annotation;/**
* @author: 風楪
* @date: 2024/7/25 上午12:19
*/
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomizedField.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufCustomizedField.java
similarity index 81%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomizedField.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufCustomizedField.java
index ec3124299a..59eea05f4f 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufCustomizedField.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufCustomizedField.java
@@ -1,9 +1,9 @@
-package com.taobao.arthas.protobuf.annotation;/**
+package com.taobao.arthas.grpc.server.protobuf.annotation;/**
* @author: 風楪
* @date: 2024/7/25 上午12:21
*/
-import com.taobao.arthas.protobuf.ProtobufFieldTypeEnum;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufFieldTypeEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufEnableZigZap.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufEnableZigZap.java
similarity index 87%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufEnableZigZap.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufEnableZigZap.java
index c6566dccbd..f92c9cbbe6 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufEnableZigZap.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufEnableZigZap.java
@@ -1,4 +1,4 @@
-package com.taobao.arthas.protobuf.annotation;/**
+package com.taobao.arthas.grpc.server.protobuf.annotation;/**
* @author: 風楪
* @date: 2024/7/28 下午7:27
*/
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufIgnore.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufIgnore.java
similarity index 87%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufIgnore.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufIgnore.java
index 4ea603cf86..fa6b00a2f9 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufIgnore.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufIgnore.java
@@ -1,4 +1,4 @@
-package com.taobao.arthas.protobuf.annotation;/**
+package com.taobao.arthas.grpc.server.protobuf.annotation;/**
* @author: 風楪
* @date: 2024/7/25 上午12:44
*/
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufPacked.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufPacked.java
similarity index 89%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufPacked.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufPacked.java
index 65a7ba270e..1944558a52 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/annotation/ProtobufPacked.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufPacked.java
@@ -1,4 +1,4 @@
-package com.taobao.arthas.protobuf.annotation;/**
+package com.taobao.arthas.grpc.server.protobuf.annotation;/**
* @author: 風楪
* @date: 2024/7/30 上午2:01
*/
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/CodedOutputStreamCache.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/CodedOutputStreamCache.java
similarity index 96%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/CodedOutputStreamCache.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/CodedOutputStreamCache.java
index 756943f602..8c7709b01b 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/CodedOutputStreamCache.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/CodedOutputStreamCache.java
@@ -1,4 +1,4 @@
-package com.taobao.arthas.protobuf.utils;/**
+package com.taobao.arthas.grpc.server.protobuf.utils;/**
* @author: 風楪
* @date: 2024/8/3 下午7:20
*/
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/EnumHandler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/EnumHandler.java
similarity index 79%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/EnumHandler.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/EnumHandler.java
index 90064ad05c..f2f1ab9db2 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/EnumHandler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/EnumHandler.java
@@ -1,4 +1,4 @@
-package com.taobao.arthas.protobuf.utils;/**
+package com.taobao.arthas.grpc.server.protobuf.utils;/**
* @author: 風楪
* @date: 2024/8/6 上午1:19
*/
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/FieldUtil.java
similarity index 98%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/FieldUtil.java
index 309110b31c..93445b5fd2 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/FieldUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/FieldUtil.java
@@ -1,23 +1,19 @@
-package com.taobao.arthas.protobuf.utils;/**
+package com.taobao.arthas.grpc.server.protobuf.utils;/**
* @author: 風楪
* @date: 2024/7/25 上午12:33
*/
-import com.baidu.bjf.remoting.protobuf.EnumReadable;
-import com.baidu.bjf.remoting.protobuf.FieldType;
import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
-import com.baidu.bjf.remoting.protobuf.utils.FieldInfo;
-import com.baidu.bjf.remoting.protobuf.utils.ProtobufProxyUtils;
import com.baidu.bjf.remoting.protobuf.utils.StringUtils;
import com.google.protobuf.*;
-import com.taobao.arthas.protobuf.ProtobufCodec;
-import com.taobao.arthas.protobuf.ProtobufField;
-import com.taobao.arthas.protobuf.ProtobufFieldTypeEnum;
-import com.taobao.arthas.protobuf.ProtobufProxy;
-import com.taobao.arthas.protobuf.annotation.ProtobufPacked;
-import com.taobao.arthas.protobuf.annotation.ProtobufCustomizedField;
-import com.taobao.arthas.protobuf.annotation.ProtobufIgnore;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufField;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufFieldTypeEnum;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
+import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufPacked;
+import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufCustomizedField;
+import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufIgnore;
import java.io.IOException;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/MiniTemplator.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/MiniTemplator.java
similarity index 99%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/MiniTemplator.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/MiniTemplator.java
index 1701d1034d..4fe073fda0 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/MiniTemplator.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/MiniTemplator.java
@@ -10,7 +10,7 @@
// Please contact the author if you need another license.
// This module is provided "as is", without warranties of any kind.
-package com.taobao.arthas.protobuf.utils;;
+package com.taobao.arthas.grpc.server.protobuf.utils;;
import java.io.File;
import java.io.FileInputStream;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/ProtoBufClassCompiler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufClassCompiler.java
similarity index 98%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/ProtoBufClassCompiler.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufClassCompiler.java
index 5f60da3749..80e47576e2 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/protobuf/utils/ProtoBufClassCompiler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufClassCompiler.java
@@ -1,18 +1,15 @@
-package com.taobao.arthas.protobuf.utils;/**
+package com.taobao.arthas.grpc.server.protobuf.utils;/**
* @author: 風楪
* @date: 2024/8/9 01:21
*/
import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
import com.baidu.bjf.remoting.protobuf.utils.compiler.ClassUtils;
-import com.baidu.bjf.remoting.protobuf.utils.compiler.JdkCompiler;
-import com.taobao.arthas.protobuf.ProtobufProxy;
import javax.tools.*;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.AccessController;
import java.security.PrivilegedAction;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/ArthasSampleService.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/ArthasSampleService.java
new file mode 100644
index 0000000000..992ce0b80f
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/ArthasSampleService.java
@@ -0,0 +1,16 @@
+package com.taobao.arthas.grpc.server.service;/**
+ * @author: 風楪
+ * @date: 2024/6/30 下午11:42
+ */
+
+import com.taobao.arthas.grpc.server.service.req.ArthasSampleRequest;
+import com.taobao.arthas.grpc.server.service.res.ArthasSampleResponse;
+
+/**
+ * @author: FengYe
+ * @date: 2024/6/30 下午11:42
+ * @description: ArthasSampleService
+ */
+public interface ArthasSampleService {
+ ArthasSampleResponse trace(ArthasSampleRequest command);
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
new file mode 100644
index 0000000000..0e4317fca6
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
@@ -0,0 +1,25 @@
+package com.taobao.arthas.grpc.server.service.impl;/**
+ * @author: 風楪
+ * @date: 2024/6/30 下午11:43
+ */
+
+import com.taobao.arthas.grpc.server.handler.annotation.GrpcMethod;
+import com.taobao.arthas.grpc.server.handler.annotation.GrpcService;
+import com.taobao.arthas.grpc.server.service.ArthasSampleService;
+import com.taobao.arthas.grpc.server.service.req.ArthasSampleRequest;
+import com.taobao.arthas.grpc.server.service.res.ArthasSampleResponse;
+
+/**
+ * @author: FengYe
+ * @date: 2024/6/30 下午11:43
+ * @description: ArthasSampleServiceImpl
+ */
+@GrpcService(path = "arthasSample.ArthasTempService")
+public class ArthasSampleServiceImpl implements ArthasSampleService {
+
+ @Override
+ @GrpcMethod("trace")
+ public ArthasSampleResponse trace(ArthasSampleRequest command) {
+ return new ArthasSampleResponse();
+ }
+}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasSampleRequest.java
similarity index 71%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasSampleRequest.java
index 159b395dd7..46a0475c4d 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/req/ArthasSampleRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasSampleRequest.java
@@ -1,19 +1,12 @@
-package com.taobao.arthas.service.req;/**
+package com.taobao.arthas.grpc.server.service.req;/**
* @author: 風楪
* @date: 2024/7/14 上午4:28
*/
-import com.baidu.bjf.remoting.protobuf.annotation.Protobuf;
-import com.google.protobuf.*;
-import com.taobao.arthas.protobuf.annotation.ProtobufClass;
-import com.taobao.arthas.protobuf.annotation.ProtobufCustomizedField;
-import com.taobao.arthas.protobuf.annotation.ProtobufIgnore;
+import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
import lombok.ToString;
-import java.io.IOException;
-import java.nio.ByteBuffer;
import java.util.List;
-import java.util.Map;
/**
* @author: FengYe
@@ -21,7 +14,6 @@
* @description: ArthasSampleRequest
*/
-@com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass
@ProtobufClass
@ToString
public class ArthasSampleRequest {
@@ -32,7 +24,6 @@ public class ArthasSampleRequest {
private StatusEnum status;
private List testList;
- @com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass
@ProtobufClass
public enum StatusEnum {
START(1, "开始"),
@@ -47,7 +38,6 @@ public enum StatusEnum {
private String desc;
}
- @com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass
@ProtobufClass
public static class TestClass {
private String name;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/res/ArthasSampleResponse.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/res/ArthasSampleResponse.java
similarity index 74%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/service/res/ArthasSampleResponse.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/res/ArthasSampleResponse.java
index 06a357e010..09ab40f71f 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/res/ArthasSampleResponse.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/res/ArthasSampleResponse.java
@@ -1,9 +1,9 @@
-package com.taobao.arthas.service.res;/**
+package com.taobao.arthas.grpc.server.service.res;/**
* @author: 風楪
* @date: 2024/8/11 22:11
*/
-import com.taobao.arthas.protobuf.annotation.ProtobufClass;
+import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
/**
* @author: FengYe
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/temp/TempImpl.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/temp/TempImpl.java
similarity index 93%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/temp/TempImpl.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/temp/TempImpl.java
index 62df4452ee..481b085368 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/temp/TempImpl.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/temp/TempImpl.java
@@ -1,4 +1,4 @@
-package com.taobao.arthas.temp;/**
+package com.taobao.arthas.grpc.server.temp;/**
* @author: 風楪
* @date: 2024/8/13 01:57
*/
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/utils/ByteUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java
similarity index 93%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/utils/ByteUtil.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java
index b070c361d0..7f04b11128 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/utils/ByteUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java
@@ -1,4 +1,4 @@
-package com.taobao.arthas.utils;/**
+package com.taobao.arthas.grpc.server.utils;/**
* @author: 風楪
* @date: 2024/9/5 00:51
*/
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ReflectUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ReflectUtil.java
new file mode 100644
index 0000000000..5da93c9dfd
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ReflectUtil.java
@@ -0,0 +1,38 @@
+package com.taobao.arthas.grpc.server.utils;/**
+ * @author: 風楪
+ * @date: 2024/9/6 02:20
+ */
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/6 02:20
+ * @description: ReflectUtil
+ */
+public class ReflectUtil {
+ public static List> findClasses(String packageName) {
+ List> classes = new ArrayList<>();
+ String path = packageName.replace('.', '/');
+ try {
+ URL resource = Thread.currentThread().getContextClassLoader().getResource(path);
+ if (resource != null) {
+ File directory = new File(resource.toURI());
+ if (directory.exists()) {
+ for (File file : directory.listFiles()) {
+ if (file.isFile() && file.getName().endsWith(".class")) {
+ String className = packageName + '.' + file.getName().replace(".class", "");
+ classes.add(Class.forName(className));
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+
+ }
+ return classes;
+ }
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/ArthasSampleService.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/ArthasSampleService.java
deleted file mode 100644
index 744258fc17..0000000000
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/ArthasSampleService.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.taobao.arthas.service;/**
- * @author: 風楪
- * @date: 2024/6/30 下午11:42
- */
-
-/**
- * @author: FengYe
- * @date: 2024/6/30 下午11:42
- * @description: ArthasSampleService
- */
-public interface ArthasSampleService {
- String trace(String command);
-}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/impl/ArthasSampleServiceImpl.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/service/impl/ArthasSampleServiceImpl.java
deleted file mode 100644
index 194d8364fe..0000000000
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/service/impl/ArthasSampleServiceImpl.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.taobao.arthas.service.impl;/**
- * @author: 風楪
- * @date: 2024/6/30 下午11:43
- */
-
-import com.taobao.arthas.service.ArthasSampleService;
-import lombok.extern.slf4j.Slf4j;
-
-/**
- * @author: FengYe
- * @date: 2024/6/30 下午11:43
- * @description: ArthasSampleServiceImpl
- */
-@Slf4j
-public class ArthasSampleServiceImpl implements ArthasSampleService {
- @Override
- public String trace(String command) {
- log.info("receive command: {}", command);
- return "receive command: " + command;
- }
-}
\ No newline at end of file
From 526cdd943dd63e5d8825cec03b66c5ce619f6a76 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Tue, 10 Sep 2024 02:26:13 +0800
Subject: [PATCH 27/48] update: add grpc dispatcher
---
.../arthas/grpc/server/ArthasGrpcServer.java | 6 ++-
.../com/taobao/arthas/grpc/server/Main.java | 21 +++++++--
.../grpc/server/handler/GrpcDispatcher.java | 46 +++++++++++++------
.../grpc/server/handler/GrpcRequest.java | 28 +++++++++--
.../grpc/server/handler/Http2Handler.java | 14 +++---
.../handler/annotation/GrpcService.java | 2 +-
.../service/impl/ArthasSampleServiceImpl.java | 2 +-
7 files changed, 87 insertions(+), 32 deletions(-)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
index c94c099f18..91b54455c0 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
@@ -3,6 +3,7 @@
* @date: 2024/7/3 上午12:30
*/
+import com.taobao.arthas.grpc.server.handler.GrpcDispatcher;
import com.taobao.arthas.grpc.server.handler.Http2Handler;
import com.taobao.arthas.grpc.server.handler.annotation.GrpcService;
import com.taobao.arthas.grpc.server.utils.ReflectUtil;
@@ -60,6 +61,9 @@ public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
+ GrpcDispatcher grpcDispatcher = new GrpcDispatcher();
+ grpcDispatcher.loadGrpcService();
+
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
@@ -70,7 +74,7 @@ public static void main(String[] args) throws Exception {
public void initChannel(SocketChannel ch) {
// ch.pipeline().addLast(sslCtx.newHandler(ch.alloc()));
ch.pipeline().addLast(Http2FrameCodecBuilder.forServer().build());
- ch.pipeline().addLast(new Http2Handler());
+ ch.pipeline().addLast(new Http2Handler(grpcDispatcher));
}
});
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/Main.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/Main.java
index 8067b02df9..2c1388884c 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/Main.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/Main.java
@@ -6,6 +6,10 @@
import java.io.File;
import java.io.IOException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
@@ -20,11 +24,14 @@ public class Main {
private static Server server;
- public static void main(String[] args) throws Exception {
-// Main service = new Main();
-// service.start();
-// service.blockUntilShutdown();
- findClasses("com.taobao.arthas.grpc.server.service.impl").forEach(System.out::println);
+ public static void main(String[] args) throws Throwable {
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ Method plus1 = Main.class.getDeclaredMethod("plus", int.class, int.class);
+
+ MethodHandle unreflect = lookup.unreflect(plus1);
+
+ System.out.println(unreflect.invoke(new Main(), 1, 2));
}
private static List> findClasses(String packageName) {
@@ -49,6 +56,10 @@ private static List> findClasses(String packageName) {
return classes;
}
+ public int plus(int a,int b){
+ return a+b;
+ }
+
public static void start() throws IOException {
ServerBuilder builder = ServerBuilder.forPort(9090)
.addService(new TempImpl());
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
index 562be95027..cb12620e69 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
@@ -3,6 +3,7 @@
* @date: 2024/9/6 01:12
*/
+import com.taobao.arthas.grpc.server.handler.annotation.GrpcMethod;
import com.taobao.arthas.grpc.server.handler.annotation.GrpcService;
import com.taobao.arthas.grpc.server.utils.ReflectUtil;
@@ -10,6 +11,7 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -22,15 +24,28 @@ public class GrpcDispatcher {
private static final String GRPC_SERVICE_PACKAGE_NAME = "com.taobao.arthas.grpc.server.service.impl";
- public static void loadGrpcService(){
+ private Map grpcMethodMap = new HashMap<>();
+
+ public void loadGrpcService() {
List> classes = ReflectUtil.findClasses(GRPC_SERVICE_PACKAGE_NAME);
for (Class> clazz : classes) {
if (clazz.isAnnotationPresent(GrpcService.class)) {
try {
+ // 处理 service
+ GrpcService grpcService = clazz.getAnnotation(GrpcService.class);
Object instance = clazz.getDeclaredConstructor().newInstance();
-// Map ;
- System.out.println("实例化类: " + clazz.getName());
- // 你可以在这里调用实例的方法或进行其他操作
+
+ // 处理 method
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ Method[] declaredMethods = clazz.getDeclaredMethods();
+ for (Method method : declaredMethods) {
+ if (method.isAnnotationPresent(GrpcMethod.class)) {
+ GrpcMethod grpcMethod = clazz.getAnnotation(GrpcMethod.class);
+ MethodHandle methodHandle = lookup.unreflect(method);
+ methodHandle.bindTo(instance);
+ grpcMethodMap.put(generateGrpcMethodKey(grpcService.value(),grpcMethod.value()), methodHandle);
+ }
+ }
} catch (Exception e) {
e.printStackTrace();
}
@@ -38,15 +53,18 @@ public static void loadGrpcService(){
}
}
- public void execute(String serviceName,String methodName, Object[] args){
-// // 创建一个 Lookup 对象
-// MethodHandles.Lookup lookup = MethodHandles.lookup();
-//
-// // 获取方法句柄
-// MethodType methodType = MethodType.methodType(void.class, String.class);
-// MethodHandle methodHandle = lookup.findVirtual(Example.class, "sayHello", methodType);
-//
-// // 调用方法句柄
-// methodHandle.invoke(example, "World"); // 输出: Hello, World
+ private String generateGrpcMethodKey(String serviceName, String methodName) {
+ return serviceName + "." + methodName;
+ }
+
+ public Object execute(String serviceName, String methodName, Object... args) throws Throwable {
+ MethodHandle methodHandle = grpcMethodMap.get(generateGrpcMethodKey(serviceName, methodName));
+ return methodHandle.invoke(args);
+ }
+
+ public GrpcResponse execute(GrpcRequest request) throws Throwable {
+ String service = request.getService();
+ String method = request.getMethod();
+
}
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
index edba98ea0a..bb003b5b5b 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
@@ -25,12 +25,12 @@ public class GrpcRequest {
private Integer streamId;
/**
- * 请求的 path
+ * 请求的 service
*/
- private String path;
+ private String service;
/**
- * 请求的方法
+ * 请求的 method
*/
private String method;
@@ -43,7 +43,7 @@ public class GrpcRequest {
public GrpcRequest(Integer streamId, String path,String method) {
this.streamId = streamId;
- this.path = path;
+ this.service = path;
this.method = method;
this.data = ByteUtil.getByteBuf();
}
@@ -94,4 +94,24 @@ private byte[] decompressGzip(byte[] compressedData) {
return compressedData;
}
}
+
+ public Integer getStreamId() {
+ return streamId;
+ }
+
+ public String getService() {
+ return service;
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public ByteBuf getData() {
+ return data;
+ }
+
+ public int getDataLength() {
+ return dataLength;
+ }
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
index c9f6f94142..13f5d0d396 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
@@ -22,6 +22,8 @@
*/
public class Http2Handler extends SimpleChannelInboundHandler {
+ private GrpcDispatcher grpcDispatcher;
+
/**
* 暂存收到的所有请求的数据
*/
@@ -29,6 +31,10 @@ public class Http2Handler extends SimpleChannelInboundHandler {
private static final String HEADER_PATH = ":path";
+ public Http2Handler(GrpcDispatcher grpcDispatcher) {
+ this.grpcDispatcher = grpcDispatcher;
+ }
+
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
super.channelRead(ctx, msg);
@@ -65,12 +71,8 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
if (dataFrame.isEndStream()) {
-
- try {
-
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ //TODO
+// grpcDispatcher.execute()
byte[] bytes = grpcRequest.readData();
ProtobufCodec requestCodec = ProtobufProxy.create(ArthasSampleRequest.class);
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcService.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcService.java
index c94327a773..6d0751d501 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcService.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcService.java
@@ -16,5 +16,5 @@
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface GrpcService {
- String path() default "";
+ String value() default "";
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
index 0e4317fca6..fb72f68a0e 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
@@ -14,7 +14,7 @@
* @date: 2024/6/30 下午11:43
* @description: ArthasSampleServiceImpl
*/
-@GrpcService(path = "arthasSample.ArthasTempService")
+@GrpcService("arthasSample.ArthasTempService")
public class ArthasSampleServiceImpl implements ArthasSampleService {
@Override
From cb669af0445f20e02135127519066e0c605ef581 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Fri, 13 Sep 2024 01:36:04 +0800
Subject: [PATCH 28/48] update: add grpc dispatcher
---
.../grpc/server/handler/GrpcDispatcher.java | 14 ++++++++
.../grpc/server/handler/GrpcRequest.java | 27 ++++++++++----
.../grpc/server/handler/GrpcResponse.java | 36 +++++++++++++++++--
.../arthas/grpc/server/utils/ByteUtil.java | 13 +++++--
4 files changed, 77 insertions(+), 13 deletions(-)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
index cb12620e69..a357983eba 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
@@ -5,6 +5,9 @@
import com.taobao.arthas.grpc.server.handler.annotation.GrpcMethod;
import com.taobao.arthas.grpc.server.handler.annotation.GrpcService;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
+import com.taobao.arthas.grpc.server.utils.ByteUtil;
import com.taobao.arthas.grpc.server.utils.ReflectUtil;
import java.lang.invoke.MethodHandle;
@@ -65,6 +68,17 @@ public Object execute(String serviceName, String methodName, Object... args) thr
public GrpcResponse execute(GrpcRequest request) throws Throwable {
String service = request.getService();
String method = request.getMethod();
+ MethodType type = grpcMethodMap.get(generateGrpcMethodKey(request.getService(), request.getMethod())).type();
+ // protobuf 规范只能有单入参
+ request.setClazz(type.parameterArray()[0]);
+ ProtobufCodec protobufCodec = ProtobufProxy.create(request.getClazz());
+ Object decode = protobufCodec.decode(ByteUtil.getBytes(request.getByteData()));
+ Object execute = this.execute(service, method, decode);
+
+ GrpcResponse grpcResponse = new GrpcResponse();
+ grpcResponse.setClazz(type.returnType());
+ grpcResponse.setByteData(ByteUtil.getByteBuf(protobufCodec.encode(execute)));
+ return grpcResponse;
}
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
index bb003b5b5b..cd6bfa865e 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
@@ -35,9 +35,14 @@ public class GrpcRequest {
private String method;
/**
- * 数据
+ * 二进制数据
*/
- private ByteBuf data;
+ private ByteBuf byteData;
+
+ /**
+ * 请求类型
+ */
+ private Class> clazz;
private int dataLength;
@@ -45,7 +50,7 @@ public GrpcRequest(Integer streamId, String path,String method) {
this.streamId = streamId;
this.service = path;
this.method = method;
- this.data = ByteUtil.getByteBuf();
+ this.byteData = ByteUtil.getByteBuf();
}
public void writeData(ByteBuf byteBuf) {
@@ -63,13 +68,13 @@ public void writeData(ByteBuf byteBuf) {
dataLength += length;
System.out.println(length);
System.out.println(operateByteBuf.readableBytes());
- data.writeBytes(operateByteBuf);
+ byteData.writeBytes(operateByteBuf);
}
public byte[] readData() {
System.out.println(dataLength);
byte[] res = new byte[dataLength];
- data.readBytes(res);
+ byteData.readBytes(res);
return res;
}
@@ -107,11 +112,19 @@ public String getMethod() {
return method;
}
- public ByteBuf getData() {
- return data;
+ public ByteBuf getByteData() {
+ return byteData;
}
public int getDataLength() {
return dataLength;
}
+
+ public Class> getClazz() {
+ return clazz;
+ }
+
+ public void setClazz(Class> clazz) {
+ this.clazz = clazz;
+ }
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
index 59a2214c8f..e2e1cba61a 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
@@ -15,13 +15,19 @@
* @date: 2024/9/5 02:05
* @description: GrpcResponse
*/
-public class GrpcResponse {
+public class GrpcResponse {
private Map headers;
- private ByteBuf data;
+ /**
+ * 二进制数据
+ */
+ private ByteBuf byteData;
- private T genericsData;
+ /**
+ * 响应类型
+ */
+ private Class> clazz;
{
headers = new HashMap<>();
@@ -39,4 +45,28 @@ public Http2Headers getEndHeader() {
public Http2Headers getEndStreamHeader() {
return new DefaultHttp2Headers().set("grpc-status", "0");
}
+
+ public Map getHeaders() {
+ return headers;
+ }
+
+ public ByteBuf getByteData() {
+ return byteData;
+ }
+
+ public Class> getClazz() {
+ return clazz;
+ }
+
+ public void setHeaders(Map headers) {
+ this.headers = headers;
+ }
+
+ public void setByteData(ByteBuf byteData) {
+ this.byteData = byteData;
+ }
+
+ public void setClazz(Class> clazz) {
+ this.clazz = clazz;
+ }
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java
index 7f04b11128..70c3bd7c03 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java
@@ -22,8 +22,15 @@ public static ByteBuf getByteBuf(byte[] bytes) {
}
public static byte[] getBytes(ByteBuf buf) {
- byte[] bytes = new byte[buf.readableBytes()];
- buf.readBytes(bytes);
- return bytes;
+ if (buf.hasArray()) {
+ // 如果 ByteBuf 是一个支持底层数组的实现,直接获取数组
+ return buf.array();
+ } else {
+ // 创建一个新的 byte 数组
+ byte[] bytes = new byte[buf.readableBytes()];
+ // 将 ByteBuf 的内容复制到 byte 数组中
+ buf.getBytes(buf.readerIndex(), bytes);
+ return bytes;
+ }
}
}
From bfee0f1c2238181f52c8b37040b7d7cae48b8fc7 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Sat, 14 Sep 2024 01:37:09 +0800
Subject: [PATCH 29/48] update: complete grpc dispatcher
---
.../grpc/server/handler/GrpcDispatcher.java | 13 ++---
.../grpc/server/handler/GrpcRequest.java | 4 +-
.../grpc/server/handler/GrpcResponse.java | 26 ++++-----
.../grpc/server/handler/Http2Handler.java | 55 ++++++-------------
.../grpc/server/protobuf/ProtobufProxy.java | 17 ++----
.../server/service/ArthasSampleService.java | 1 +
.../service/impl/ArthasSampleServiceImpl.java | 12 +++-
.../arthas/grpc/server/utils/ByteUtil.java | 4 +-
.../src/main/proto/arthasSample.proto | 3 +-
9 files changed, 56 insertions(+), 79 deletions(-)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
index a357983eba..a6b1bcefec 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
@@ -43,10 +43,9 @@ public void loadGrpcService() {
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
if (method.isAnnotationPresent(GrpcMethod.class)) {
- GrpcMethod grpcMethod = clazz.getAnnotation(GrpcMethod.class);
+ GrpcMethod grpcMethod = method.getAnnotation(GrpcMethod.class);
MethodHandle methodHandle = lookup.unreflect(method);
- methodHandle.bindTo(instance);
- grpcMethodMap.put(generateGrpcMethodKey(grpcService.value(),grpcMethod.value()), methodHandle);
+ grpcMethodMap.put(generateGrpcMethodKey(grpcService.value(),grpcMethod.value()), methodHandle.bindTo(instance));
}
}
} catch (Exception e) {
@@ -60,9 +59,9 @@ private String generateGrpcMethodKey(String serviceName, String methodName) {
return serviceName + "." + methodName;
}
- public Object execute(String serviceName, String methodName, Object... args) throws Throwable {
+ public Object execute(String serviceName, String methodName, Object arg) throws Throwable {
MethodHandle methodHandle = grpcMethodMap.get(generateGrpcMethodKey(serviceName, methodName));
- return methodHandle.invoke(args);
+ return methodHandle.invoke(arg);
}
public GrpcResponse execute(GrpcRequest request) throws Throwable {
@@ -71,14 +70,14 @@ public GrpcResponse execute(GrpcRequest request) throws Throwable {
MethodType type = grpcMethodMap.get(generateGrpcMethodKey(request.getService(), request.getMethod())).type();
// protobuf 规范只能有单入参
request.setClazz(type.parameterArray()[0]);
- ProtobufCodec protobufCodec = ProtobufProxy.create(request.getClazz());
+ ProtobufCodec protobufCodec = ProtobufProxy.getCodecCacheSide(request.getClazz());
Object decode = protobufCodec.decode(ByteUtil.getBytes(request.getByteData()));
Object execute = this.execute(service, method, decode);
GrpcResponse grpcResponse = new GrpcResponse();
grpcResponse.setClazz(type.returnType());
- grpcResponse.setByteData(ByteUtil.getByteBuf(protobufCodec.encode(execute)));
+ grpcResponse.writeResponseData(execute);
return grpcResponse;
}
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
index cd6bfa865e..ef4bbdcee9 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
@@ -50,7 +50,7 @@ public GrpcRequest(Integer streamId, String path,String method) {
this.streamId = streamId;
this.service = path;
this.method = method;
- this.byteData = ByteUtil.getByteBuf();
+ this.byteData = ByteUtil.newByteBuf();
}
public void writeData(ByteBuf byteBuf) {
@@ -62,7 +62,7 @@ public void writeData(ByteBuf byteBuf) {
if (decompressedData == null) {
return;
}
- ByteBuf operateByteBuf = ByteUtil.getByteBuf(decompressedData);
+ ByteBuf operateByteBuf = ByteUtil.newByteBuf(decompressedData);
boolean compressed = operateByteBuf.readBoolean();
int length = operateByteBuf.readInt();
dataLength += length;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
index e2e1cba61a..bed596dfa0 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
@@ -3,10 +3,14 @@
* @date: 2024/9/5 02:05
*/
+import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
+import com.taobao.arthas.grpc.server.utils.ByteUtil;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http2.DefaultHttp2Headers;
import io.netty.handler.codec.http2.Http2Headers;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@@ -46,24 +50,18 @@ public Http2Headers getEndStreamHeader() {
return new DefaultHttp2Headers().set("grpc-status", "0");
}
- public Map getHeaders() {
- return headers;
- }
-
- public ByteBuf getByteData() {
+ public ByteBuf getResponseData(){
return byteData;
}
- public Class> getClazz() {
- return clazz;
- }
-
- public void setHeaders(Map headers) {
- this.headers = headers;
- }
+ public void writeResponseData(Object response) throws IOException {
+ ProtobufCodec codec = ProtobufProxy.getCodecCacheSide(clazz);
+ byte[] encode = codec.encode(response);
- public void setByteData(ByteBuf byteData) {
- this.byteData = byteData;
+ this.byteData = ByteUtil.newByteBuf();
+ this.byteData.writeBoolean(false);
+ this.byteData.writeInt(encode.length);
+ this.byteData.writeBytes(encode);
}
public void setClazz(Class> clazz) {
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
index 13f5d0d396..51c976e6cd 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
@@ -70,45 +70,22 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
grpcRequest.writeData(dataFrame.content());
if (dataFrame.isEndStream()) {
-
- //TODO
-// grpcDispatcher.execute()
-
- byte[] bytes = grpcRequest.readData();
- ProtobufCodec requestCodec = ProtobufProxy.create(ArthasSampleRequest.class);
- ProtobufCodec responseCodec = ProtobufProxy.create(ArthasSampleResponse.class);
-
- ArthasSampleRequest decode = requestCodec.decode(bytes);
-
- System.out.println(decode);
-
- ArthasSampleResponse arthasSampleResponse = new ArthasSampleResponse();
- arthasSampleResponse.setMessage("Hello ArthasSample!");
- byte[] responseData = responseCodec.encode(arthasSampleResponse);
-
-
- Http2Headers endHeader = new DefaultHttp2Headers()
- .status("200");
-// .set("content-type", "application/grpc")
-// .set("grpc-encoding", "identity")
-// .set("grpc-accept-encoding", "identity,deflate,gzip");
- ctx.write(new DefaultHttp2HeadersFrame(endHeader).stream(dataFrame.stream()));
-
- ByteBuf buffer = ctx.alloc().buffer();
- buffer.writeBoolean(false);
- buffer.writeInt(responseData.length);
- buffer.writeBytes(responseData);
- System.out.println(responseData.length);
- DefaultHttp2DataFrame resDataFrame = new DefaultHttp2DataFrame(buffer).stream(dataFrame.stream());
- ctx.write(resDataFrame);
-
-
- Http2Headers endStream = new DefaultHttp2Headers()
- .set("grpc-status", "0");
- DefaultHttp2HeadersFrame endStreamFrame = new DefaultHttp2HeadersFrame(endStream, true).stream(dataFrame.stream());
- ctx.writeAndFlush(endStreamFrame);
- } else {
-
+ try {
+ GrpcResponse response = grpcDispatcher.execute(grpcRequest);
+ ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndHeader()).stream(dataFrame.stream()));
+ ctx.writeAndFlush(new DefaultHttp2DataFrame(response.getResponseData()).stream(dataFrame.stream()));
+ ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndStreamHeader(), true).stream(dataFrame.stream()));
+ } catch (Throwable e) {
+ processError(ctx);
+
+ }
}
}
+
+ private void processError(ChannelHandlerContext ctx){
+ // TODO
+// ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndHeader()).stream(dataFrame.stream()));
+// ctx.writeAndFlush(new DefaultHttp2DataFrame(response.getResponseData()).stream(dataFrame.stream()));
+// ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndStreamHeader(), true).stream(dataFrame.stream()));
+ }
}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
index 4a16baa218..181abb0ae7 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
@@ -32,11 +32,7 @@ public class ProtobufProxy {
private static List protobufFields;
- public ProtobufProxy(Class> clazz) {
-
- }
-
- public ProtobufCodec getCodecCacheSide(Class> clazz) {
+ public static ProtobufCodec getCodecCacheSide(Class> clazz) {
ProtobufCodec codec = codecCache.get(clazz.getName());
if (codec != null) {
return codec;
@@ -101,9 +97,9 @@ private static void processImportBlock() {
imports.add("java.util.*");
imports.add("java.io.IOException");
imports.add("java.lang.reflect.*");
- imports.add("com.taobao.arthas.grpc.protobuf.*");
- imports.add("com.taobao.arthas.grpc.protobuf.utils.*");
- imports.add("com.taobao.arthas.grpc.protobuf.annotation.*");
+ imports.add("com.taobao.arthas.grpc.server.protobuf.*");
+ imports.add("com.taobao.arthas.grpc.server.protobuf.utils.*");
+ imports.add("com.taobao.arthas.grpc.server.protobuf.annotation.*");
imports.add("com.google.protobuf.*");
imports.add(clazz.getCanonicalName());
for (String pkg : imports) {
@@ -368,9 +364,4 @@ private static void loadProtobufField() {
clazz.getAnnotation(ProtobufEnableZigZap.class) != null
);
}
-
- public static void main(String[] args) {
- ProtobufCodec protobufCodec = ProtobufProxy.create(ArthasSampleRequest.class);
- }
-
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/ArthasSampleService.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/ArthasSampleService.java
index 992ce0b80f..79c6499f58 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/ArthasSampleService.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/ArthasSampleService.java
@@ -13,4 +13,5 @@
*/
public interface ArthasSampleService {
ArthasSampleResponse trace(ArthasSampleRequest command);
+ ArthasSampleResponse watch(ArthasSampleRequest command);
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
index fb72f68a0e..c0fdce3d73 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
@@ -20,6 +20,16 @@ public class ArthasSampleServiceImpl implements ArthasSampleService {
@Override
@GrpcMethod("trace")
public ArthasSampleResponse trace(ArthasSampleRequest command) {
- return new ArthasSampleResponse();
+ ArthasSampleResponse arthasSampleResponse = new ArthasSampleResponse();
+ arthasSampleResponse.setMessage("trace");
+ return arthasSampleResponse;
+ }
+
+ @Override
+ @GrpcMethod("watch")
+ public ArthasSampleResponse watch(ArthasSampleRequest command) {
+ ArthasSampleResponse arthasSampleResponse = new ArthasSampleResponse();
+ arthasSampleResponse.setMessage("watch");
+ return arthasSampleResponse;
}
}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java
index 70c3bd7c03..29044d36e6 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java
@@ -13,11 +13,11 @@
*/
public class ByteUtil {
- public static ByteBuf getByteBuf() {
+ public static ByteBuf newByteBuf() {
return PooledByteBufAllocator.DEFAULT.buffer();
}
- public static ByteBuf getByteBuf(byte[] bytes) {
+ public static ByteBuf newByteBuf(byte[] bytes) {
return PooledByteBufAllocator.DEFAULT.buffer(bytes.length).writeBytes(bytes);
}
diff --git a/arthas-grpc-server/src/main/proto/arthasSample.proto b/arthas-grpc-server/src/main/proto/arthasSample.proto
index c74da27e31..5e31b25c21 100644
--- a/arthas-grpc-server/src/main/proto/arthasSample.proto
+++ b/arthas-grpc-server/src/main/proto/arthasSample.proto
@@ -9,7 +9,8 @@ enum StatusEnum {
}
service ArthasTempService {
- rpc SayHello(ArthasSampleRequest) returns (ArthasSampleResponse);
+ rpc trace(ArthasSampleRequest) returns (ArthasSampleResponse);
+ rpc watch(ArthasSampleRequest) returns (ArthasSampleResponse);
}
message ArthasSampleRequest {
From 96251c569ac4120f5cd1bb39cacaba668d226963 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Mon, 16 Sep 2024 02:46:27 +0800
Subject: [PATCH 30/48] update: add stream handler
---
.../taobao/arthas/grpc/server/GrpcTest.java | 32 ++++++++
.../com/taobao/arthas/grpc/server/Main.java | 73 -------------------
.../grpc/server/handler/GrpcDispatcher.java | 20 ++++-
.../grpc/server/handler/GrpcRequest.java | 27 ++++---
.../grpc/server/handler/GrpcResponse.java | 2 +-
.../grpc/server/handler/Http2Handler.java | 29 +++++---
.../server/handler/annotation/GrpcMethod.java | 1 +
.../service/impl/ArthasSampleServiceImpl.java | 5 +-
.../arthas/grpc/server/temp/TempImpl.java | 38 ++++++++--
.../src/main/proto/arthasSample.proto | 5 +-
10 files changed, 123 insertions(+), 109 deletions(-)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/GrpcTest.java
delete mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/Main.java
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/GrpcTest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/GrpcTest.java
new file mode 100644
index 0000000000..a32512798f
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/GrpcTest.java
@@ -0,0 +1,32 @@
+package com.taobao.arthas.grpc.server;
+
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+
+import java.io.IOException;
+
+import com.taobao.arthas.grpc.server.temp.TempImpl;
+
+/**
+ * @author: 風楪
+ * @date: 2024/6/30 上午1:22
+ */
+public class GrpcTest {
+
+ private static Server server;
+
+ public static void main(String[] args) throws Throwable {
+ start();
+ blockUntilShutdown();
+ }
+ public static void start() throws IOException {
+ ServerBuilder builder = ServerBuilder.forPort(9090)
+ .addService(new TempImpl());
+ server = builder.build();
+ server.start();
+ }
+
+ public static void blockUntilShutdown() throws InterruptedException {
+ server.awaitTermination();
+ }
+}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/Main.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/Main.java
deleted file mode 100644
index 2c1388884c..0000000000
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/Main.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.taobao.arthas.grpc.server;
-
-import com.taobao.arthas.grpc.server.temp.TempImpl;
-import io.grpc.Server;
-import io.grpc.ServerBuilder;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author: 風楪
- * @date: 2024/6/30 上午1:22
- */
-public class Main {
-
- private static final String TEMPLATE_FILE = "/class_template.tpl";
-
- private static Server server;
-
- public static void main(String[] args) throws Throwable {
- MethodHandles.Lookup lookup = MethodHandles.lookup();
-
- Method plus1 = Main.class.getDeclaredMethod("plus", int.class, int.class);
-
- MethodHandle unreflect = lookup.unreflect(plus1);
-
- System.out.println(unreflect.invoke(new Main(), 1, 2));
- }
-
- private static List> findClasses(String packageName) {
- List> classes = new ArrayList<>();
- String path = packageName.replace('.', '/');
- try {
- URL resource = Thread.currentThread().getContextClassLoader().getResource(path);
- if (resource != null) {
- File directory = new File(resource.toURI());
- if (directory.exists()) {
- for (File file : directory.listFiles()) {
- if (file.isFile() && file.getName().endsWith(".class")) {
- String className = packageName + '.' + file.getName().replace(".class", "");
- classes.add(Class.forName(className));
- }
- }
- }
- }
- } catch (Exception e) {
-
- }
- return classes;
- }
-
- public int plus(int a,int b){
- return a+b;
- }
-
- public static void start() throws IOException {
- ServerBuilder builder = ServerBuilder.forPort(9090)
- .addService(new TempImpl());
- server = builder.build();
- server.start();
- }
-
- public void blockUntilShutdown() throws InterruptedException {
- server.awaitTermination();
- }
-}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
index a6b1bcefec..a7d07d2a6e 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
@@ -17,6 +17,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
/**
* @author: FengYe
@@ -27,7 +28,9 @@ public class GrpcDispatcher {
private static final String GRPC_SERVICE_PACKAGE_NAME = "com.taobao.arthas.grpc.server.service.impl";
- private Map grpcMethodMap = new HashMap<>();
+ private Map grpcMethodInvokeMap = new HashMap<>();
+
+ private Map grpcMethodStreamMap = new HashMap<>();
public void loadGrpcService() {
List> classes = ReflectUtil.findClasses(GRPC_SERVICE_PACKAGE_NAME);
@@ -45,7 +48,9 @@ public void loadGrpcService() {
if (method.isAnnotationPresent(GrpcMethod.class)) {
GrpcMethod grpcMethod = method.getAnnotation(GrpcMethod.class);
MethodHandle methodHandle = lookup.unreflect(method);
- grpcMethodMap.put(generateGrpcMethodKey(grpcService.value(),grpcMethod.value()), methodHandle.bindTo(instance));
+ String grpcMethodKey = generateGrpcMethodKey(grpcService.value(), grpcMethod.value());
+ grpcMethodInvokeMap.put(grpcMethodKey, methodHandle.bindTo(instance));
+ grpcMethodStreamMap.put(grpcMethodKey, grpcMethod.stream());
}
}
} catch (Exception e) {
@@ -60,14 +65,14 @@ private String generateGrpcMethodKey(String serviceName, String methodName) {
}
public Object execute(String serviceName, String methodName, Object arg) throws Throwable {
- MethodHandle methodHandle = grpcMethodMap.get(generateGrpcMethodKey(serviceName, methodName));
+ MethodHandle methodHandle = grpcMethodInvokeMap.get(generateGrpcMethodKey(serviceName, methodName));
return methodHandle.invoke(arg);
}
public GrpcResponse execute(GrpcRequest request) throws Throwable {
String service = request.getService();
String method = request.getMethod();
- MethodType type = grpcMethodMap.get(generateGrpcMethodKey(request.getService(), request.getMethod())).type();
+ MethodType type = grpcMethodInvokeMap.get(generateGrpcMethodKey(request.getService(), request.getMethod())).type();
// protobuf 规范只能有单入参
request.setClazz(type.parameterArray()[0]);
ProtobufCodec protobufCodec = ProtobufProxy.getCodecCacheSide(request.getClazz());
@@ -80,4 +85,11 @@ public GrpcResponse execute(GrpcRequest request) throws Throwable {
grpcResponse.writeResponseData(execute);
return grpcResponse;
}
+
+ public void checkGrpcStream(GrpcRequest request){
+ request.setStream(
+ Optional.ofNullable(grpcMethodStreamMap.get(generateGrpcMethodKey(request.getService(), request.getMethod())))
+ .orElse(false)
+ );
+ }
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
index ef4bbdcee9..9ad04a0c68 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
@@ -40,11 +40,14 @@ public class GrpcRequest {
private ByteBuf byteData;
/**
- * 请求类型
+ * 请求class
*/
private Class> clazz;
- private int dataLength;
+ /**
+ * 是否是 grpc 流式请求
+ */
+ private boolean stream;
public GrpcRequest(Integer streamId, String path,String method) {
this.streamId = streamId;
@@ -63,17 +66,15 @@ public void writeData(ByteBuf byteBuf) {
return;
}
ByteBuf operateByteBuf = ByteUtil.newByteBuf(decompressedData);
+
+ // 必须要先把这5个字节读出来,后续才是真正的data
boolean compressed = operateByteBuf.readBoolean();
int length = operateByteBuf.readInt();
- dataLength += length;
- System.out.println(length);
- System.out.println(operateByteBuf.readableBytes());
byteData.writeBytes(operateByteBuf);
}
public byte[] readData() {
- System.out.println(dataLength);
- byte[] res = new byte[dataLength];
+ byte[] res = new byte[byteData.readableBytes()];
byteData.readBytes(res);
return res;
}
@@ -116,10 +117,6 @@ public ByteBuf getByteData() {
return byteData;
}
- public int getDataLength() {
- return dataLength;
- }
-
public Class> getClazz() {
return clazz;
}
@@ -127,4 +124,12 @@ public Class> getClazz() {
public void setClazz(Class> clazz) {
this.clazz = clazz;
}
+
+ public boolean isStream() {
+ return stream;
+ }
+
+ public void setStream(boolean stream) {
+ this.stream = stream;
+ }
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
index bed596dfa0..bbdaef78df 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
@@ -29,7 +29,7 @@ public class GrpcResponse {
private ByteBuf byteData;
/**
- * 响应类型
+ * 响应class
*/
private Class> clazz;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
index 51c976e6cd..70c9ff52e1 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
@@ -61,7 +61,9 @@ private void handleGrpcRequest(Http2HeadersFrame headersFrame, ChannelHandlerCon
String path = headersFrame.headers().get(HEADER_PATH).toString();
// 去掉前面的斜杠,然后按斜杠分割
String[] parts = path.substring(1).split("/");
- dataBuffer.put(id, new GrpcRequest(headersFrame.stream().id(), parts[0], parts[1]));
+ GrpcRequest grpcRequest = new GrpcRequest(headersFrame.stream().id(), parts[0], parts[1]);
+ grpcDispatcher.checkGrpcStream(grpcRequest);
+ dataBuffer.put(id, grpcRequest);
System.out.println("Received headers: " + headersFrame.headers());
}
@@ -69,17 +71,24 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
GrpcRequest grpcRequest = dataBuffer.get(dataFrame.stream().id());
grpcRequest.writeData(dataFrame.content());
- if (dataFrame.isEndStream()) {
- try {
- GrpcResponse response = grpcDispatcher.execute(grpcRequest);
- ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndHeader()).stream(dataFrame.stream()));
- ctx.writeAndFlush(new DefaultHttp2DataFrame(response.getResponseData()).stream(dataFrame.stream()));
- ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndStreamHeader(), true).stream(dataFrame.stream()));
- } catch (Throwable e) {
- processError(ctx);
-
+ if (grpcRequest.isStream()) {
+ // 流式调用,即刻响应
+ // todo
+ } else {
+ // 非流式调用,等到 endStream 再响应
+ if (dataFrame.isEndStream()) {
+ try {
+ GrpcResponse response = grpcDispatcher.execute(grpcRequest);
+ ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndHeader()).stream(dataFrame.stream()));
+ ctx.writeAndFlush(new DefaultHttp2DataFrame(response.getResponseData()).stream(dataFrame.stream()));
+ ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndStreamHeader(), true).stream(dataFrame.stream()));
+ } catch (Throwable e) {
+ processError(ctx);
+ }
}
}
+
+
}
private void processError(ChannelHandlerContext ctx){
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcMethod.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcMethod.java
index ef35716913..d109fdce59 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcMethod.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcMethod.java
@@ -17,4 +17,5 @@
@Retention(RetentionPolicy.RUNTIME)
public @interface GrpcMethod {
String value() default "";
+ boolean stream() default false;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
index c0fdce3d73..0d88de0501 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
@@ -26,10 +26,11 @@ public ArthasSampleResponse trace(ArthasSampleRequest command) {
}
@Override
- @GrpcMethod("watch")
+ @GrpcMethod(value = "watch", stream = true)
public ArthasSampleResponse watch(ArthasSampleRequest command) {
+ String name = command.getName();
ArthasSampleResponse arthasSampleResponse = new ArthasSampleResponse();
- arthasSampleResponse.setMessage("watch");
+ arthasSampleResponse.setMessage(name);
return arthasSampleResponse;
}
}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/temp/TempImpl.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/temp/TempImpl.java
index 481b085368..2a6247888f 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/temp/TempImpl.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/temp/TempImpl.java
@@ -1,22 +1,50 @@
package com.taobao.arthas.grpc.server.temp;/**
* @author: 風楪
- * @date: 2024/8/13 01:57
+ * @date: 2024/9/16 01:59
*/
+
import arthasSample.ArthasSample;
import arthasSample.ArthasTempServiceGrpc;
import io.grpc.stub.StreamObserver;
/**
* @author: FengYe
- * @date: 2024/8/13 01:57
+ * @date: 2024/9/16 01:59
* @description: TempImpl
*/
public class TempImpl extends ArthasTempServiceGrpc.ArthasTempServiceImplBase {
+
@Override
- public void sayHello(ArthasSample.ArthasSampleRequest request, StreamObserver responseObserver) {
- ArthasSample.ArthasSampleResponse build = ArthasSample.ArthasSampleResponse.newBuilder().setMessage("Hello ArthasSample!").build();
- responseObserver.onNext(build);
+ public void trace(ArthasSample.ArthasSampleRequest request, StreamObserver responseObserver) {
+ ArthasSample.ArthasSampleResponse.Builder builder = ArthasSample.ArthasSampleResponse.newBuilder();
+ builder.setMessage("trace");
+ responseObserver.onNext(builder.build());
responseObserver.onCompleted();
}
+
+ @Override
+ public StreamObserver watch(StreamObserver responseObserver) {
+ return new StreamObserver() {
+ @Override
+ public void onNext(ArthasSample.ArthasSampleRequest value) {
+
+ // 回应客户端
+ ArthasSample.ArthasSampleResponse response = ArthasSample.ArthasSampleResponse.newBuilder()
+ .setMessage(value.getName())
+ .build();
+ responseObserver.onNext(response);
+ }
+
+ @Override
+ public void onError(Throwable t) {
+ System.err.println("Error: " + t);
+ }
+
+ @Override
+ public void onCompleted() {
+ responseObserver.onCompleted();
+ }
+ };
+ }
}
diff --git a/arthas-grpc-server/src/main/proto/arthasSample.proto b/arthas-grpc-server/src/main/proto/arthasSample.proto
index 5e31b25c21..3e14f5eec9 100644
--- a/arthas-grpc-server/src/main/proto/arthasSample.proto
+++ b/arthas-grpc-server/src/main/proto/arthasSample.proto
@@ -10,12 +10,11 @@ enum StatusEnum {
service ArthasTempService {
rpc trace(ArthasSampleRequest) returns (ArthasSampleResponse);
- rpc watch(ArthasSampleRequest) returns (ArthasSampleResponse);
+ rpc watch(stream ArthasSampleRequest) returns (stream ArthasSampleResponse);
}
message ArthasSampleRequest {
- string name = 1;
- double age = 2;
+ string name = 1; double age = 2;
int64 price = 3;
StatusEnum status = 4;
repeated TestClass testList = 5;
From b2c289f083aab1c865488f95d7b6d67140ca9bf2 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Tue, 17 Sep 2024 03:36:58 +0800
Subject: [PATCH 31/48] update: add stream handler
---
arthas-grpc-server/pom.xml | 105 +++++------
.../arthas/grpc/server/ArthasGrpcServer.java | 49 ++---
.../taobao/arthas/grpc/server/GrpcTest.java | 32 ----
.../grpc/server/handler/GrpcDispatcher.java | 3 +-
.../grpc/server/handler/GrpcRequest.java | 25 ++-
.../grpc/server/handler/Http2Handler.java | 36 ++--
.../grpc/server/protobuf/ProtobufProxy.java | 83 +++++----
.../protobuf/utils/ProtoBufClassCompiler.java | 24 +--
.../{FieldUtil.java => ProtoBufUtil.java} | 170 ++++++++++++++++--
.../arthas/grpc/server/temp/TempImpl.java | 50 ------
10 files changed, 314 insertions(+), 263 deletions(-)
delete mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/GrpcTest.java
rename arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/{FieldUtil.java => ProtoBufUtil.java} (87%)
delete mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/temp/TempImpl.java
diff --git a/arthas-grpc-server/pom.xml b/arthas-grpc-server/pom.xml
index 7edcc6739d..7045441714 100644
--- a/arthas-grpc-server/pom.xml
+++ b/arthas-grpc-server/pom.xml
@@ -42,31 +42,12 @@
4.1.111.Final
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- io.grpc
- grpc-netty
-
- io.grpc
- grpc-services
+ com.google.protobuf
+ protobuf-java
+ 4.27.2
-
org.slf4j
@@ -88,43 +69,53 @@
provided
-
- com.baidu
- jprotobuf
- 2.4.20
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
- org.xolstice.maven.plugins
- protobuf-maven-plugin
- 0.6.1
-
- ${basedir}/src/main/proto
- com.google.protobuf:protoc:3.11.0:exe:${os.detected.classifier}
- grpc-java
- io.grpc:protoc-gen-grpc-java:1.28.0:exe:${os.detected.classifier}
-
-
-
-
- compile
- compile-custom
-
-
-
-
-
-
-
- kr.motd.maven
- os-maven-plugin
- 1.4.1.Final
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
index 91b54455c0..07fc1a9718 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
@@ -5,8 +5,6 @@
import com.taobao.arthas.grpc.server.handler.GrpcDispatcher;
import com.taobao.arthas.grpc.server.handler.Http2Handler;
-import com.taobao.arthas.grpc.server.handler.annotation.GrpcService;
-import com.taobao.arthas.grpc.server.utils.ReflectUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
@@ -15,19 +13,10 @@
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http2.Http2FrameCodecBuilder;
-import io.netty.handler.ssl.SslContext;
-import io.netty.handler.ssl.SslContextBuilder;
-import io.netty.handler.ssl.util.SelfSignedCertificate;
-
import java.io.File;
import java.io.IOException;
-import java.lang.reflect.Method;
-import java.net.URL;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
/**
* @author: FengYe
@@ -36,27 +25,25 @@
*/
public class ArthasGrpcServer {
-
public static void main(String[] args) throws Exception {
- //自签名生成密钥
- SelfSignedCertificate ssc = new SelfSignedCertificate();
- SslContext sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
- .build();
-
-
- // 指定生成自签名证书和密钥的位置
- File certFile = new File(System.getProperty("user.dir"),"certificate.crt");
- File keyFile = new File(System.getProperty("user.dir"),"privateKey.key");
-
- // 将生成的证书和私钥移动到指定位置
- moveFile(ssc.certificate(), certFile);
- moveFile(ssc.privateKey(), keyFile);
-
- System.out.println(certFile.getAbsolutePath());
- System.out.println(keyFile.getAbsolutePath());
-
- System.out.println("Certificate: " + ssc.certificate());
- System.out.println("Private Key: " + ssc.privateKey());
+// //自签名生成密钥
+// SelfSignedCertificate ssc = new SelfSignedCertificate();
+// SslContext sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
+// .build();
+//
+// // 指定生成自签名证书和密钥的位置
+// File certFile = new File(System.getProperty("user.dir"),"certificate.crt");
+// File keyFile = new File(System.getProperty("user.dir"),"privateKey.key");
+//
+// // 将生成的证书和私钥移动到指定位置
+// moveFile(ssc.certificate(), certFile);
+// moveFile(ssc.privateKey(), keyFile);
+//
+// System.out.println(certFile.getAbsolutePath());
+// System.out.println(keyFile.getAbsolutePath());
+//
+// System.out.println("Certificate: " + ssc.certificate());
+// System.out.println("Private Key: " + ssc.privateKey());
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/GrpcTest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/GrpcTest.java
deleted file mode 100644
index a32512798f..0000000000
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/GrpcTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.taobao.arthas.grpc.server;
-
-import io.grpc.Server;
-import io.grpc.ServerBuilder;
-
-import java.io.IOException;
-
-import com.taobao.arthas.grpc.server.temp.TempImpl;
-
-/**
- * @author: 風楪
- * @date: 2024/6/30 上午1:22
- */
-public class GrpcTest {
-
- private static Server server;
-
- public static void main(String[] args) throws Throwable {
- start();
- blockUntilShutdown();
- }
- public static void start() throws IOException {
- ServerBuilder builder = ServerBuilder.forPort(9090)
- .addService(new TempImpl());
- server = builder.build();
- server.start();
- }
-
- public static void blockUntilShutdown() throws InterruptedException {
- server.awaitTermination();
- }
-}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
index a7d07d2a6e..38b36fabac 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
@@ -76,7 +76,7 @@ public GrpcResponse execute(GrpcRequest request) throws Throwable {
// protobuf 规范只能有单入参
request.setClazz(type.parameterArray()[0]);
ProtobufCodec protobufCodec = ProtobufProxy.getCodecCacheSide(request.getClazz());
- Object decode = protobufCodec.decode(ByteUtil.getBytes(request.getByteData()));
+ Object decode = protobufCodec.decode(request.readData());
Object execute = this.execute(service, method, decode);
@@ -91,5 +91,6 @@ public void checkGrpcStream(GrpcRequest request){
Optional.ofNullable(grpcMethodStreamMap.get(generateGrpcMethodKey(request.getService(), request.getMethod())))
.orElse(false)
);
+ request.setStreamFirstData(true);
}
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
index 9ad04a0c68..324bcff280 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
@@ -49,6 +49,11 @@ public class GrpcRequest {
*/
private boolean stream;
+ /**
+ * 是否是 grpc 流式请求的第一个data
+ */
+ private boolean streamFirstData;
+
public GrpcRequest(Integer streamId, String path,String method) {
this.streamId = streamId;
this.service = path;
@@ -73,10 +78,16 @@ public void writeData(ByteBuf byteBuf) {
byteData.writeBytes(operateByteBuf);
}
+ /**
+ * 只读取数据而不操作 byteData
+ * @return
+ */
public byte[] readData() {
- byte[] res = new byte[byteData.readableBytes()];
- byteData.readBytes(res);
- return res;
+ return ByteUtil.getBytes(byteData);
+ }
+
+ public void clearData(){
+ byteData.clear();
}
private byte[] decompressGzip(byte[] compressedData) {
@@ -132,4 +143,12 @@ public boolean isStream() {
public void setStream(boolean stream) {
this.stream = stream;
}
+
+ public boolean isStreamFirstData() {
+ return streamFirstData;
+ }
+
+ public void setStreamFirstData(boolean streamFirstData) {
+ this.streamFirstData = streamFirstData;
+ }
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
index 70c9ff52e1..d69bc10cff 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
@@ -3,11 +3,6 @@
* @date: 2024/7/7 下午9:58
*/
-import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
-import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
-import com.taobao.arthas.grpc.server.service.req.ArthasSampleRequest;
-import com.taobao.arthas.grpc.server.service.res.ArthasSampleResponse;
-import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http2.*;
@@ -73,7 +68,24 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
if (grpcRequest.isStream()) {
// 流式调用,即刻响应
- // todo
+ try {
+ GrpcResponse response = grpcDispatcher.execute(grpcRequest);
+ grpcRequest.clearData();
+
+ // 针对第一个响应发送 header
+ if (grpcRequest.isStreamFirstData()) {
+ ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndHeader()).stream(dataFrame.stream()));
+ grpcRequest.setStreamFirstData(false);
+ }
+
+ ctx.writeAndFlush(new DefaultHttp2DataFrame(response.getResponseData()).stream(dataFrame.stream()));
+
+ if (dataFrame.isEndStream()) {
+ ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndStreamHeader(), true).stream(dataFrame.stream()));
+ }
+ } catch (Throwable e) {
+ processError(ctx, e);
+ }
} else {
// 非流式调用,等到 endStream 再响应
if (dataFrame.isEndStream()) {
@@ -83,18 +95,14 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
ctx.writeAndFlush(new DefaultHttp2DataFrame(response.getResponseData()).stream(dataFrame.stream()));
ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndStreamHeader(), true).stream(dataFrame.stream()));
} catch (Throwable e) {
- processError(ctx);
+ processError(ctx, e);
}
}
}
-
-
}
- private void processError(ChannelHandlerContext ctx){
- // TODO
-// ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndHeader()).stream(dataFrame.stream()));
-// ctx.writeAndFlush(new DefaultHttp2DataFrame(response.getResponseData()).stream(dataFrame.stream()));
-// ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndStreamHeader(), true).stream(dataFrame.stream()));
+ private void processError(ChannelHandlerContext ctx, Throwable e) {
+ //todo
+ ctx.writeAndFlush(e.getMessage());
}
}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
index 181abb0ae7..fb0101acb8 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
@@ -7,10 +7,9 @@
import com.google.protobuf.WireFormat;
import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufEnableZigZap;
import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
-import com.taobao.arthas.grpc.server.protobuf.utils.FieldUtil;
+import com.taobao.arthas.grpc.server.protobuf.utils.ProtoBufUtil;
import com.taobao.arthas.grpc.server.protobuf.utils.MiniTemplator;
import com.taobao.arthas.grpc.server.protobuf.utils.ProtoBufClassCompiler;
-import com.taobao.arthas.grpc.server.service.req.ArthasSampleRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
@@ -66,7 +65,7 @@ public static ProtobufCodec create(Class clazz) {
processImportBlock();
- miniTemplator.setVariable("className", FieldUtil.getClassName(clazz) + "$$ProxyClass");
+ miniTemplator.setVariable("className", ProtoBufUtil.getClassName(clazz) + "$$ProxyClass");
miniTemplator.setVariable("codecClassName", ProtobufCodec.class.getName());
miniTemplator.setVariable("targetProxyClassName", clazz.getCanonicalName());
processEncodeBlock();
@@ -75,7 +74,7 @@ public static ProtobufCodec create(Class clazz) {
String code = miniTemplator.generateOutput();
ProtoBufClassCompiler protoBufClassCompiler = new ProtoBufClassCompiler(ProtoBufClassCompiler.class.getClassLoader());
- String fullClassName = FieldUtil.getFullClassName(clazz) + "$$ProxyClass";
+ String fullClassName = ProtoBufUtil.getFullClassName(clazz) + "$$ProxyClass";
Class> newClass = protoBufClassCompiler.compile(fullClassName, code, clazz.getClassLoader());
try {
@@ -110,16 +109,16 @@ private static void processImportBlock() {
private static void processEncodeBlock() {
for (ProtobufField protobufField : protobufFields) {
- String dynamicFieldGetter = FieldUtil.getGetterDynamicString(protobufField, clazz);
+ String dynamicFieldGetter = ProtoBufUtil.getGetterDynamicString(protobufField, clazz);
String dynamicFieldType = protobufField.isList() ? "Collection" : protobufField.getProtobufFieldType().getJavaType();
- String dynamicFieldName = FieldUtil.getDynamicFieldName(protobufField.getOrder());
+ String dynamicFieldName = ProtoBufUtil.getDynamicFieldName(protobufField.getOrder());
miniTemplator.setVariable("dynamicFieldType", dynamicFieldType);
miniTemplator.setVariable("dynamicFieldName", dynamicFieldName);
miniTemplator.setVariable("dynamicFieldGetter", dynamicFieldGetter);
- String sizeDynamicString = FieldUtil.getSizeDynamicString(protobufField);
+ String sizeDynamicString = ProtoBufUtil.getSizeDynamicString(protobufField);
miniTemplator.setVariable("sizeDynamicString", sizeDynamicString);
- miniTemplator.setVariable("encodeWriteFieldValue", FieldUtil.getWriteByteDynamicString(protobufField));
+ miniTemplator.setVariable("encodeWriteFieldValue", ProtoBufUtil.getWriteByteDynamicString(protobufField));
miniTemplator.addBlock("encodeFields");
}
}
@@ -141,7 +140,7 @@ private static void processDecodeBlock() {
express = "new HashMap()";
}
if (isList || isMap) {
- initListMapFields.append(FieldUtil.getInitListMapFieldDynamicString(protobufField, express));
+ initListMapFields.append(ProtoBufUtil.getInitListMapFieldDynamicString(protobufField, express));
}
if (protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.ENUM) {
@@ -149,7 +148,7 @@ private static void processDecodeBlock() {
if (!isList) {
express = "FieldUtil.getEnumValue(" + clsName + ".class, " + clsName + ".values()[0].name())";
// add set get method
- String setToField = FieldUtil.getSetFieldDynamicString(protobufField, clazz, express);
+ String setToField = ProtoBufUtil.getSetFieldDynamicString(protobufField, clazz, express);
miniTemplator.setVariable("enumInitialize", setToField);
miniTemplator.addBlock("enumFields");
}
@@ -163,7 +162,7 @@ private static void processDecodeBlock() {
for (ProtobufField protobufField : protobufFields) {
boolean isList = protobufField.isList();
String t = protobufField.getProtobufFieldType().getType();
- t = FieldUtil.capitalize(t);
+ t = ProtoBufUtil.capitalize(t);
boolean listTypeCheck = false;
String express;
@@ -172,7 +171,7 @@ private static void processDecodeBlock() {
String decodeOrder = "-1";
if (protobufField.getProtobufFieldType() != ProtobufFieldTypeEnum.DEFAULT) {
- decodeOrder = FieldUtil.makeTag(protobufField.getOrder(),
+ decodeOrder = ProtoBufUtil.makeTag(protobufField.getOrder(),
protobufField.getProtobufFieldType().getInternalFieldType().getWireType()) + "";
} else {
decodeOrder = "FieldUtil.makeTag(" + protobufField.getOrder() + ",WireFormat."
@@ -209,12 +208,12 @@ private static void processDecodeBlock() {
checkObjectType(protobufField, cls);
code.append("codec = ProtobufProxy.create(").append(cls.getCanonicalName()).append(".class");
- code.append(")").append(FieldUtil.JAVA_LINE_BREAK);
+ code.append(")").append(ProtoBufUtil.JAVA_LINE_BREAK);
objectDecodeExpress = code.toString();
code.setLength(0);
- objectDecodeExpress += "int length = input.readRawVarint32()" + FieldUtil.JAVA_LINE_BREAK;
- objectDecodeExpress += "final int oldLimit = input.pushLimit(length)" + FieldUtil.JAVA_LINE_BREAK;
+ objectDecodeExpress += "int length = input.readRawVarint32()" + ProtoBufUtil.JAVA_LINE_BREAK;
+ objectDecodeExpress += "final int oldLimit = input.pushLimit(length)" + ProtoBufUtil.JAVA_LINE_BREAK;
listTypeCheck = true;
express = "(" + cls.getCanonicalName() + ") codec.readFrom(input)";
@@ -228,16 +227,16 @@ private static void processDecodeBlock() {
code.append("EnumHandler<").append(enumClassName).append("> keyhandler");
code.append("= new EnumHandler");
code.append("<").append(enumClassName).append(">() {");
- code.append(FieldUtil.LINE_BREAK);
+ code.append(ProtoBufUtil.LINE_BREAK);
code.append("public ").append(enumClassName).append(" handle(int value) {");
- code.append(FieldUtil.LINE_BREAK);
+ code.append(ProtoBufUtil.LINE_BREAK);
code.append("String enumName = FieldUtil.getEnumName(").append(enumClassName)
.append(".values(), value)");
- code.append(FieldUtil.JAVA_LINE_BREAK);
+ code.append(ProtoBufUtil.JAVA_LINE_BREAK);
code.append("return ").append(enumClassName).append(".valueOf(enumName)");
- code.append(FieldUtil.JAVA_LINE_BREAK);
+ code.append(ProtoBufUtil.JAVA_LINE_BREAK);
code.append("}}");
- code.append(FieldUtil.JAVA_LINE_BREAK);
+ code.append(ProtoBufUtil.JAVA_LINE_BREAK);
}
if (protobufField.isEnumValueType()) {
@@ -245,23 +244,23 @@ private static void processDecodeBlock() {
code.append("EnumHandler<").append(enumClassName).append("> handler");
code.append("= new EnumHandler");
code.append("<").append(enumClassName).append(">() {");
- code.append(FieldUtil.LINE_BREAK);
+ code.append(ProtoBufUtil.LINE_BREAK);
code.append("public ").append(enumClassName).append(" handle(int value) {");
- code.append(FieldUtil.LINE_BREAK);
+ code.append(ProtoBufUtil.LINE_BREAK);
code.append("String enumName = FieldUtil.getEnumName(").append(enumClassName)
.append(".values(), value)");
- code.append(FieldUtil.JAVA_LINE_BREAK);
+ code.append(ProtoBufUtil.JAVA_LINE_BREAK);
code.append("return ").append(enumClassName).append(".valueOf(enumName)");
- code.append(FieldUtil.JAVA_LINE_BREAK);
+ code.append(ProtoBufUtil.JAVA_LINE_BREAK);
code.append("}}");
- code.append(FieldUtil.JAVA_LINE_BREAK);
+ code.append(ProtoBufUtil.JAVA_LINE_BREAK);
}
objectDecodeExpress = code.toString();
code.setLength(0);
express = "FieldUtil.putMapValue(input, " + getMapCommand + ",";
- express += FieldUtil.getMapFieldGenericParameterString(protobufField);
+ express += ProtoBufUtil.getMapFieldGenericParameterString(protobufField);
if (protobufField.isEnumKeyType()) {
express += ", keyhandler";
} else {
@@ -286,12 +285,12 @@ private static void processDecodeBlock() {
// class
code.append("codec = ProtobufProxy.create(").append(name).append(".class");
- code.append(")").append(FieldUtil.JAVA_LINE_BREAK);
+ code.append(")").append(ProtoBufUtil.JAVA_LINE_BREAK);
objectDecodeExpress = code.toString();
code.setLength(0);
- objectDecodeExpress += "int length = input.readRawVarint32()" + FieldUtil.JAVA_LINE_BREAK;
- objectDecodeExpress += "final int oldLimit = input.pushLimit(length)" + FieldUtil.JAVA_LINE_BREAK;
+ objectDecodeExpress += "int length = input.readRawVarint32()" + ProtoBufUtil.JAVA_LINE_BREAK;
+ objectDecodeExpress += "final int oldLimit = input.pushLimit(length)" + ProtoBufUtil.JAVA_LINE_BREAK;
listTypeCheck = true;
express = "(" + name + ") codec.readFrom(input)";
@@ -301,11 +300,11 @@ private static void processDecodeBlock() {
express += ".toByteArray()";
}
- String decodeFieldSetValue = FieldUtil.getSetFieldDynamicString(protobufField, clazz, express) + FieldUtil.JAVA_LINE_BREAK;
+ String decodeFieldSetValue = ProtoBufUtil.getSetFieldDynamicString(protobufField, clazz, express) + ProtoBufUtil.JAVA_LINE_BREAK;
if (listTypeCheck) {
- objectDecodeExpressSuffix += "input.checkLastTagWas(0)" + FieldUtil.JAVA_LINE_BREAK;
- objectDecodeExpressSuffix += "input.popLimit(oldLimit)" + FieldUtil.JAVA_LINE_BREAK;
+ objectDecodeExpressSuffix += "input.checkLastTagWas(0)" + ProtoBufUtil.JAVA_LINE_BREAK;
+ objectDecodeExpressSuffix += "input.popLimit(oldLimit)" + ProtoBufUtil.JAVA_LINE_BREAK;
}
String objectPackedDecodeExpress = "";
@@ -314,18 +313,18 @@ private static void processDecodeBlock() {
ProtobufFieldTypeEnum protobufFieldType = protobufField.getProtobufFieldType();
if (protobufFieldType.isPrimitive() || protobufFieldType.isEnum()) {
code.append("if (tag == ")
- .append(FieldUtil.makeTag(protobufField.getOrder(), WireFormat.WIRETYPE_LENGTH_DELIMITED));
- code.append(") {").append(FieldUtil.LINE_BREAK);
+ .append(ProtoBufUtil.makeTag(protobufField.getOrder(), WireFormat.WIRETYPE_LENGTH_DELIMITED));
+ code.append(") {").append(ProtoBufUtil.LINE_BREAK);
- code.append("int length = input.readRawVarint32()").append(FieldUtil.JAVA_LINE_BREAK);
- code.append("int limit = input.pushLimit(length)").append(FieldUtil.JAVA_LINE_BREAK);
+ code.append("int length = input.readRawVarint32()").append(ProtoBufUtil.JAVA_LINE_BREAK);
+ code.append("int limit = input.pushLimit(length)").append(ProtoBufUtil.JAVA_LINE_BREAK);
- code.append(FieldUtil.getSetFieldDynamicString(protobufField, clazz, express));
+ code.append(ProtoBufUtil.getSetFieldDynamicString(protobufField, clazz, express));
- code.append("input.popLimit(limit)").append(FieldUtil.JAVA_LINE_BREAK);
+ code.append("input.popLimit(limit)").append(ProtoBufUtil.JAVA_LINE_BREAK);
- code.append("continue").append(FieldUtil.JAVA_LINE_BREAK);
- code.append("}").append(FieldUtil.LINE_BREAK);
+ code.append("continue").append(ProtoBufUtil.JAVA_LINE_BREAK);
+ code.append("}").append(ProtoBufUtil.LINE_BREAK);
objectPackedDecodeExpress = code.toString();
}
@@ -355,12 +354,12 @@ private static String getMapCommand(ProtobufField protobufField) {
valueGeneric = protobufField.getGenericValueType().getCanonicalName();
String getMapCommand = "(Map<" + keyGeneric;
getMapCommand = getMapCommand + ", " + valueGeneric + ">)";
- getMapCommand = getMapCommand + FieldUtil.getGetterDynamicString(protobufField, clazz);
+ getMapCommand = getMapCommand + ProtoBufUtil.getGetterDynamicString(protobufField, clazz);
return getMapCommand;
}
private static void loadProtobufField() {
- protobufFields = FieldUtil.getProtobufFieldList(clazz,
+ protobufFields = ProtoBufUtil.getProtobufFieldList(clazz,
clazz.getAnnotation(ProtobufEnableZigZap.class) != null
);
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufClassCompiler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufClassCompiler.java
index 80e47576e2..7ca26e4a81 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufClassCompiler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufClassCompiler.java
@@ -1,10 +1,4 @@
-package com.taobao.arthas.grpc.server.protobuf.utils;/**
- * @author: 風楪
- * @date: 2024/8/9 01:21
- */
-
-import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
-import com.baidu.bjf.remoting.protobuf.utils.compiler.ClassUtils;
+package com.taobao.arthas.grpc.server.protobuf.utils;
import javax.tools.*;
import java.io.*;
@@ -70,7 +64,7 @@ public synchronized Class> compile(String className, String code, ClassLoader
throw t;
} catch (Throwable t) {
throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: "
- + className + ", code: \n" + code + "\n, stack: " + ClassUtils.toString(t));
+ + className + ", code: \n" + code + "\n, stack: " + ProtoBufUtil.toString(t));
}
}
}
@@ -82,7 +76,7 @@ public synchronized Class> doCompile(String name, String sourceCode) throws Th
JavaFileObjectImpl javaFileObject = new JavaFileObjectImpl(className, sourceCode);
fileObjects.put(new URI(StandardLocation.SOURCE_PATH.getName() + "/" + packageName + "/" + className + ".java"), javaFileObject);
javaFileManager.putFileForInput(StandardLocation.SOURCE_PATH, packageName,
- className + ClassUtils.JAVA_EXTENSION, javaFileObject);
+ className + ProtoBufUtil.JAVA_EXTENSION, javaFileObject);
DiagnosticCollector diagnosticCollector = new DiagnosticCollector();
Boolean result = compiler.getTask(null, javaFileManager, diagnosticCollector, options, null,
@@ -124,7 +118,7 @@ public void putFileForInput(StandardLocation location, String packageName, Strin
}
private URI uri(Location location, String packageName, String relativeName) {
- return ClassUtils.toURI(location.getName() + '/' + packageName + '/' + relativeName);
+ return ProtoBufUtil.toURI(location.getName() + '/' + packageName + '/' + relativeName);
}
@Override
@@ -209,7 +203,7 @@ protected Class> findClass(final String qualifiedClassName) throws ClassNotFou
return defineClass(qualifiedClassName, bytes, 0, bytes.length);
}
try {
- return ClassHelper.forNameWithCallerClassLoader(qualifiedClassName, getClass());
+ return ProtoBufUtil.forNameWithCallerClassLoader(qualifiedClassName, getClass());
} catch (ClassNotFoundException nf) {
return super.findClass(qualifiedClassName);
}
@@ -227,9 +221,9 @@ protected synchronized Class> loadClass(final String name, final boolean resol
@Override
public InputStream getResourceAsStream(final String name) {
- if (name.endsWith(ClassUtils.CLASS_EXTENSION)) {
+ if (name.endsWith(ProtoBufUtil.CLASS_EXTENSION)) {
String qualifiedClassName =
- name.substring(0, name.length() - ClassUtils.CLASS_EXTENSION.length()).replace('/', '.');
+ name.substring(0, name.length() - ProtoBufUtil.CLASS_EXTENSION.length()).replace('/', '.');
JavaFileObjectImpl file = (JavaFileObjectImpl) classes.get(qualifiedClassName);
if (file != null) {
return new ByteArrayInputStream(file.getByteCode());
@@ -247,12 +241,12 @@ private static final class JavaFileObjectImpl extends SimpleJavaFileObject {
private final CharSequence source;
public JavaFileObjectImpl(final String baseName, final CharSequence source) throws URISyntaxException {
- super(new URI(baseName + ClassUtils.JAVA_EXTENSION), Kind.SOURCE);
+ super(new URI(baseName + ProtoBufUtil.JAVA_EXTENSION), Kind.SOURCE);
this.source = source;
}
JavaFileObjectImpl(final String name, final Kind kind) {
- super(ClassUtils.toURI(name), kind);
+ super(ProtoBufUtil.toURI(name), kind);
source = null;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/FieldUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java
similarity index 87%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/FieldUtil.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java
index 93445b5fd2..73e5cc2b85 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/FieldUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java
@@ -1,11 +1,5 @@
-package com.taobao.arthas.grpc.server.protobuf.utils;/**
- * @author: 風楪
- * @date: 2024/7/25 上午12:33
- */
+package com.taobao.arthas.grpc.server.protobuf.utils;
-
-import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
-import com.baidu.bjf.remoting.protobuf.utils.StringUtils;
import com.google.protobuf.*;
import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
import com.taobao.arthas.grpc.server.protobuf.ProtobufField;
@@ -15,13 +9,17 @@
import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufCustomizedField;
import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufIgnore;
-
import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.lang.Enum;
+import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.*;
/**
@@ -29,13 +27,16 @@
* @date: 2024/7/25 上午12:33
* @description: FieldUtil
*/
-public class FieldUtil {
-
+public class ProtoBufUtil {
public static final Map, ProtobufFieldTypeEnum> TYPE_MAPPER;
public static final Map PRIMITIVE_TYPE_MAPPING;
+ private static final Map> PRIMIIIVE_TYPE_CLASS_MAPPING = new HashMap>(16);
+
+ private static final Map, Class>> PRIMITIVE_WRAPPER_TYPE_MAP = new HashMap, Class>>(8);
+
public static final String DYNAMIC_TARGET = "target";
public static final String PACKAGE_SEPARATOR = ".";
@@ -48,6 +49,14 @@ public class FieldUtil {
public static final String WIREFORMAT_CLSNAME = com.google.protobuf.WireFormat.FieldType.class.getCanonicalName();
+ public static final String ARRAY_SUFFIX = "[]";
+
+ private static final String INTERNAL_ARRAY_PREFIX = "[L";
+
+ public static final String JAVA_EXTENSION = ".java";
+
+ public static final String CLASS_EXTENSION = ".class";
+
static {
PRIMITIVE_TYPE_MAPPING = new HashMap();
@@ -60,6 +69,24 @@ public class FieldUtil {
PRIMITIVE_TYPE_MAPPING.put(float.class.getSimpleName(), Float.class.getSimpleName());
PRIMITIVE_TYPE_MAPPING.put(char.class.getSimpleName(), Character.class.getSimpleName());
PRIMITIVE_TYPE_MAPPING.put(byte.class.getSimpleName(), Byte.class.getSimpleName());
+
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Boolean.class, boolean.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Byte.class, byte.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Character.class, char.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Double.class, double.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Float.class, float.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Integer.class, int.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Long.class, long.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Short.class, short.class);
+
+ Set> primitiveTypeNames = new HashSet>(16);
+ primitiveTypeNames.addAll(PRIMITIVE_WRAPPER_TYPE_MAP.values());
+ primitiveTypeNames.addAll(Arrays.asList(new Class>[] { boolean[].class, byte[].class, char[].class,
+ double[].class, float[].class, int[].class, long[].class, short[].class }));
+ for (Iterator> it = primitiveTypeNames.iterator(); it.hasNext();) {
+ Class> primitiveClass = (Class>) it.next();
+ PRIMIIIVE_TYPE_CLASS_MAPPING.put(primitiveClass.getName(), primitiveClass);
+ }
}
static {
@@ -617,9 +644,9 @@ public static void writeObject(CodedOutputStream out, int order, ProtobufFieldTy
}
} else if (type == ProtobufFieldTypeEnum.STRING) {
if (withTag) {
- out.writeBytes(order, ByteString.copyFromUtf8(String.valueOf(o)));
+ out.writeBytes(order, ByteString.copyFromUtf8(java.lang.String.valueOf(o)));
} else {
- out.writeBytesNoTag(ByteString.copyFromUtf8(String.valueOf(o)));
+ out.writeBytesNoTag(ByteString.copyFromUtf8(java.lang.String.valueOf(o)));
}
} else if (type == ProtobufFieldTypeEnum.UINT32) {
if (withTag) {
@@ -880,7 +907,7 @@ public static int getEnumOrdinal(Enum en) {
}
public static > T getEnumValue(Class enumType, String name) {
- if (StringUtils.isEmpty(name)) {
+ if (isEmpty(name)) {
return null;
}
@@ -982,9 +1009,9 @@ public static int getObjectSize(int order, Object object, ProtobufFieldTypeEnum
}
if (type == ProtobufFieldTypeEnum.STRING) {
- size = CodedOutputStream.computeStringSizeNoTag(String.valueOf(object));
+ size = CodedOutputStream.computeStringSizeNoTag(java.lang.String.valueOf(object));
} else if (type == ProtobufFieldTypeEnum.BOOL) {
- size = CodedOutputStream.computeBoolSizeNoTag(Boolean.valueOf(String.valueOf(object)));
+ size = CodedOutputStream.computeBoolSizeNoTag(Boolean.valueOf(java.lang.String.valueOf(object)));
} else if (type == ProtobufFieldTypeEnum.BYTES) {
byte[] bb = (byte[]) object;
size = CodedOutputStream.computeBytesSizeNoTag(ByteString.copyFrom(bb));
@@ -1044,11 +1071,11 @@ public static String toObjectType(String primitiveType) {
}
public static String getFullClassName(Class> cls) {
- if (StringUtils.isEmpty(getPackage(cls))) {
+ if (isEmpty(getPackage(cls))) {
return getClassName(cls);
}
- return getPackage(cls) + ClassHelper.PACKAGE_SEPARATOR + getClassName(cls);
+ return getPackage(cls) + PACKAGE_SEPARATOR + getClassName(cls);
}
public static String getPackage(Class> cls) {
@@ -1069,13 +1096,120 @@ public static String getPackage(Class> cls) {
public static String getClassName(Class> cls) {
if (cls.isMemberClass()) {
String name = cls.getName();
- name = StringUtils.substringAfterLast(name, PACKAGE_SEPARATOR);
+ name = substringAfterLast(name, PACKAGE_SEPARATOR);
return name;
}
return cls.getSimpleName();
}
+ public static boolean isEmpty(String s){
+ return s == null || s.isEmpty();
+ }
+
+ public static String substringAfterLast(String str, String separator) {
+ if (isEmpty(str)) {
+ return str;
+ } else if (isEmpty(separator)) {
+ return "";
+ } else {
+ int pos = str.lastIndexOf(separator);
+ return pos != -1 && pos != str.length() - separator.length() ? str.substring(pos + separator.length()) : "";
+ }
+ }
+
+ public static Class> forNameWithCallerClassLoader(String name, Class> caller) throws ClassNotFoundException {
+ return forName(name, caller.getClassLoader());
+ }
+
+ public static Class> forName(String name, ClassLoader classLoader) throws ClassNotFoundException, LinkageError {
+
+ Class> clazz = resolvePrimitiveClassName(name);
+ if (clazz != null) {
+ return clazz;
+ }
+
+ // "java.lang.String[]" style arrays
+ if (name.endsWith(ARRAY_SUFFIX)) {
+ String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
+ Class> elementClass = forName(elementClassName, classLoader);
+ return Array.newInstance(elementClass, 0).getClass();
+ }
+
+ // "[Ljava.lang.String;" style arrays
+ int internalArrayMarker = name.indexOf(INTERNAL_ARRAY_PREFIX);
+ if (internalArrayMarker != -1 && name.endsWith(";")) {
+ String elementClassName = null;
+ if (internalArrayMarker == 0) {
+ elementClassName = name.substring(INTERNAL_ARRAY_PREFIX.length(), name.length() - 1);
+ } else if (name.startsWith("[")) {
+ elementClassName = name.substring(1);
+ }
+ Class> elementClass = forName(elementClassName, classLoader);
+ return Array.newInstance(elementClass, 0).getClass();
+ }
+
+ ClassLoader classLoaderToUse = classLoader;
+ if (classLoaderToUse == null) {
+ classLoaderToUse = getClassLoader();
+ }
+ return classLoaderToUse.loadClass(name);
+ }
+
+ public static Class> resolvePrimitiveClassName(String name) {
+ Class> result = null;
+ // Most class names will be quite long, considering that they
+ // SHOULD sit in a package, so a length check is worthwhile.
+ if (name != null && name.length() <= 8) {
+ // Could be a primitive - likely.
+ result = (Class>) PRIMIIIVE_TYPE_CLASS_MAPPING.get(name);
+ }
+ return result;
+ }
+
+ public static ClassLoader getClassLoader() {
+ return getClassLoader(ProtoBufUtil.class);
+ }
+
+ public static ClassLoader getClassLoader(Class> cls) {
+ ClassLoader cl = null;
+ try {
+ cl = Thread.currentThread().getContextClassLoader();
+ } catch (Throwable ex) {
+ // Cannot access thread context ClassLoader - falling back to system
+ // class loader...
+ }
+ if (cl == null) {
+ // No thread context class loader -> use class loader of this class.
+ cl = cls.getClassLoader();
+ }
+ return cl;
+ }
+
+ public static URI toURI(String name) {
+ try {
+ return new URI(name);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static String toString(Throwable e) {
+ StringWriter w = new StringWriter();
+ PrintWriter p = new PrintWriter(w);
+ p.print(e.getClass().getName() + ": ");
+ if (e.getMessage() != null) {
+ p.print(e.getMessage() + "\n");
+ }
+ p.println();
+ try {
+ e.printStackTrace(p);
+ return w.toString();
+ } finally {
+ p.close();
+ }
+ }
+
public static boolean isNull(Object o) {
return o == null;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/temp/TempImpl.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/temp/TempImpl.java
deleted file mode 100644
index 2a6247888f..0000000000
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/temp/TempImpl.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.taobao.arthas.grpc.server.temp;/**
- * @author: 風楪
- * @date: 2024/9/16 01:59
- */
-
-
-import arthasSample.ArthasSample;
-import arthasSample.ArthasTempServiceGrpc;
-import io.grpc.stub.StreamObserver;
-
-/**
- * @author: FengYe
- * @date: 2024/9/16 01:59
- * @description: TempImpl
- */
-public class TempImpl extends ArthasTempServiceGrpc.ArthasTempServiceImplBase {
-
- @Override
- public void trace(ArthasSample.ArthasSampleRequest request, StreamObserver responseObserver) {
- ArthasSample.ArthasSampleResponse.Builder builder = ArthasSample.ArthasSampleResponse.newBuilder();
- builder.setMessage("trace");
- responseObserver.onNext(builder.build());
- responseObserver.onCompleted();
- }
-
- @Override
- public StreamObserver watch(StreamObserver responseObserver) {
- return new StreamObserver() {
- @Override
- public void onNext(ArthasSample.ArthasSampleRequest value) {
-
- // 回应客户端
- ArthasSample.ArthasSampleResponse response = ArthasSample.ArthasSampleResponse.newBuilder()
- .setMessage(value.getName())
- .build();
- responseObserver.onNext(response);
- }
-
- @Override
- public void onError(Throwable t) {
- System.err.println("Error: " + t);
- }
-
- @Override
- public void onCompleted() {
- responseObserver.onCompleted();
- }
- };
- }
-}
From a3426b7220ba504bb4bcb4c15f07d5b0b0c28eb9 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Thu, 19 Sep 2024 00:05:52 +0800
Subject: [PATCH 32/48] update: Optimize the situation where multiple grpc
bodies exist in the same http2frame
---
.../grpc/server/handler/GrpcDispatcher.java | 32 +++++++----
.../grpc/server/handler/GrpcRequest.java | 57 +++++++++++++++----
.../server/handler/Http2FrameRequest.java | 19 +++++++
.../grpc/server/handler/Http2Handler.java | 25 +++++---
.../grpc/server/protobuf/ProtobufProxy.java | 12 ++--
.../server/protobuf/utils/ProtoBufUtil.java | 20 +++----
.../src/main/resources/class_template.tpl | 4 +-
7 files changed, 121 insertions(+), 48 deletions(-)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2FrameRequest.java
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
index 38b36fabac..36d5441cda 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
@@ -64,29 +64,39 @@ private String generateGrpcMethodKey(String serviceName, String methodName) {
return serviceName + "." + methodName;
}
- public Object execute(String serviceName, String methodName, Object arg) throws Throwable {
+ public GrpcResponse execute(String serviceName, String methodName, Object arg) throws Throwable {
MethodHandle methodHandle = grpcMethodInvokeMap.get(generateGrpcMethodKey(serviceName, methodName));
- return methodHandle.invoke(arg);
+ MethodType type = grpcMethodInvokeMap.get(generateGrpcMethodKey(serviceName, methodName)).type();
+ Object execute = methodHandle.invoke(arg);
+ GrpcResponse grpcResponse = new GrpcResponse();
+ grpcResponse.setClazz(type.returnType());
+ grpcResponse.writeResponseData(execute);
+ return grpcResponse;
}
public GrpcResponse execute(GrpcRequest request) throws Throwable {
String service = request.getService();
String method = request.getMethod();
- MethodType type = grpcMethodInvokeMap.get(generateGrpcMethodKey(request.getService(), request.getMethod())).type();
// protobuf 规范只能有单入参
- request.setClazz(type.parameterArray()[0]);
+ request.setClazz(getRequestClass(request.getService(), request.getMethod()));
ProtobufCodec protobufCodec = ProtobufProxy.getCodecCacheSide(request.getClazz());
Object decode = protobufCodec.decode(request.readData());
+ return this.execute(service, method, decode);
+ }
- Object execute = this.execute(service, method, decode);
-
- GrpcResponse grpcResponse = new GrpcResponse();
- grpcResponse.setClazz(type.returnType());
- grpcResponse.writeResponseData(execute);
- return grpcResponse;
+ /**
+ * 获取指定 service method 对应的入参类型
+ *
+ * @param serviceName
+ * @param methodName
+ * @return
+ */
+ public Class> getRequestClass(String serviceName, String methodName) {
+ //protobuf 规范只能有单入参
+ return grpcMethodInvokeMap.get(generateGrpcMethodKey(serviceName, methodName)).type().parameterArray()[0];
}
- public void checkGrpcStream(GrpcRequest request){
+ public void checkGrpcStream(GrpcRequest request) {
request.setStream(
Optional.ofNullable(grpcMethodStreamMap.get(generateGrpcMethodKey(request.getService(), request.getMethod())))
.orElse(false)
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
index 324bcff280..7a0498bf13 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
@@ -15,7 +15,7 @@
/**
* @author: FengYe
* @date: 2024/9/4 23:07
- * @description: GrpcRequest
+ * @description: GrpcRequest grpc 请求体
*/
public class GrpcRequest {
@@ -35,10 +35,15 @@ public class GrpcRequest {
private String method;
/**
- * 二进制数据
+ * 二进制数据,可能包含多个 grpc body,每个 body 都带有 5 个 byte 的前缀,分别是 boolean compressed - int length
*/
private ByteBuf byteData;
+ /**
+ * 二进制数据的长度
+ */
+ private int length;
+
/**
* 请求class
*/
@@ -54,7 +59,8 @@ public class GrpcRequest {
*/
private boolean streamFirstData;
- public GrpcRequest(Integer streamId, String path,String method) {
+
+ public GrpcRequest(Integer streamId, String path, String method) {
this.streamId = streamId;
this.service = path;
this.method = method;
@@ -70,26 +76,30 @@ public void writeData(ByteBuf byteBuf) {
if (decompressedData == null) {
return;
}
- ByteBuf operateByteBuf = ByteUtil.newByteBuf(decompressedData);
-
- // 必须要先把这5个字节读出来,后续才是真正的data
- boolean compressed = operateByteBuf.readBoolean();
- int length = operateByteBuf.readInt();
- byteData.writeBytes(operateByteBuf);
+ byteData.writeBytes(ByteUtil.newByteBuf(decompressedData));
}
/**
- * 只读取数据而不操作 byteData
+ * 读取部分数据
+ *
* @return
*/
public byte[] readData() {
- return ByteUtil.getBytes(byteData);
+ if (byteData.readableBytes() == 0) {
+ return null;
+ }
+ boolean compressed = byteData.readBoolean();
+ int length = byteData.readInt();
+ byte[] bytes = new byte[length];
+ byteData.readBytes(bytes);
+ return bytes;
}
- public void clearData(){
+ public void clearData() {
byteData.clear();
}
+ // todo 后续优化gzip处理
private byte[] decompressGzip(byte[] compressedData) {
boolean isGzip = (compressedData.length > 2 && (compressedData[0] & 0xff) == 0x1f && (compressedData[1] & 0xff) == 0x8b);
if (isGzip) {
@@ -112,6 +122,29 @@ private byte[] decompressGzip(byte[] compressedData) {
}
}
+ private ByteBuf decompressGzip(ByteBuf byteBuf) {
+ byte[] compressedData = ByteUtil.getBytes(byteBuf);
+ boolean isGzip = (compressedData.length > 2 && (compressedData[0] & 0xff) == 0x1f && (compressedData[1] & 0xff) == 0x8b);
+ if (isGzip) {
+ try {
+ InputStream byteStream = new ByteArrayInputStream(compressedData);
+ GZIPInputStream gzipStream = new GZIPInputStream(byteStream);
+ byte[] buffer = new byte[1024];
+ int len;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ while ((len = gzipStream.read(buffer)) != -1) {
+ out.write(buffer, 0, len);
+ }
+ return ByteUtil.newByteBuf(out.toByteArray());
+ } catch (IOException e) {
+ System.err.println("Failed to decompress GZIP data: " + e.getMessage());
+ }
+ return null;
+ } else {
+ return byteBuf;
+ }
+ }
+
public Integer getStreamId() {
return streamId;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2FrameRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2FrameRequest.java
new file mode 100644
index 0000000000..49091da077
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2FrameRequest.java
@@ -0,0 +1,19 @@
+package com.taobao.arthas.grpc.server.handler;/**
+ * @author: 風楪
+ * @date: 2024/9/18 23:12
+ */
+
+import java.util.List;
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/18 23:12
+ * @description: 一个 http2 的 frame 中可能存在多个 grpc 的请求体
+ */
+public class Http2FrameRequest {
+
+ /**
+ * grpc 请求体
+ */
+ private List grpcRequests;
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
index d69bc10cff..dbd700f118 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
@@ -3,6 +3,8 @@
* @date: 2024/7/7 下午9:58
*/
+import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http2.*;
@@ -66,19 +68,28 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
GrpcRequest grpcRequest = dataBuffer.get(dataFrame.stream().id());
grpcRequest.writeData(dataFrame.content());
+ System.out.println(dataFrame.stream().id());
if (grpcRequest.isStream()) {
// 流式调用,即刻响应
try {
- GrpcResponse response = grpcDispatcher.execute(grpcRequest);
- grpcRequest.clearData();
+ GrpcResponse response = new GrpcResponse();
+ byte[] bytes = grpcRequest.readData();
+ while (bytes != null) {
+ ProtobufCodec protobufCodec = ProtobufProxy.getCodecCacheSide(grpcDispatcher.getRequestClass(grpcRequest.getService(),grpcRequest.getMethod()));
+ Object decode = protobufCodec.decode(bytes);
+ response = grpcDispatcher.execute(grpcRequest.getService(), grpcRequest.getMethod(), decode);
+
+ // 针对第一个响应发送 header
+ if (grpcRequest.isStreamFirstData()) {
+ ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndHeader()).stream(dataFrame.stream()));
+ grpcRequest.setStreamFirstData(false);
+ }
+ ctx.writeAndFlush(new DefaultHttp2DataFrame(response.getResponseData()).stream(dataFrame.stream()));
- // 针对第一个响应发送 header
- if (grpcRequest.isStreamFirstData()) {
- ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndHeader()).stream(dataFrame.stream()));
- grpcRequest.setStreamFirstData(false);
+ bytes = grpcRequest.readData();
}
- ctx.writeAndFlush(new DefaultHttp2DataFrame(response.getResponseData()).stream(dataFrame.stream()));
+ grpcRequest.clearData();
if (dataFrame.isEndStream()) {
ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndStreamHeader(), true).stream(dataFrame.stream()));
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
index fb0101acb8..389be4c24e 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
@@ -146,7 +146,7 @@ private static void processDecodeBlock() {
if (protobufField.getProtobufFieldType() == ProtobufFieldTypeEnum.ENUM) {
String clsName = protobufField.getJavaField().getType().getCanonicalName();
if (!isList) {
- express = "FieldUtil.getEnumValue(" + clsName + ".class, " + clsName + ".values()[0].name())";
+ express = "ProtoBufUtil.getEnumValue(" + clsName + ".class, " + clsName + ".values()[0].name())";
// add set get method
String setToField = ProtoBufUtil.getSetFieldDynamicString(protobufField, clazz, express);
miniTemplator.setVariable("enumInitialize", setToField);
@@ -174,7 +174,7 @@ private static void processDecodeBlock() {
decodeOrder = ProtoBufUtil.makeTag(protobufField.getOrder(),
protobufField.getProtobufFieldType().getInternalFieldType().getWireType()) + "";
} else {
- decodeOrder = "FieldUtil.makeTag(" + protobufField.getOrder() + ",WireFormat."
+ decodeOrder = "ProtoBufUtil.makeTag(" + protobufField.getOrder() + ",WireFormat."
+ protobufField.getProtobufFieldType().getWireFormat() + ")";
}
miniTemplator.setVariable("decodeOrder", decodeOrder);
@@ -188,7 +188,7 @@ private static void processDecodeBlock() {
clsName = cls.getCanonicalName();
}
}
- express = "FieldUtil.getEnumValue(" + clsName + ".class, FieldUtil.getEnumName(" + clsName
+ express = "ProtoBufUtil.getEnumValue(" + clsName + ".class, ProtoBufUtil.getEnumName(" + clsName
+ ".values()," + "input.read" + t + "()))";
} else {
// here is the trick way to process BigDecimal and BigInteger
@@ -230,7 +230,7 @@ private static void processDecodeBlock() {
code.append(ProtoBufUtil.LINE_BREAK);
code.append("public ").append(enumClassName).append(" handle(int value) {");
code.append(ProtoBufUtil.LINE_BREAK);
- code.append("String enumName = FieldUtil.getEnumName(").append(enumClassName)
+ code.append("String enumName = ProtoBufUtil.getEnumName(").append(enumClassName)
.append(".values(), value)");
code.append(ProtoBufUtil.JAVA_LINE_BREAK);
code.append("return ").append(enumClassName).append(".valueOf(enumName)");
@@ -247,7 +247,7 @@ private static void processDecodeBlock() {
code.append(ProtoBufUtil.LINE_BREAK);
code.append("public ").append(enumClassName).append(" handle(int value) {");
code.append(ProtoBufUtil.LINE_BREAK);
- code.append("String enumName = FieldUtil.getEnumName(").append(enumClassName)
+ code.append("String enumName = ProtoBufUtil.getEnumName(").append(enumClassName)
.append(".values(), value)");
code.append(ProtoBufUtil.JAVA_LINE_BREAK);
code.append("return ").append(enumClassName).append(".valueOf(enumName)");
@@ -259,7 +259,7 @@ private static void processDecodeBlock() {
objectDecodeExpress = code.toString();
code.setLength(0);
- express = "FieldUtil.putMapValue(input, " + getMapCommand + ",";
+ express = "ProtoBufUtil.putMapValue(input, " + getMapCommand + ",";
express += ProtoBufUtil.getMapFieldGenericParameterString(protobufField);
if (protobufField.isEnumKeyType()) {
express += ", keyhandler";
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java
index 73e5cc2b85..221966832f 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java
@@ -25,7 +25,7 @@
/**
* @author: FengYe
* @date: 2024/7/25 上午12:33
- * @description: FieldUtil
+ * @description: ProtoBufUtil
*/
public class ProtoBufUtil {
@@ -385,7 +385,7 @@ public static String getGetterDynamicString(ProtobufField protobufField, Class
}
String code = "(" + toObjectType(type) + ") ";
- code += "FieldUtil.getField(" + DYNAMIC_TARGET + ", \"" + field.getName() + "\")";
+ code += "ProtoBufUtil.getField(" + DYNAMIC_TARGET + ", \"" + field.getName() + "\")";
return code;
}
@@ -406,14 +406,14 @@ public static String getSizeDynamicString(ProtobufField field) {
if (isList) {
- return "FieldUtil.getListSize(" + order + "," + dynamicFieldName + "," + ProtobufFieldTypeEnum.class.getName() + "." + typeName
+ return "ProtoBufUtil.getListSize(" + order + "," + dynamicFieldName + "," + ProtobufFieldTypeEnum.class.getName() + "." + typeName
+ "," + field.isPacked() + ");" + LINE_BREAK;
} else if (isMap) {
- return "FieldUtil.getMapSize(" + order + "," + dynamicFieldName + "," + getMapFieldGenericParameterString(field) + ");" + LINE_BREAK;
+ return "ProtoBufUtil.getMapSize(" + order + "," + dynamicFieldName + "," + getMapFieldGenericParameterString(field) + ");" + LINE_BREAK;
}
if (protobufFieldType == ProtobufFieldTypeEnum.OBJECT) {
- return "FieldUtil.getObjectSize(" + order + "," + dynamicFieldName + ", " + ProtobufFieldTypeEnum.class.getName() + "."
+ return "ProtoBufUtil.getObjectSize(" + order + "," + dynamicFieldName + ", " + ProtobufFieldTypeEnum.class.getName() + "."
+ typeName + ");" + LINE_BREAK;
}
@@ -447,7 +447,7 @@ public static String getWriteByteDynamicString(ProtobufField protobufField) {
if (protobufField.isList()) {
String typeString = protobufFieldType.getType().toUpperCase();
- sb.append("FieldUtil.writeList(").append(CODE_OUTPUT_STREAM_OBJ_NAME).append(",");
+ sb.append("ProtoBufUtil.writeList(").append(CODE_OUTPUT_STREAM_OBJ_NAME).append(",");
sb.append(order).append(",").append(ProtobufFieldTypeEnum.class.getName()).append(".").append(typeString);
sb.append(",").append(dynamicFieldName).append(",").append(Boolean.valueOf(protobufField.isPacked())).append(")")
.append(JAVA_LINE_BREAK).append("}").append(LINE_BREAK);
@@ -865,7 +865,7 @@ public static String getSetFieldDynamicString(ProtobufField protobufField, Class
if (isList) {
sb.append(collectionType).append(" __list = ").append(collectionTypetoCreate)
.append(JAVA_LINE_BREAK);
- sb.append("FieldUtil.setField(").append(DYNAMIC_TARGET).append(", \"").append(javaField.getName())
+ sb.append("ProtoBufUtil.setField(").append(DYNAMIC_TARGET).append(", \"").append(javaField.getName())
.append("\", __list)").append(JAVA_LINE_BREAK).append("}").append(LINE_BREAK);
if (express != null) {
if (isPacked) {
@@ -880,7 +880,7 @@ public static String getSetFieldDynamicString(ProtobufField protobufField, Class
return sb.toString();
} else if (isMap) {
sb.append("Map __map = new HashMap()").append(JAVA_LINE_BREAK);
- sb.append("FieldUtil.setField(").append(DYNAMIC_TARGET).append(", \"").append(javaField.getName())
+ sb.append("ProtoBufUtil.setField(").append(DYNAMIC_TARGET).append(", \"").append(javaField.getName())
.append("\", __map)").append(JAVA_LINE_BREAK).append("}").append(LINE_BREAK);
return sb + express;
}
@@ -893,7 +893,7 @@ public static String getSetFieldDynamicString(ProtobufField protobufField, Class
express = "new Date(" + express + ")";
}
- code = "FieldUtil.setField(" + DYNAMIC_TARGET + ", \"" + javaField.getName() + "\", " + express + ")"
+ code = "ProtoBufUtil.setField(" + DYNAMIC_TARGET + ", \"" + javaField.getName() + "\", " + express + ")"
+ LINE_BREAK;
}
return code;
@@ -939,7 +939,7 @@ public static String getEnumName(Enum[] e, int value) {
* @return
*/
public static String getInitListMapFieldDynamicString(ProtobufField protobufField, String express) {
- return "FieldUtil.setField(" + DYNAMIC_TARGET + ", \"" + protobufField.getJavaField().getName() + "\", " + express + ");"
+ return "ProtoBufUtil.setField(" + DYNAMIC_TARGET + ", \"" + protobufField.getJavaField().getName() + "\", " + express + ");"
+ LINE_BREAK;
}
diff --git a/arthas-grpc-server/src/main/resources/class_template.tpl b/arthas-grpc-server/src/main/resources/class_template.tpl
index a2ff4bc984..89d6e1dd2b 100644
--- a/arthas-grpc-server/src/main/resources/class_template.tpl
+++ b/arthas-grpc-server/src/main/resources/class_template.tpl
@@ -18,7 +18,7 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
throws IOException {
${dynamicFieldType} ${dynamicFieldName} = null;
- if (!FieldUtil.isNull(${dynamicFieldGetter})) {
+ if (!ProtoBufUtil.isNull(${dynamicFieldGetter})) {
${dynamicFieldName} = ${dynamicFieldGetter};
${encodeWriteFieldValue}
}
@@ -34,7 +34,7 @@ public class ${className} implements ${codecClassName}<${targetProxyClassName}>,
int size = 0;
${dynamicFieldType} ${dynamicFieldName} = null;
- if (!FieldUtil.isNull(${dynamicFieldGetter})) {
+ if (!ProtoBufUtil.isNull(${dynamicFieldGetter})) {
${dynamicFieldName} = ${dynamicFieldGetter};
size += ${sizeDynamicString}
}
From 893f7f3dd5bb6295eeba016c246304355d9ff848 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Fri, 20 Sep 2024 00:26:32 +0800
Subject: [PATCH 33/48] update: add unit test
---
arthas-grpc-server/pom.xml | 41 +++---
.../grpc/server/protobuf/ProtobufProxy.java | 8 +-
.../server/protobuf/utils/ProtoBufUtil.java | 2 +-
.../service/req/ArthasSampleRequest.java | 2 -
.../src/test/java/grpc/GrpcTest.java | 13 ++
.../src/test/java/protobuf/ProtoBufTest.java | 51 +++++++
.../test/java/protobuf/ProtoBufTestReq.java | 129 ++++++++++++++++++
7 files changed, 219 insertions(+), 27 deletions(-)
create mode 100644 arthas-grpc-server/src/test/java/grpc/GrpcTest.java
create mode 100644 arthas-grpc-server/src/test/java/protobuf/ProtoBufTest.java
create mode 100644 arthas-grpc-server/src/test/java/protobuf/ProtoBufTestReq.java
diff --git a/arthas-grpc-server/pom.xml b/arthas-grpc-server/pom.xml
index 7045441714..025ed5b385 100644
--- a/arthas-grpc-server/pom.xml
+++ b/arthas-grpc-server/pom.xml
@@ -62,29 +62,30 @@
1.5.0
-
- org.projectlombok
- lombok
- 1.18.30
- provided
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ io.grpc
+ grpc-netty
+ test
+
+
+ io.grpc
+ grpc-services
+ test
+
+
+ org.junit.vintage
+ junit-vintage-engine
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
index 389be4c24e..bd6b690424 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
@@ -23,7 +23,7 @@
public class ProtobufProxy {
private static final String TEMPLATE_FILE = "/class_template.tpl";
- private static final Map codecCache = new ConcurrentHashMap();
+ private static final Map codecCache = new ConcurrentHashMap<>();
private static Class> clazz;
@@ -31,8 +31,8 @@ public class ProtobufProxy {
private static List protobufFields;
- public static ProtobufCodec getCodecCacheSide(Class> clazz) {
- ProtobufCodec codec = codecCache.get(clazz.getName());
+ public static ProtobufCodec getCodecCacheSide(Class clazz) {
+ ProtobufCodec codec = codecCache.get(clazz.getName());
if (codec != null) {
return codec;
}
@@ -46,7 +46,7 @@ public static ProtobufCodec getCodecCacheSide(Class> clazz) {
}
}
- public static ProtobufCodec create(Class clazz) {
+ public static ProtobufCodec create(Class clazz) {
Objects.requireNonNull(clazz);
if (clazz.getAnnotation(ProtobufClass.class) == null) {
throw new IllegalArgumentException(clazz + "class is not annotated with @ProtobufClass");
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java
index 221966832f..f0ee0162bd 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java
@@ -453,7 +453,7 @@ public static String getWriteByteDynamicString(ProtobufField protobufField) {
.append(JAVA_LINE_BREAK).append("}").append(LINE_BREAK);
return sb.toString();
} else if (protobufField.isMap()) {
- sb.append("Field.writeMap(").append(CODE_OUTPUT_STREAM_OBJ_NAME).append(",");
+ sb.append("ProtoBufUtil.writeMap(").append(CODE_OUTPUT_STREAM_OBJ_NAME).append(",");
sb.append(order).append(",").append(dynamicFieldName);
String joinedSentence = getMapFieldGenericParameterString(protobufField);
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasSampleRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasSampleRequest.java
index 46a0475c4d..d5eaabc29f 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasSampleRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasSampleRequest.java
@@ -4,7 +4,6 @@
*/
import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
-import lombok.ToString;
import java.util.List;
@@ -15,7 +14,6 @@
*/
@ProtobufClass
-@ToString
public class ArthasSampleRequest {
private String name;
diff --git a/arthas-grpc-server/src/test/java/grpc/GrpcTest.java b/arthas-grpc-server/src/test/java/grpc/GrpcTest.java
new file mode 100644
index 0000000000..d5c4b440e5
--- /dev/null
+++ b/arthas-grpc-server/src/test/java/grpc/GrpcTest.java
@@ -0,0 +1,13 @@
+package grpc; /**
+ * @author: 風楪
+ * @date: 2024/9/19 22:20
+ */
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/19 22:20
+ * @description: grpc.GrpcTest
+ */
+public class GrpcTest {
+
+}
diff --git a/arthas-grpc-server/src/test/java/protobuf/ProtoBufTest.java b/arthas-grpc-server/src/test/java/protobuf/ProtoBufTest.java
new file mode 100644
index 0000000000..0c72902d93
--- /dev/null
+++ b/arthas-grpc-server/src/test/java/protobuf/ProtoBufTest.java
@@ -0,0 +1,51 @@
+package protobuf; /**
+ * @author: 風楪
+ * @date: 2024/9/19 22:35
+ */
+
+import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
+import com.taobao.arthas.grpc.server.service.req.ArthasSampleRequest;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/19 22:35
+ * @description: protobuf.ProtoBufTest
+ */
+public class ProtoBufTest {
+ @Test
+ public void testEncodeAndDecode() {
+ ProtoBufTestReq protoBufTestReq = new ProtoBufTestReq();
+ protoBufTestReq.setName("test");
+ protoBufTestReq.setAge(18);
+ protoBufTestReq.setPrice(100L);
+ protoBufTestReq.setStatus(ArthasSampleRequest.StatusEnum.START);
+ List list = new ArrayList<>();
+ list.add(new ProtoBufTestReq.TestClass("test1"));
+ list.add(new ProtoBufTestReq.TestClass("test2"));
+ list.add(new ProtoBufTestReq.TestClass("test3"));
+ Map map = new HashMap<>();
+ map.put("key1","value1");
+ map.put("key2","value2");
+ map.put("key3","value3");
+ protoBufTestReq.setTestList(list);
+ protoBufTestReq.setTestMap(map);
+
+ try {
+ ProtobufCodec protobufCodec = ProtobufProxy.getCodecCacheSide(ProtoBufTestReq.class);
+ byte[] encode = protobufCodec.encode(protoBufTestReq);
+ ProtoBufTestReq decode = protobufCodec.decode(encode);
+ Assert.assertEquals(protoBufTestReq.toString(), decode.toString());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/arthas-grpc-server/src/test/java/protobuf/ProtoBufTestReq.java b/arthas-grpc-server/src/test/java/protobuf/ProtoBufTestReq.java
new file mode 100644
index 0000000000..53c48512c3
--- /dev/null
+++ b/arthas-grpc-server/src/test/java/protobuf/ProtoBufTestReq.java
@@ -0,0 +1,129 @@
+package protobuf;/**
+ * @author: 風楪
+ * @date: 2024/9/19 22:38
+ */
+
+import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
+import com.taobao.arthas.grpc.server.service.req.ArthasSampleRequest;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/19 22:38
+ * @description: ProtoBufTestReq
+ */
+@ProtobufClass
+public class ProtoBufTestReq {
+ private String name;
+ private double age;
+ private long price;
+ private ArthasSampleRequest.StatusEnum status;
+ private List testList;
+ private Map testMap;
+
+ @ProtobufClass
+ public enum StatusEnum {
+ START(1, "开始"),
+ STOP(2, "结束");
+
+ StatusEnum(int code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ private int code;
+ private String desc;
+ }
+
+ @ProtobufClass
+ public static class TestClass {
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ // 注意被 @ProtobufClass 注解的 class 必须添加无参构造函数
+ public TestClass() {
+ }
+
+ public TestClass(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return "TestClass{" +
+ "name='" + name + '\'' +
+ '}';
+ }
+ }
+
+ public List getTestList() {
+ return testList;
+ }
+
+ public void setTestList(List testList) {
+ this.testList = testList;
+ }
+
+ public ArthasSampleRequest.StatusEnum getStatus() {
+ return status;
+ }
+
+ public void setStatus(ArthasSampleRequest.StatusEnum status) {
+ this.status = status;
+ }
+
+ public long getPrice() {
+ return price;
+ }
+
+ public void setPrice(long price) {
+ this.price = price;
+ }
+
+ public double getAge() {
+ return age;
+ }
+
+ public void setAge(double age) {
+ this.age = age;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Map getTestMap() {
+ return testMap;
+ }
+
+ public void setTestMap(Map testMap) {
+ this.testMap = testMap;
+ }
+
+ @Override
+ public java.lang.String toString() {
+ return "ProtoBufTestReq{" +
+ "name='" + name + '\'' +
+ ", age=" + age +
+ ", price=" + price +
+ ", status=" + status +
+ ", testList=" + testList +
+ ", testMap=" + testMap +
+ '}';
+ }
+}
+
From f3050abc63c61aeafa291fc2781cebb5781dda4e Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Mon, 23 Sep 2024 02:47:33 +0800
Subject: [PATCH 34/48] update: formatter
---
arthas-grpc-server/pom.xml | 64 +++++++-------
.../arthas/grpc/server/ArthasGrpcServer.java | 6 +-
.../grpc/server/handler/GrpcDispatcher.java | 6 +-
.../grpc/server/handler/GrpcRequest.java | 5 +-
.../grpc/server/handler/GrpcResponse.java | 7 +-
.../server/handler/Http2FrameRequest.java | 5 +-
.../grpc/server/handler/Http2Handler.java | 7 +-
.../server/handler/annotation/GrpcMethod.java | 8 +-
.../handler/annotation/GrpcService.java | 7 +-
.../grpc/server/protobuf/ProtobufCodec.java | 5 +-
.../grpc/server/protobuf/ProtobufField.java | 5 +-
.../protobuf/ProtobufFieldTypeEnum.java | 5 +-
.../grpc/server/protobuf/ProtobufProxy.java | 6 +-
.../protobuf/annotation/ProtobufClass.java | 5 +-
.../annotation/ProtobufCustomizedField.java | 8 +-
.../annotation/ProtobufEnableZigZap.java | 7 +-
.../protobuf/annotation/ProtobufIgnore.java | 7 +-
.../protobuf/annotation/ProtobufPacked.java | 5 +-
.../server/service/ArthasSampleService.java | 13 ++-
.../service/impl/ArthasSampleServiceImpl.java | 29 +++----
.../service/req/ArthasSampleRequest.java | 83 -------------------
.../service/req/ArthasUnittestRequest.java | 21 +++++
...ponse.java => ArthasUnittestResponse.java} | 7 +-
.../arthas/grpc/server/utils/ByteUtil.java | 5 +-
.../arthas/grpc/server/utils/ReflectUtil.java | 5 +-
.../src/main/proto/arthasSample.proto | 8 +-
.../src/main/proto/arthasUnittest.proto | 16 ++++
.../java/{ => unittest}/grpc/GrpcTest.java | 5 +-
.../{ => unittest}/protobuf/ProtoBufTest.java | 9 +-
.../protobuf/ProtoBufTestReq.java | 15 ++--
30 files changed, 131 insertions(+), 253 deletions(-)
delete mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasSampleRequest.java
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasUnittestRequest.java
rename arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/res/{ArthasSampleResponse.java => ArthasUnittestResponse.java} (72%)
create mode 100644 arthas-grpc-server/src/main/proto/arthasUnittest.proto
rename arthas-grpc-server/src/test/java/{ => unittest}/grpc/GrpcTest.java (62%)
rename arthas-grpc-server/src/test/java/{ => unittest}/protobuf/ProtoBufTest.java (87%)
rename arthas-grpc-server/src/test/java/{ => unittest}/protobuf/ProtoBufTestReq.java (87%)
diff --git a/arthas-grpc-server/pom.xml b/arthas-grpc-server/pom.xml
index 025ed5b385..352b7e8c12 100644
--- a/arthas-grpc-server/pom.xml
+++ b/arthas-grpc-server/pom.xml
@@ -69,12 +69,12 @@
io.grpc
grpc-netty
- test
+ provided
io.grpc
grpc-services
- test
+ provided
org.junit.vintage
@@ -89,34 +89,34 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ org.xolstice.maven.plugins
+ protobuf-maven-plugin
+ 0.6.1
+
+ ${basedir}/src/main/proto
+ com.google.protobuf:protoc:3.11.0:exe:${os.detected.classifier}
+ grpc-java
+ io.grpc:protoc-gen-grpc-java:1.28.0:exe:${os.detected.classifier}
+
+
+
+
+ compile
+ compile-custom
+
+
+
+
+
+
+
+ kr.motd.maven
+ os-maven-plugin
+ 1.4.1.Final
+
+
+
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
index 07fc1a9718..eef0fbacd7 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server;/**
- * @author: 風楪
- * @date: 2024/7/3 上午12:30
- */
+package com.taobao.arthas.grpc.server;
import com.taobao.arthas.grpc.server.handler.GrpcDispatcher;
import com.taobao.arthas.grpc.server.handler.Http2Handler;
@@ -65,7 +62,6 @@ public void initChannel(SocketChannel ch) {
}
});
- // Bind and start to accept incoming connections.
b.bind(9090).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
index 36d5441cda..10f40b14cb 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
@@ -1,13 +1,9 @@
-package com.taobao.arthas.grpc.server.handler;/**
- * @author: 風楪
- * @date: 2024/9/6 01:12
- */
+package com.taobao.arthas.grpc.server.handler;
import com.taobao.arthas.grpc.server.handler.annotation.GrpcMethod;
import com.taobao.arthas.grpc.server.handler.annotation.GrpcService;
import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
-import com.taobao.arthas.grpc.server.utils.ByteUtil;
import com.taobao.arthas.grpc.server.utils.ReflectUtil;
import java.lang.invoke.MethodHandle;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
index 7a0498bf13..feda7c3357 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.handler;/**
- * @author: 風楪
- * @date: 2024/9/4 23:07
- */
+package com.taobao.arthas.grpc.server.handler;
import com.taobao.arthas.grpc.server.utils.ByteUtil;
import io.netty.buffer.ByteBuf;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
index bbdaef78df..1c6c2ccec3 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.handler;/**
- * @author: 風楪
- * @date: 2024/9/5 02:05
- */
+package com.taobao.arthas.grpc.server.handler;
import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
@@ -50,7 +47,7 @@ public Http2Headers getEndStreamHeader() {
return new DefaultHttp2Headers().set("grpc-status", "0");
}
- public ByteBuf getResponseData(){
+ public ByteBuf getResponseData() {
return byteData;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2FrameRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2FrameRequest.java
index 49091da077..1e8058dcce 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2FrameRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2FrameRequest.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.handler;/**
- * @author: 風楪
- * @date: 2024/9/18 23:12
- */
+package com.taobao.arthas.grpc.server.handler;
import java.util.List;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
index dbd700f118..fdf634f4eb 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.handler;/**
- * @author: 風楪
- * @date: 2024/7/7 下午9:58
- */
+package com.taobao.arthas.grpc.server.handler;
import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
@@ -75,7 +72,7 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
GrpcResponse response = new GrpcResponse();
byte[] bytes = grpcRequest.readData();
while (bytes != null) {
- ProtobufCodec protobufCodec = ProtobufProxy.getCodecCacheSide(grpcDispatcher.getRequestClass(grpcRequest.getService(),grpcRequest.getMethod()));
+ ProtobufCodec protobufCodec = ProtobufProxy.getCodecCacheSide(grpcDispatcher.getRequestClass(grpcRequest.getService(), grpcRequest.getMethod()));
Object decode = protobufCodec.decode(bytes);
response = grpcDispatcher.execute(grpcRequest.getService(), grpcRequest.getMethod(), decode);
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcMethod.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcMethod.java
index d109fdce59..10f1c9b724 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcMethod.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcMethod.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.handler.annotation;/**
- * @author: 風楪
- * @date: 2024/9/6 01:57
- */
+package com.taobao.arthas.grpc.server.handler.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -13,9 +10,10 @@
* @date: 2024/9/6 01:57
* @description: GrpcMethod
*/
-@Target({ ElementType.METHOD })
+@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface GrpcMethod {
String value() default "";
+
boolean stream() default false;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcService.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcService.java
index 6d0751d501..c54dc7d624 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcService.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/annotation/GrpcService.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.handler.annotation;/**
- * @author: 風楪
- * @date: 2024/9/6 01:57
- */
+package com.taobao.arthas.grpc.server.handler.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -13,7 +10,7 @@
* @date: 2024/9/6 01:57
* @description: GrpcService
*/
-@Target({ ElementType.TYPE })
+@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface GrpcService {
String value() default "";
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufCodec.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufCodec.java
index 0bd6486258..63b783fa3e 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufCodec.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufCodec.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.protobuf;/**
- * @author: 風楪
- * @date: 2024/7/17 下午9:44
- */
+package com.taobao.arthas.grpc.server.protobuf;
import com.google.protobuf.CodedInputStream;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufField.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufField.java
index 69b1fcb4d9..498265a0c5 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufField.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufField.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.protobuf;/**
- * @author: 風楪
- * @date: 2024/7/25 上午12:14
- */
+package com.taobao.arthas.grpc.server.protobuf;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufFieldTypeEnum.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufFieldTypeEnum.java
index 36f3a1d1e7..6fc34e19a5 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufFieldTypeEnum.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufFieldTypeEnum.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.protobuf;/**
- * @author: 風楪
- * @date: 2024/7/17 下午10:02
- */
+package com.taobao.arthas.grpc.server.protobuf;
import com.google.protobuf.WireFormat;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
index bd6b690424..6903f6e018 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/ProtobufProxy.java
@@ -1,8 +1,4 @@
-package com.taobao.arthas.grpc.server.protobuf;/**
- * @author: 風楪
- * @date: 2024/7/17 下午9:57
- */
-
+package com.taobao.arthas.grpc.server.protobuf;
import com.google.protobuf.WireFormat;
import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufEnableZigZap;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufClass.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufClass.java
index 62482239c7..5843dee4ad 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufClass.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufClass.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.protobuf.annotation;/**
- * @author: 風楪
- * @date: 2024/7/25 上午12:19
- */
+package com.taobao.arthas.grpc.server.protobuf.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufCustomizedField.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufCustomizedField.java
index 59eea05f4f..adfa7f05f3 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufCustomizedField.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufCustomizedField.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.protobuf.annotation;/**
- * @author: 風楪
- * @date: 2024/7/25 上午12:21
- */
+package com.taobao.arthas.grpc.server.protobuf.annotation;
import com.taobao.arthas.grpc.server.protobuf.ProtobufFieldTypeEnum;
@@ -15,9 +12,10 @@
* @date: 2024/7/25 上午12:21
* @description: ProtobufField 用于自定义标识字段
*/
-@Target({ ElementType.FIELD })
+@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ProtobufCustomizedField {
int order() default 0;
+
ProtobufFieldTypeEnum protoBufFieldType() default ProtobufFieldTypeEnum.DEFAULT;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufEnableZigZap.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufEnableZigZap.java
index f92c9cbbe6..4a85807fd1 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufEnableZigZap.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufEnableZigZap.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.protobuf.annotation;/**
- * @author: 風楪
- * @date: 2024/7/28 下午7:27
- */
+package com.taobao.arthas.grpc.server.protobuf.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -13,7 +10,7 @@
* @date: 2024/7/28 下午7:27
* @description: EnableZigZap 是否启用 zigzap 编码
*/
-@Target({ ElementType.TYPE })
+@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ProtobufEnableZigZap {
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufIgnore.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufIgnore.java
index fa6b00a2f9..269a3edcb4 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufIgnore.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufIgnore.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.protobuf.annotation;/**
- * @author: 風楪
- * @date: 2024/7/25 上午12:44
- */
+package com.taobao.arthas.grpc.server.protobuf.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -13,7 +10,7 @@
* @date: 2024/7/25 上午12:44
* @description: ProtobufIgnore
*/
-@Target({ ElementType.TYPE, ElementType.FIELD })
+@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ProtobufIgnore {
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufPacked.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufPacked.java
index 1944558a52..7045ad6003 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufPacked.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/annotation/ProtobufPacked.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.protobuf.annotation;/**
- * @author: 風楪
- * @date: 2024/7/30 上午2:01
- */
+package com.taobao.arthas.grpc.server.protobuf.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/ArthasSampleService.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/ArthasSampleService.java
index 79c6499f58..732fe570fa 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/ArthasSampleService.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/ArthasSampleService.java
@@ -1,10 +1,7 @@
-package com.taobao.arthas.grpc.server.service;/**
- * @author: 風楪
- * @date: 2024/6/30 下午11:42
- */
+package com.taobao.arthas.grpc.server.service;
-import com.taobao.arthas.grpc.server.service.req.ArthasSampleRequest;
-import com.taobao.arthas.grpc.server.service.res.ArthasSampleResponse;
+import com.taobao.arthas.grpc.server.service.req.ArthasUnittestRequest;
+import com.taobao.arthas.grpc.server.service.res.ArthasUnittestResponse;
/**
* @author: FengYe
@@ -12,6 +9,6 @@
* @description: ArthasSampleService
*/
public interface ArthasSampleService {
- ArthasSampleResponse trace(ArthasSampleRequest command);
- ArthasSampleResponse watch(ArthasSampleRequest command);
+ ArthasUnittestResponse trace(ArthasUnittestRequest command);
+ ArthasUnittestResponse watch(ArthasUnittestRequest command);
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
index 0d88de0501..5e5cb415e3 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
@@ -1,36 +1,33 @@
-package com.taobao.arthas.grpc.server.service.impl;/**
- * @author: 風楪
- * @date: 2024/6/30 下午11:43
- */
+package com.taobao.arthas.grpc.server.service.impl;
import com.taobao.arthas.grpc.server.handler.annotation.GrpcMethod;
import com.taobao.arthas.grpc.server.handler.annotation.GrpcService;
import com.taobao.arthas.grpc.server.service.ArthasSampleService;
-import com.taobao.arthas.grpc.server.service.req.ArthasSampleRequest;
-import com.taobao.arthas.grpc.server.service.res.ArthasSampleResponse;
+import com.taobao.arthas.grpc.server.service.req.ArthasUnittestRequest;
+import com.taobao.arthas.grpc.server.service.res.ArthasUnittestResponse;
/**
* @author: FengYe
* @date: 2024/6/30 下午11:43
* @description: ArthasSampleServiceImpl
*/
-@GrpcService("arthasSample.ArthasTempService")
+@GrpcService("arthas.sample.ArthasTempService")
public class ArthasSampleServiceImpl implements ArthasSampleService {
@Override
@GrpcMethod("trace")
- public ArthasSampleResponse trace(ArthasSampleRequest command) {
- ArthasSampleResponse arthasSampleResponse = new ArthasSampleResponse();
- arthasSampleResponse.setMessage("trace");
- return arthasSampleResponse;
+ public ArthasUnittestResponse trace(ArthasUnittestRequest command) {
+ ArthasUnittestResponse arthasUnittestResponse = new ArthasUnittestResponse();
+ arthasUnittestResponse.setMessage("trace");
+ return arthasUnittestResponse;
}
@Override
@GrpcMethod(value = "watch", stream = true)
- public ArthasSampleResponse watch(ArthasSampleRequest command) {
- String name = command.getName();
- ArthasSampleResponse arthasSampleResponse = new ArthasSampleResponse();
- arthasSampleResponse.setMessage(name);
- return arthasSampleResponse;
+ public ArthasUnittestResponse watch(ArthasUnittestRequest command) {
+ String message = command.getMessage();
+ ArthasUnittestResponse arthasUnittestResponse = new ArthasUnittestResponse();
+ arthasUnittestResponse.setMessage(message);
+ return arthasUnittestResponse;
}
}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasSampleRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasSampleRequest.java
deleted file mode 100644
index d5eaabc29f..0000000000
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasSampleRequest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.taobao.arthas.grpc.server.service.req;/**
- * @author: 風楪
- * @date: 2024/7/14 上午4:28
- */
-
-import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
-
-import java.util.List;
-
-/**
- * @author: FengYe
- * @date: 2024/7/14 上午4:28
- * @description: ArthasSampleRequest
- */
-
-@ProtobufClass
-public class ArthasSampleRequest {
-
- private String name;
- private double age;
- private long price;
- private StatusEnum status;
- private List testList;
-
- @ProtobufClass
- public enum StatusEnum {
- START(1, "开始"),
- STOP(2, "结束");
-
- StatusEnum(int code, String desc) {
- this.code = code;
- this.desc = desc;
- }
-
- private int code;
- private String desc;
- }
-
- @ProtobufClass
- public static class TestClass {
- private String name;
- }
-
- public List getTestList() {
- return testList;
- }
-
- public void setTestList(List testList) {
- this.testList = testList;
- }
-
- public StatusEnum getStatus() {
- return status;
- }
-
- public void setStatus(StatusEnum status) {
- this.status = status;
- }
-
- public long getPrice() {
- return price;
- }
-
- public void setPrice(long price) {
- this.price = price;
- }
-
- public double getAge() {
- return age;
- }
-
- public void setAge(double age) {
- this.age = age;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasUnittestRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasUnittestRequest.java
new file mode 100644
index 0000000000..b2b1c44352
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasUnittestRequest.java
@@ -0,0 +1,21 @@
+package com.taobao.arthas.grpc.server.service.req;
+
+import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
+
+/**
+ * @author: FengYe
+ * @date: 2024/7/14 上午4:28
+ * @description: ArthasSampleRequest
+ */
+@ProtobufClass
+public class ArthasUnittestRequest {
+ private String message;
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/res/ArthasSampleResponse.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/res/ArthasUnittestResponse.java
similarity index 72%
rename from arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/res/ArthasSampleResponse.java
rename to arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/res/ArthasUnittestResponse.java
index 09ab40f71f..49c5a58387 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/res/ArthasSampleResponse.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/res/ArthasUnittestResponse.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.service.res;/**
- * @author: 風楪
- * @date: 2024/8/11 22:11
- */
+package com.taobao.arthas.grpc.server.service.res;
import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
@@ -11,7 +8,7 @@
* @description: ArthasSampleResponse
*/
@ProtobufClass
-public class ArthasSampleResponse {
+public class ArthasUnittestResponse {
private String message;
public String getMessage() {
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java
index 29044d36e6..2bd239521d 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ByteUtil.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.utils;/**
- * @author: 風楪
- * @date: 2024/9/5 00:51
- */
+package com.taobao.arthas.grpc.server.utils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ReflectUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ReflectUtil.java
index 5da93c9dfd..c6e3e053ed 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ReflectUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/utils/ReflectUtil.java
@@ -1,7 +1,4 @@
-package com.taobao.arthas.grpc.server.utils;/**
- * @author: 風楪
- * @date: 2024/9/6 02:20
- */
+package com.taobao.arthas.grpc.server.utils;
import java.io.File;
import java.net.URL;
diff --git a/arthas-grpc-server/src/main/proto/arthasSample.proto b/arthas-grpc-server/src/main/proto/arthasSample.proto
index 3e14f5eec9..33df5d8a80 100644
--- a/arthas-grpc-server/src/main/proto/arthasSample.proto
+++ b/arthas-grpc-server/src/main/proto/arthasSample.proto
@@ -1,6 +1,6 @@
syntax = "proto3";
-package arthasSample;
+package arthas.sample;
enum StatusEnum {
@@ -8,9 +8,9 @@ enum StatusEnum {
STOP = 1;
}
-service ArthasTempService {
- rpc trace(ArthasSampleRequest) returns (ArthasSampleResponse);
- rpc watch(stream ArthasSampleRequest) returns (stream ArthasSampleResponse);
+service ArthasSampleService {
+ rpc testUnary(ArthasSampleRequest) returns (ArthasSampleResponse);
+ rpc testBiStream(stream ArthasSampleRequest) returns (stream ArthasSampleResponse);
}
message ArthasSampleRequest {
diff --git a/arthas-grpc-server/src/main/proto/arthasUnittest.proto b/arthas-grpc-server/src/main/proto/arthasUnittest.proto
new file mode 100644
index 0000000000..731c0f1e63
--- /dev/null
+++ b/arthas-grpc-server/src/main/proto/arthasUnittest.proto
@@ -0,0 +1,16 @@
+syntax = "proto3";
+
+package arthas.unittest;
+
+service ArthasUnittestService {
+ rpc trace(ArthasUnittestRequest) returns (ArthasUnittestResponse);
+ rpc watch(stream ArthasUnittestRequest) returns (stream ArthasUnittestResponse);
+}
+
+message ArthasUnittestRequest {
+ string message = 1;
+}
+
+message ArthasUnittestResponse{
+ string message = 1;
+}
diff --git a/arthas-grpc-server/src/test/java/grpc/GrpcTest.java b/arthas-grpc-server/src/test/java/unittest/grpc/GrpcTest.java
similarity index 62%
rename from arthas-grpc-server/src/test/java/grpc/GrpcTest.java
rename to arthas-grpc-server/src/test/java/unittest/grpc/GrpcTest.java
index d5c4b440e5..504282a14c 100644
--- a/arthas-grpc-server/src/test/java/grpc/GrpcTest.java
+++ b/arthas-grpc-server/src/test/java/unittest/grpc/GrpcTest.java
@@ -1,7 +1,4 @@
-package grpc; /**
- * @author: 風楪
- * @date: 2024/9/19 22:20
- */
+package unittest.grpc;
/**
* @author: FengYe
diff --git a/arthas-grpc-server/src/test/java/protobuf/ProtoBufTest.java b/arthas-grpc-server/src/test/java/unittest/protobuf/ProtoBufTest.java
similarity index 87%
rename from arthas-grpc-server/src/test/java/protobuf/ProtoBufTest.java
rename to arthas-grpc-server/src/test/java/unittest/protobuf/ProtoBufTest.java
index 0c72902d93..c7de3bf762 100644
--- a/arthas-grpc-server/src/test/java/protobuf/ProtoBufTest.java
+++ b/arthas-grpc-server/src/test/java/unittest/protobuf/ProtoBufTest.java
@@ -1,11 +1,8 @@
-package protobuf; /**
- * @author: 風楪
- * @date: 2024/9/19 22:35
- */
+package unittest.protobuf;
import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
-import com.taobao.arthas.grpc.server.service.req.ArthasSampleRequest;
+import com.taobao.arthas.grpc.server.service.req.ArthasUnittestRequest;
import org.junit.Assert;
import org.junit.Test;
@@ -27,7 +24,7 @@ public void testEncodeAndDecode() {
protoBufTestReq.setName("test");
protoBufTestReq.setAge(18);
protoBufTestReq.setPrice(100L);
- protoBufTestReq.setStatus(ArthasSampleRequest.StatusEnum.START);
+ protoBufTestReq.setStatus(ProtoBufTestReq.StatusEnum.START);
List list = new ArrayList<>();
list.add(new ProtoBufTestReq.TestClass("test1"));
list.add(new ProtoBufTestReq.TestClass("test2"));
diff --git a/arthas-grpc-server/src/test/java/protobuf/ProtoBufTestReq.java b/arthas-grpc-server/src/test/java/unittest/protobuf/ProtoBufTestReq.java
similarity index 87%
rename from arthas-grpc-server/src/test/java/protobuf/ProtoBufTestReq.java
rename to arthas-grpc-server/src/test/java/unittest/protobuf/ProtoBufTestReq.java
index 53c48512c3..2af16c91fe 100644
--- a/arthas-grpc-server/src/test/java/protobuf/ProtoBufTestReq.java
+++ b/arthas-grpc-server/src/test/java/unittest/protobuf/ProtoBufTestReq.java
@@ -1,14 +1,11 @@
-package protobuf;/**
- * @author: 風楪
- * @date: 2024/9/19 22:38
- */
+package unittest.protobuf;
+import com.taobao.arthas.grpc.server.protobuf.ProtobufField;
import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
-import com.taobao.arthas.grpc.server.service.req.ArthasSampleRequest;
+import com.taobao.arthas.grpc.server.service.req.ArthasUnittestRequest;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
/**
* @author: FengYe
@@ -20,7 +17,7 @@ public class ProtoBufTestReq {
private String name;
private double age;
private long price;
- private ArthasSampleRequest.StatusEnum status;
+ private ProtoBufTestReq.StatusEnum status;
private List testList;
private Map testMap;
@@ -74,11 +71,11 @@ public void setTestList(List testList) {
this.testList = testList;
}
- public ArthasSampleRequest.StatusEnum getStatus() {
+ public ProtoBufTestReq.StatusEnum getStatus() {
return status;
}
- public void setStatus(ArthasSampleRequest.StatusEnum status) {
+ public void setStatus(ProtoBufTestReq.StatusEnum status) {
this.status = status;
}
From 7aa63aa641f9309610f83cc148fea2f0dcf8acdf Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Tue, 24 Sep 2024 01:40:06 +0800
Subject: [PATCH 35/48] update: add unit test and error process
---
arthas-grpc-server/pom.xml | 10 +-
.../arthas/grpc/server/handler/ErrorRes.java | 21 ++++
.../grpc/server/handler/GrpcDispatcher.java | 2 +-
.../grpc/server/handler/GrpcResponse.java | 10 +-
.../grpc/server/handler/Http2Handler.java | 20 ++--
.../service/impl/ArthasSampleServiceImpl.java | 7 +-
.../src/main/proto/arthasSample.proto | 29 -----
.../src/test/java/unittest/grpc/GrpcTest.java | 102 +++++++++++++++++-
8 files changed, 153 insertions(+), 48 deletions(-)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/ErrorRes.java
delete mode 100644 arthas-grpc-server/src/main/proto/arthasSample.proto
diff --git a/arthas-grpc-server/pom.xml b/arthas-grpc-server/pom.xml
index 352b7e8c12..6f3e8575d5 100644
--- a/arthas-grpc-server/pom.xml
+++ b/arthas-grpc-server/pom.xml
@@ -39,13 +39,13 @@
io.netty
netty-codec-http2
- 4.1.111.Final
+ 4.1.72.Final
com.google.protobuf
protobuf-java
- 4.27.2
+ 3.19.2
@@ -70,6 +70,12 @@
io.grpc
grpc-netty
provided
+
+
+ io.netty
+ netty-codec-http2
+
+
io.grpc
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/ErrorRes.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/ErrorRes.java
new file mode 100644
index 0000000000..c7cbe8d7ea
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/ErrorRes.java
@@ -0,0 +1,21 @@
+package com.taobao.arthas.grpc.server.handler;
+
+import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
+
+/**
+ * @author: FengYe
+ * @date: 2024/9/23 23:58
+ * @description: ErrorRes
+ */
+@ProtobufClass
+public class ErrorRes {
+ private String errorMsg;
+
+ public String getErrorMsg() {
+ return errorMsg;
+ }
+
+ public void setErrorMsg(String errorMsg) {
+ this.errorMsg = errorMsg;
+ }
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
index 10f40b14cb..8f3daed1be 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
@@ -89,7 +89,7 @@ public GrpcResponse execute(GrpcRequest request) throws Throwable {
*/
public Class> getRequestClass(String serviceName, String methodName) {
//protobuf 规范只能有单入参
- return grpcMethodInvokeMap.get(generateGrpcMethodKey(serviceName, methodName)).type().parameterArray()[0];
+ return Optional.ofNullable(grpcMethodInvokeMap.get(generateGrpcMethodKey(serviceName, methodName))).orElseThrow(() -> new RuntimeException("The specified grpc method does not exist")).type().parameterArray()[0];
}
public void checkGrpcStream(GrpcRequest request) {
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
index 1c6c2ccec3..bbf678fcd7 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcResponse.java
@@ -51,10 +51,14 @@ public ByteBuf getResponseData() {
return byteData;
}
- public void writeResponseData(Object response) throws IOException {
+ public void writeResponseData(Object response) {
ProtobufCodec codec = ProtobufProxy.getCodecCacheSide(clazz);
- byte[] encode = codec.encode(response);
-
+ byte[] encode = null;
+ try {
+ encode = codec.encode(response);
+ } catch (IOException e) {
+ throw new RuntimeException("ProtobufCodec encode error");
+ }
this.byteData = ByteUtil.newByteBuf();
this.byteData.writeBoolean(false);
this.byteData.writeInt(encode.length);
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
index fdf634f4eb..ff4c01a8b6 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
@@ -2,6 +2,8 @@
import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
+import com.taobao.arthas.grpc.server.utils.ByteUtil;
+import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http2.*;
@@ -43,7 +45,6 @@ protected void channelRead0(ChannelHandlerContext ctx, Http2Frame frame) throws
}
}
-
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
@@ -65,7 +66,6 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
GrpcRequest grpcRequest = dataBuffer.get(dataFrame.stream().id());
grpcRequest.writeData(dataFrame.content());
- System.out.println(dataFrame.stream().id());
if (grpcRequest.isStream()) {
// 流式调用,即刻响应
try {
@@ -92,7 +92,7 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndStreamHeader(), true).stream(dataFrame.stream()));
}
} catch (Throwable e) {
- processError(ctx, e);
+ processError(ctx, e, dataFrame.stream());
}
} else {
// 非流式调用,等到 endStream 再响应
@@ -103,14 +103,20 @@ private void handleGrpcData(Http2DataFrame dataFrame, ChannelHandlerContext ctx)
ctx.writeAndFlush(new DefaultHttp2DataFrame(response.getResponseData()).stream(dataFrame.stream()));
ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndStreamHeader(), true).stream(dataFrame.stream()));
} catch (Throwable e) {
- processError(ctx, e);
+ processError(ctx, e, dataFrame.stream());
}
}
}
}
- private void processError(ChannelHandlerContext ctx, Throwable e) {
- //todo
- ctx.writeAndFlush(e.getMessage());
+ private void processError(ChannelHandlerContext ctx, Throwable e, Http2FrameStream stream) {
+ GrpcResponse response = new GrpcResponse();
+ ErrorRes errorRes = new ErrorRes();
+ errorRes.setErrorMsg(e.getMessage());
+ response.setClazz(ErrorRes.class);
+ response.writeResponseData(errorRes);
+ ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndHeader()).stream(stream));
+ ctx.writeAndFlush(new DefaultHttp2DataFrame(response.getResponseData()).stream(stream));
+ ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response.getEndStreamHeader(), true).stream(stream));
}
}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
index 5e5cb415e3..b01787c36c 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/impl/ArthasSampleServiceImpl.java
@@ -11,23 +11,22 @@
* @date: 2024/6/30 下午11:43
* @description: ArthasSampleServiceImpl
*/
-@GrpcService("arthas.sample.ArthasTempService")
+@GrpcService("arthas.unittest.ArthasUnittestService")
public class ArthasSampleServiceImpl implements ArthasSampleService {
@Override
@GrpcMethod("trace")
public ArthasUnittestResponse trace(ArthasUnittestRequest command) {
ArthasUnittestResponse arthasUnittestResponse = new ArthasUnittestResponse();
- arthasUnittestResponse.setMessage("trace");
+ arthasUnittestResponse.setMessage(command.getMessage());
return arthasUnittestResponse;
}
@Override
@GrpcMethod(value = "watch", stream = true)
public ArthasUnittestResponse watch(ArthasUnittestRequest command) {
- String message = command.getMessage();
ArthasUnittestResponse arthasUnittestResponse = new ArthasUnittestResponse();
- arthasUnittestResponse.setMessage(message);
+ arthasUnittestResponse.setMessage(command.getMessage());
return arthasUnittestResponse;
}
}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/main/proto/arthasSample.proto b/arthas-grpc-server/src/main/proto/arthasSample.proto
deleted file mode 100644
index 33df5d8a80..0000000000
--- a/arthas-grpc-server/src/main/proto/arthasSample.proto
+++ /dev/null
@@ -1,29 +0,0 @@
-syntax = "proto3";
-
-package arthas.sample;
-
-
-enum StatusEnum {
- START = 0;
- STOP = 1;
-}
-
-service ArthasSampleService {
- rpc testUnary(ArthasSampleRequest) returns (ArthasSampleResponse);
- rpc testBiStream(stream ArthasSampleRequest) returns (stream ArthasSampleResponse);
-}
-
-message ArthasSampleRequest {
- string name = 1; double age = 2;
- int64 price = 3;
- StatusEnum status = 4;
- repeated TestClass testList = 5;
-}
-
-message TestClass{
- string name = 1;
-}
-
-message ArthasSampleResponse {
- string message = 1;
-}
diff --git a/arthas-grpc-server/src/test/java/unittest/grpc/GrpcTest.java b/arthas-grpc-server/src/test/java/unittest/grpc/GrpcTest.java
index 504282a14c..d6d57b12e0 100644
--- a/arthas-grpc-server/src/test/java/unittest/grpc/GrpcTest.java
+++ b/arthas-grpc-server/src/test/java/unittest/grpc/GrpcTest.java
@@ -1,10 +1,108 @@
package unittest.grpc;
+import arthas.unittest.ArthasUnittest;
+import arthas.unittest.ArthasUnittestServiceGrpc;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.StatusRuntimeException;
+import io.grpc.stub.StreamObserver;
+import org.junit.Test;
+import org.junit.jupiter.api.Disabled;
+
+import java.util.concurrent.CountDownLatch;
+
/**
* @author: FengYe
- * @date: 2024/9/19 22:20
- * @description: grpc.GrpcTest
+ * @date: 2024/9/24 00:17
+ * @description: GrpcUnaryTest
*/
public class GrpcTest {
+ private static final String target = "localhost:9090";
+ private ArthasUnittestServiceGrpc.ArthasUnittestServiceBlockingStub blockingStub = null;
+ private ArthasUnittestServiceGrpc.ArthasUnittestServiceStub stub = null;
+
+ @Disabled("跳过启动测试")
+ @Test
+ public void testUnary() {
+ ManagedChannel channel = ManagedChannelBuilder.forTarget(target)
+ .usePlaintext()
+ .build();
+
+ blockingStub = ArthasUnittestServiceGrpc.newBlockingStub(channel);
+
+ try {
+ trace("trace");
+ } finally {
+ channel.shutdownNow();
+ }
+ }
+
+ @Disabled("跳过启动测试")
+ @Test
+ public void testStream() {
+ ManagedChannel channel = ManagedChannelBuilder.forTarget(target)
+ .usePlaintext()
+ .build();
+
+ stub = ArthasUnittestServiceGrpc.newStub(channel);
+
+ try {
+ watch("watch1", "watch2", "watch3");
+ } finally {
+ channel.shutdownNow();
+ }
+ }
+
+ private void trace(String name) {
+ ArthasUnittest.ArthasUnittestRequest request = ArthasUnittest.ArthasUnittestRequest.newBuilder().setMessage(name).build();
+ try {
+ ArthasUnittest.ArthasUnittestResponse res = blockingStub.trace(request);
+ System.out.println(res.getMessage());
+ } catch (StatusRuntimeException e) {
+ e.printStackTrace();
+ System.out.println("RPC failed: " + e.getStatus());
+ }
+ }
+
+ private void watch(String... names) {
+ // 使用 CountDownLatch 来等待所有响应
+ CountDownLatch finishLatch = new CountDownLatch(1);
+
+ StreamObserver watch = stub.watch(new StreamObserver() {
+ @Override
+ public void onNext(ArthasUnittest.ArthasUnittestResponse value) {
+ System.out.println("watch: " + value.getMessage());
+ }
+
+ @Override
+ public void onError(Throwable t) {
+
+ }
+
+ @Override
+ public void onCompleted() {
+ System.out.println("Finished sending watch.");
+ }
+ });
+
+
+ try {
+ for (String name : names) {
+ ArthasUnittest.ArthasUnittestRequest request = ArthasUnittest.ArthasUnittestRequest.newBuilder().setMessage(name).build();
+ Thread.sleep(1000L);
+ watch.onNext(request);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ watch.onCompleted();
+ }
+ // 等待服务器的响应
+ try {
+ finishLatch.await(); // 等待完成
+ } catch (InterruptedException e) {
+ System.out.println("Client interrupted: " + e.getMessage());
+ }
+ }
}
From 2061dea048713d86fa016e1f4e88ebd878f43723 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Thu, 10 Oct 2024 21:28:21 +0800
Subject: [PATCH 36/48] update: add maven profiles
---
arthas-grpc-server/pom.xml | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arthas-grpc-server/pom.xml b/arthas-grpc-server/pom.xml
index 6f3e8575d5..b74977c7b6 100644
--- a/arthas-grpc-server/pom.xml
+++ b/arthas-grpc-server/pom.xml
@@ -125,4 +125,18 @@
+
+
+
+ mac
+
+
+ mac
+
+
+
+ osx-x86_64
+
+
+
\ No newline at end of file
From e594712d53b1b1a1921501754038c30e42d6ca2e Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Sun, 13 Oct 2024 03:17:22 +0800
Subject: [PATCH 37/48] update: add more unit test and log
---
arthas-grpc-server/pom.xml | 25 +++++++-
.../grpc/server/ArthasGrpcBootstrap.java | 13 +++++
.../arthas/grpc/server/ArthasGrpcServer.java | 58 ++++++++-----------
.../grpc/server/handler/GrpcDispatcher.java | 6 +-
.../grpc/server/handler/GrpcRequest.java | 35 ++---------
.../grpc/server/handler/Http2Handler.java | 5 ++
.../server/protobuf/utils/ProtoBufUtil.java | 22 ++++---
.../src/test/java/unittest/grpc/GrpcTest.java | 42 +++++++++-----
.../java/unittest/grpc/Http2HandlerTest.java | 9 +++
.../src/test/java/unittest/grpc/TempTest.java | 36 ++++++++++++
.../grpc/service/ArthasSampleService.java | 14 +++++
.../service/impl/ArthasSampleServiceImpl.java | 32 ++++++++++
.../service/req/ArthasUnittestRequest.java | 21 +++++++
.../service/res/ArthasUnittestResponse.java | 21 +++++++
.../src/test/proto/arthasUnittest.proto | 16 +++++
15 files changed, 262 insertions(+), 93 deletions(-)
create mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcBootstrap.java
create mode 100644 arthas-grpc-server/src/test/java/unittest/grpc/Http2HandlerTest.java
create mode 100644 arthas-grpc-server/src/test/java/unittest/grpc/TempTest.java
create mode 100644 arthas-grpc-server/src/test/java/unittest/grpc/service/ArthasSampleService.java
create mode 100644 arthas-grpc-server/src/test/java/unittest/grpc/service/impl/ArthasSampleServiceImpl.java
create mode 100644 arthas-grpc-server/src/test/java/unittest/grpc/service/req/ArthasUnittestRequest.java
create mode 100644 arthas-grpc-server/src/test/java/unittest/grpc/service/res/ArthasUnittestResponse.java
create mode 100644 arthas-grpc-server/src/test/proto/arthasUnittest.proto
diff --git a/arthas-grpc-server/pom.xml b/arthas-grpc-server/pom.xml
index b74977c7b6..c073413454 100644
--- a/arthas-grpc-server/pom.xml
+++ b/arthas-grpc-server/pom.xml
@@ -63,8 +63,6 @@
-
-
io.grpc
@@ -92,6 +90,29 @@
junit-jupiter
test
+
+ javax.annotation
+ javax.annotation-api
+ 1.3.2
+ provided
+ true
+
+
+ com.alibaba.arthas
+ arthas-repackage-logger
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+ org.slf4j
+ slf4j-api
+
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcBootstrap.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcBootstrap.java
new file mode 100644
index 0000000000..c953ffc954
--- /dev/null
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcBootstrap.java
@@ -0,0 +1,13 @@
+package com.taobao.arthas.grpc.server;
+
+/**
+ * @author: FengYe
+ * @date: 2024/10/13 02:40
+ * @description: ArthasGrpcServerBootstrap
+ */
+public class ArthasGrpcBootstrap {
+ public static void main(String[] args) {
+ ArthasGrpcServer arthasGrpcServer = new ArthasGrpcServer(9090, null);
+ arthasGrpcServer.start();
+ }
+}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
index eef0fbacd7..3425657256 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
@@ -1,8 +1,13 @@
package com.taobao.arthas.grpc.server;
+import com.alibaba.arthas.deps.ch.qos.logback.classic.Level;
+import com.alibaba.arthas.deps.ch.qos.logback.classic.LoggerContext;
+import com.alibaba.arthas.deps.org.slf4j.Logger;
+import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.grpc.server.handler.GrpcDispatcher;
import com.taobao.arthas.grpc.server.handler.Http2Handler;
import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
@@ -10,10 +15,8 @@
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http2.Http2FrameCodecBuilder;
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
+
+import java.lang.invoke.MethodHandles;
/**
* @author: FengYe
@@ -22,31 +25,23 @@
*/
public class ArthasGrpcServer {
- public static void main(String[] args) throws Exception {
-// //自签名生成密钥
-// SelfSignedCertificate ssc = new SelfSignedCertificate();
-// SslContext sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-// .build();
-//
-// // 指定生成自签名证书和密钥的位置
-// File certFile = new File(System.getProperty("user.dir"),"certificate.crt");
-// File keyFile = new File(System.getProperty("user.dir"),"privateKey.key");
-//
-// // 将生成的证书和私钥移动到指定位置
-// moveFile(ssc.certificate(), certFile);
-// moveFile(ssc.privateKey(), keyFile);
-//
-// System.out.println(certFile.getAbsolutePath());
-// System.out.println(keyFile.getAbsolutePath());
-//
-// System.out.println("Certificate: " + ssc.certificate());
-// System.out.println("Private Key: " + ssc.privateKey());
+ private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass().getName());
+
+ private int port = 9090;
+
+ private String grpcServicePackageName;
+
+ public ArthasGrpcServer(int port, String grpcServicePackageName) {
+ this.port = port;
+ this.grpcServicePackageName = grpcServicePackageName;
+ }
+ public void start() {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
GrpcDispatcher grpcDispatcher = new GrpcDispatcher();
- grpcDispatcher.loadGrpcService();
+ grpcDispatcher.loadGrpcService(grpcServicePackageName);
try {
ServerBootstrap b = new ServerBootstrap();
@@ -56,23 +51,18 @@ public static void main(String[] args) throws Exception {
.childHandler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) {
-// ch.pipeline().addLast(sslCtx.newHandler(ch.alloc()));
ch.pipeline().addLast(Http2FrameCodecBuilder.forServer().build());
ch.pipeline().addLast(new Http2Handler(grpcDispatcher));
}
});
-
- b.bind(9090).sync().channel().closeFuture().sync();
+ Channel channel = b.bind(port).sync().channel();
+ logger.info("ArthasGrpcServer start successfully on port: {}", port);
+ channel.closeFuture().sync();
+ } catch (InterruptedException e) {
+ logger.error("ArthasGrpcServer start error", e);
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
-
- private static void moveFile(File source, File target) throws IOException {
- if (!target.getParentFile().exists()) {
- target.getParentFile().mkdirs();
- }
- Files.move(source.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
- }
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
index 8f3daed1be..abfb30559e 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
@@ -22,14 +22,14 @@
*/
public class GrpcDispatcher {
- private static final String GRPC_SERVICE_PACKAGE_NAME = "com.taobao.arthas.grpc.server.service.impl";
+ private static final String DEFAULT_GRPC_SERVICE_PACKAGE_NAME = "com.taobao.arthas.grpc.server.service.impl";
private Map grpcMethodInvokeMap = new HashMap<>();
private Map grpcMethodStreamMap = new HashMap<>();
- public void loadGrpcService() {
- List> classes = ReflectUtil.findClasses(GRPC_SERVICE_PACKAGE_NAME);
+ public void loadGrpcService(String grpcServicePackageName) {
+ List> classes = ReflectUtil.findClasses(Optional.ofNullable(grpcServicePackageName).orElse(DEFAULT_GRPC_SERVICE_PACKAGE_NAME));
for (Class> clazz : classes) {
if (clazz.isAnnotationPresent(GrpcService.class)) {
try {
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
index feda7c3357..1f3b2a852a 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcRequest.java
@@ -96,52 +96,29 @@ public void clearData() {
byteData.clear();
}
- // todo 后续优化gzip处理
private byte[] decompressGzip(byte[] compressedData) {
boolean isGzip = (compressedData.length > 2 && (compressedData[0] & 0xff) == 0x1f && (compressedData[1] & 0xff) == 0x8b);
if (isGzip) {
- try {
- InputStream byteStream = new ByteArrayInputStream(compressedData);
- GZIPInputStream gzipStream = new GZIPInputStream(byteStream);
+ try (InputStream byteStream = new ByteArrayInputStream(compressedData);
+ GZIPInputStream gzipStream = new GZIPInputStream(byteStream);
+ ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+
byte[] buffer = new byte[1024];
int len;
- ByteArrayOutputStream out = new ByteArrayOutputStream();
while ((len = gzipStream.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
return out.toByteArray();
} catch (IOException e) {
System.err.println("Failed to decompress GZIP data: " + e.getMessage());
+ // Optionally rethrow the exception or return an Optional
+ return null; // or throw new RuntimeException(e);
}
- return null;
} else {
return compressedData;
}
}
- private ByteBuf decompressGzip(ByteBuf byteBuf) {
- byte[] compressedData = ByteUtil.getBytes(byteBuf);
- boolean isGzip = (compressedData.length > 2 && (compressedData[0] & 0xff) == 0x1f && (compressedData[1] & 0xff) == 0x8b);
- if (isGzip) {
- try {
- InputStream byteStream = new ByteArrayInputStream(compressedData);
- GZIPInputStream gzipStream = new GZIPInputStream(byteStream);
- byte[] buffer = new byte[1024];
- int len;
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- while ((len = gzipStream.read(buffer)) != -1) {
- out.write(buffer, 0, len);
- }
- return ByteUtil.newByteBuf(out.toByteArray());
- } catch (IOException e) {
- System.err.println("Failed to decompress GZIP data: " + e.getMessage());
- }
- return null;
- } else {
- return byteBuf;
- }
- }
-
public Integer getStreamId() {
return streamId;
}
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
index ff4c01a8b6..22eee788be 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/Http2Handler.java
@@ -1,5 +1,7 @@
package com.taobao.arthas.grpc.server.handler;
+import com.alibaba.arthas.deps.org.slf4j.Logger;
+import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
import com.taobao.arthas.grpc.server.utils.ByteUtil;
@@ -9,6 +11,7 @@
import io.netty.handler.codec.http2.*;
import java.io.*;
+import java.lang.invoke.MethodHandles;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -18,6 +21,8 @@
*/
public class Http2Handler extends SimpleChannelInboundHandler {
+ private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass().getName());
+
private GrpcDispatcher grpcDispatcher;
/**
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java
index f0ee0162bd..d4c23882e0 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/protobuf/utils/ProtoBufUtil.java
@@ -1,5 +1,7 @@
package com.taobao.arthas.grpc.server.protobuf.utils;
+import com.alibaba.arthas.deps.org.slf4j.Logger;
+import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.google.protobuf.*;
import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
import com.taobao.arthas.grpc.server.protobuf.ProtobufField;
@@ -13,6 +15,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.Enum;
+import java.lang.invoke.MethodHandles;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@@ -29,6 +32,8 @@
*/
public class ProtoBufUtil {
+ private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass().getName());
+
public static final Map, ProtobufFieldTypeEnum> TYPE_MAPPER;
public static final Map PRIMITIVE_TYPE_MAPPING;
@@ -81,9 +86,9 @@ public class ProtoBufUtil {
Set> primitiveTypeNames = new HashSet>(16);
primitiveTypeNames.addAll(PRIMITIVE_WRAPPER_TYPE_MAP.values());
- primitiveTypeNames.addAll(Arrays.asList(new Class>[] { boolean[].class, byte[].class, char[].class,
- double[].class, float[].class, int[].class, long[].class, short[].class }));
- for (Iterator> it = primitiveTypeNames.iterator(); it.hasNext();) {
+ primitiveTypeNames.addAll(Arrays.asList(new Class>[]{boolean[].class, byte[].class, char[].class,
+ double[].class, float[].class, int[].class, long[].class, short[].class}));
+ for (Iterator> it = primitiveTypeNames.iterator(); it.hasNext(); ) {
Class> primitiveClass = (Class>) it.next();
PRIMIIIVE_TYPE_CLASS_MAPPING.put(primitiveClass.getName(), primitiveClass);
}
@@ -289,7 +294,7 @@ public static Object getField(Object t, String name) {
try {
return field.get(t);
} catch (Exception e) {
- //todo log
+ logger.error("ProtoBufUtil getFiled error, t:{}, name:{}", t, name, e);
}
return null;
}
@@ -303,7 +308,7 @@ public static void setField(Object t, String name, Object value) {
try {
field.set(t, value);
} catch (Exception e) {
- //todo log
+ logger.error("ProtoBufUtil setFiled error, t:{}, name:{}, value:{}", t, name, value, e);
}
}
@@ -376,7 +381,7 @@ public static String getGetterDynamicString(ProtobufField protobufField, Class
dynamicTargetClass.getMethod(getter, new Class>[0]);
return DYNAMIC_TARGET + PACKAGE_SEPARATOR + getter + "()";
} catch (Exception e) {
- //todo log
+ logger.error("ProtoBufUtil getGetterDynamicString error, protobufField:{}, dynamicTargetClass:{}", protobufField, dynamicTargetClass, e);
}
String type = field.getType().getCanonicalName();
@@ -427,7 +432,6 @@ public static String getSizeDynamicString(ProtobufField field) {
}
javaType = capitalize(javaType);
dynamicFieldName = dynamicFieldName + protobufFieldType.getToPrimitiveType();
- //todo check 感觉上面这个有点问题,测试的时候看下
return "com.google.protobuf.CodedOutputStream.compute" + javaType + "Size(" + order + "," + dynamicFieldName
+ ");" + LINE_BREAK;
}
@@ -859,7 +863,7 @@ public static String getSetFieldDynamicString(ProtobufField protobufField, Class
return DYNAMIC_TARGET + PACKAGE_SEPARATOR + setter + "(" + express + ")\n";
} catch (Exception e) {
- //todo log
+ logger.error("ProtoBufUtil getSetFieldDynamicString error, protobufField:{}, dynamicTargetClass:{}, express:{}", protobufField, dynamicTargetClass, express, e);
}
if (isList) {
@@ -1103,7 +1107,7 @@ public static String getClassName(Class> cls) {
return cls.getSimpleName();
}
- public static boolean isEmpty(String s){
+ public static boolean isEmpty(String s) {
return s == null || s.isEmpty();
}
diff --git a/arthas-grpc-server/src/test/java/unittest/grpc/GrpcTest.java b/arthas-grpc-server/src/test/java/unittest/grpc/GrpcTest.java
index d6d57b12e0..fcb46576c6 100644
--- a/arthas-grpc-server/src/test/java/unittest/grpc/GrpcTest.java
+++ b/arthas-grpc-server/src/test/java/unittest/grpc/GrpcTest.java
@@ -2,11 +2,15 @@
import arthas.unittest.ArthasUnittest;
import arthas.unittest.ArthasUnittestServiceGrpc;
+import com.taobao.arthas.grpc.server.ArthasGrpcServer;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;
+import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import java.util.concurrent.CountDownLatch;
@@ -17,14 +21,25 @@
* @description: GrpcUnaryTest
*/
public class GrpcTest {
- private static final String target = "localhost:9090";
+ private static final String HOST = "localhost";
+ private static final int PORT = 9090;
+ private static final String HOST_PORT = HOST + ":" + PORT;
+ private static final String UNIT_TEST_GRPC_SERVICE_PACKAGE_NAME = "unittest.grpc.service.impl";
private ArthasUnittestServiceGrpc.ArthasUnittestServiceBlockingStub blockingStub = null;
private ArthasUnittestServiceGrpc.ArthasUnittestServiceStub stub = null;
- @Disabled("跳过启动测试")
+ @Before
+ public void startServer() {
+ Thread grpcWebProxyStart = new Thread(() -> {
+ ArthasGrpcServer arthasGrpcServer = new ArthasGrpcServer(PORT, UNIT_TEST_GRPC_SERVICE_PACKAGE_NAME);
+ arthasGrpcServer.start();
+ });
+ grpcWebProxyStart.start();
+ }
+
@Test
public void testUnary() {
- ManagedChannel channel = ManagedChannelBuilder.forTarget(target)
+ ManagedChannel channel = ManagedChannelBuilder.forTarget(HOST_PORT)
.usePlaintext()
.build();
@@ -37,10 +52,9 @@ public void testUnary() {
}
}
- @Disabled("跳过启动测试")
@Test
public void testStream() {
- ManagedChannel channel = ManagedChannelBuilder.forTarget(target)
+ ManagedChannel channel = ManagedChannelBuilder.forTarget(HOST_PORT)
.usePlaintext()
.build();
@@ -55,16 +69,11 @@ public void testStream() {
private void trace(String name) {
ArthasUnittest.ArthasUnittestRequest request = ArthasUnittest.ArthasUnittestRequest.newBuilder().setMessage(name).build();
- try {
- ArthasUnittest.ArthasUnittestResponse res = blockingStub.trace(request);
- System.out.println(res.getMessage());
- } catch (StatusRuntimeException e) {
- e.printStackTrace();
- System.out.println("RPC failed: " + e.getStatus());
- }
+ ArthasUnittest.ArthasUnittestResponse res = blockingStub.trace(request);
+ System.out.println(res.getMessage());
}
- private void watch(String... names) {
+ private void watch(String... names){
// 使用 CountDownLatch 来等待所有响应
CountDownLatch finishLatch = new CountDownLatch(1);
@@ -92,17 +101,18 @@ public void onCompleted() {
Thread.sleep(1000L);
watch.onNext(request);
}
- } catch (Exception e) {
- throw new RuntimeException(e);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
} finally {
watch.onCompleted();
+ finishLatch.countDown();
}
// 等待服务器的响应
try {
finishLatch.await(); // 等待完成
} catch (InterruptedException e) {
- System.out.println("Client interrupted: " + e.getMessage());
+ e.printStackTrace();
}
}
}
diff --git a/arthas-grpc-server/src/test/java/unittest/grpc/Http2HandlerTest.java b/arthas-grpc-server/src/test/java/unittest/grpc/Http2HandlerTest.java
new file mode 100644
index 0000000000..97edfa5220
--- /dev/null
+++ b/arthas-grpc-server/src/test/java/unittest/grpc/Http2HandlerTest.java
@@ -0,0 +1,9 @@
+package unittest.grpc;
+
+/**
+ * @author: FengYe
+ * @date: 2024/10/12 00:56
+ * @description: Http2HandlerTest
+ */
+public class Http2HandlerTest {
+}
diff --git a/arthas-grpc-server/src/test/java/unittest/grpc/TempTest.java b/arthas-grpc-server/src/test/java/unittest/grpc/TempTest.java
new file mode 100644
index 0000000000..754b7d92ef
--- /dev/null
+++ b/arthas-grpc-server/src/test/java/unittest/grpc/TempTest.java
@@ -0,0 +1,36 @@
+package unittest.grpc;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author: FengYe
+ * @date: 2024/10/13 03:03
+ * @description: TempTest
+ */
+public class TempTest {
+
+ private int num;
+
+ @Before
+ public void before() throws InterruptedException {
+ System.out.println("before start,"+num++);
+ System.out.println(Thread.currentThread().getId());
+ Thread.sleep(10000L);
+ System.out.println("before end");
+ }
+
+ @Test
+ public void test1() throws InterruptedException {
+ System.out.println("test1 start");
+ Thread.sleep(1000L);
+ System.out.println("test1 end");
+ }
+
+ @Test
+ public void test2() throws InterruptedException {
+ System.out.println("test2 start");
+ Thread.sleep(1000L);
+ System.out.println("test2 end");
+ }
+}
diff --git a/arthas-grpc-server/src/test/java/unittest/grpc/service/ArthasSampleService.java b/arthas-grpc-server/src/test/java/unittest/grpc/service/ArthasSampleService.java
new file mode 100644
index 0000000000..4830fc9c51
--- /dev/null
+++ b/arthas-grpc-server/src/test/java/unittest/grpc/service/ArthasSampleService.java
@@ -0,0 +1,14 @@
+package unittest.grpc.service;
+
+import unittest.grpc.service.req.ArthasUnittestRequest;
+import unittest.grpc.service.res.ArthasUnittestResponse;
+
+/**
+ * @author: FengYe
+ * @date: 2024/6/30 下午11:42
+ * @description: ArthasSampleService
+ */
+public interface ArthasSampleService {
+ ArthasUnittestResponse trace(ArthasUnittestRequest command);
+ ArthasUnittestResponse watch(ArthasUnittestRequest command);
+}
diff --git a/arthas-grpc-server/src/test/java/unittest/grpc/service/impl/ArthasSampleServiceImpl.java b/arthas-grpc-server/src/test/java/unittest/grpc/service/impl/ArthasSampleServiceImpl.java
new file mode 100644
index 0000000000..4ed9cc6e73
--- /dev/null
+++ b/arthas-grpc-server/src/test/java/unittest/grpc/service/impl/ArthasSampleServiceImpl.java
@@ -0,0 +1,32 @@
+package unittest.grpc.service.impl;
+
+import com.taobao.arthas.grpc.server.handler.annotation.GrpcMethod;
+import com.taobao.arthas.grpc.server.handler.annotation.GrpcService;
+import unittest.grpc.service.ArthasSampleService;
+import unittest.grpc.service.req.ArthasUnittestRequest;
+import unittest.grpc.service.res.ArthasUnittestResponse;
+
+/**
+ * @author: FengYe
+ * @date: 2024/6/30 下午11:43
+ * @description: ArthasSampleServiceImpl
+ */
+@GrpcService("arthas.unittest.ArthasUnittestService")
+public class ArthasSampleServiceImpl implements ArthasSampleService {
+
+ @Override
+ @GrpcMethod("trace")
+ public ArthasUnittestResponse trace(ArthasUnittestRequest command) {
+ ArthasUnittestResponse arthasUnittestResponse = new ArthasUnittestResponse();
+ arthasUnittestResponse.setMessage(command.getMessage());
+ return arthasUnittestResponse;
+ }
+
+ @Override
+ @GrpcMethod(value = "watch", stream = true)
+ public ArthasUnittestResponse watch(ArthasUnittestRequest command) {
+ ArthasUnittestResponse arthasUnittestResponse = new ArthasUnittestResponse();
+ arthasUnittestResponse.setMessage(command.getMessage());
+ return arthasUnittestResponse;
+ }
+}
\ No newline at end of file
diff --git a/arthas-grpc-server/src/test/java/unittest/grpc/service/req/ArthasUnittestRequest.java b/arthas-grpc-server/src/test/java/unittest/grpc/service/req/ArthasUnittestRequest.java
new file mode 100644
index 0000000000..018e15490e
--- /dev/null
+++ b/arthas-grpc-server/src/test/java/unittest/grpc/service/req/ArthasUnittestRequest.java
@@ -0,0 +1,21 @@
+package unittest.grpc.service.req;
+
+import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
+
+/**
+ * @author: FengYe
+ * @date: 2024/7/14 上午4:28
+ * @description: ArthasSampleRequest
+ */
+@ProtobufClass
+public class ArthasUnittestRequest {
+ private String message;
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/arthas-grpc-server/src/test/java/unittest/grpc/service/res/ArthasUnittestResponse.java b/arthas-grpc-server/src/test/java/unittest/grpc/service/res/ArthasUnittestResponse.java
new file mode 100644
index 0000000000..f340c3844d
--- /dev/null
+++ b/arthas-grpc-server/src/test/java/unittest/grpc/service/res/ArthasUnittestResponse.java
@@ -0,0 +1,21 @@
+package unittest.grpc.service.res;
+
+import com.taobao.arthas.grpc.server.protobuf.annotation.ProtobufClass;
+
+/**
+ * @author: FengYe
+ * @date: 2024/8/11 22:11
+ * @description: ArthasSampleResponse
+ */
+@ProtobufClass
+public class ArthasUnittestResponse {
+ private String message;
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/arthas-grpc-server/src/test/proto/arthasUnittest.proto b/arthas-grpc-server/src/test/proto/arthasUnittest.proto
new file mode 100644
index 0000000000..731c0f1e63
--- /dev/null
+++ b/arthas-grpc-server/src/test/proto/arthasUnittest.proto
@@ -0,0 +1,16 @@
+syntax = "proto3";
+
+package arthas.unittest;
+
+service ArthasUnittestService {
+ rpc trace(ArthasUnittestRequest) returns (ArthasUnittestResponse);
+ rpc watch(stream ArthasUnittestRequest) returns (stream ArthasUnittestResponse);
+}
+
+message ArthasUnittestRequest {
+ string message = 1;
+}
+
+message ArthasUnittestResponse{
+ string message = 1;
+}
From 45b6027b926089728ce32c6beebb73c7659c2749 Mon Sep 17 00:00:00 2001
From: summer <1129126684@qq.com>
Date: Tue, 15 Oct 2024 03:01:34 +0800
Subject: [PATCH 38/48] update: Migration from jprotobuf serialization to
protobuf:protoc; migrating the business logic in http2Handler to a custom
executorGroup; added http2 headers in grpcRequest; support for handling
resetStream
---
.../arthas/grpc/server/ArthasGrpcServer.java | 4 +-
.../arthas/grpc/server/handler/ErrorRes.java | 1 +
.../grpc/server/handler/GrpcDispatcher.java | 59 ++++++-----
.../grpc/server/handler/GrpcRequest.java | 14 +++
.../grpc/server/handler/GrpcResponse.java | 42 ++++++--
.../grpc/server/handler/Http2Handler.java | 99 +++++++++++--------
.../grpc/server/protobuf/ProtobufCodec.java | 1 +
.../grpc/server/protobuf/ProtobufField.java | 1 +
.../protobuf/ProtobufFieldTypeEnum.java | 1 +
.../grpc/server/protobuf/ProtobufProxy.java | 1 +
.../protobuf/annotation/ProtobufClass.java | 1 +
.../annotation/ProtobufCustomizedField.java | 1 +
.../annotation/ProtobufEnableZigZap.java | 1 +
.../protobuf/annotation/ProtobufIgnore.java | 1 +
.../protobuf/annotation/ProtobufPacked.java | 1 +
.../server/service/ArthasSampleService.java | 7 +-
.../service/impl/ArthasSampleServiceImpl.java | 26 ++---
.../service/req/ArthasUnittestRequest.java | 21 ----
.../service/res/ArthasUnittestResponse.java | 21 ----
.../src/main/proto/arthasGrpc.proto | 7 ++
.../src/main/proto/arthasUnittest.proto | 2 +-
.../src/test/java/unittest/grpc/GrpcTest.java | 4 +-
.../grpc/service/ArthasSampleService.java | 7 +-
.../service/impl/ArthasSampleServiceImpl.java | 26 ++---
.../service/req/ArthasUnittestRequest.java | 21 ----
.../service/res/ArthasUnittestResponse.java | 21 ----
.../src/test/proto/arthasUnittest.proto | 2 +-
27 files changed, 202 insertions(+), 191 deletions(-)
delete mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/req/ArthasUnittestRequest.java
delete mode 100644 arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/service/res/ArthasUnittestResponse.java
create mode 100644 arthas-grpc-server/src/main/proto/arthasGrpc.proto
delete mode 100644 arthas-grpc-server/src/test/java/unittest/grpc/service/req/ArthasUnittestRequest.java
delete mode 100644 arthas-grpc-server/src/test/java/unittest/grpc/service/res/ArthasUnittestResponse.java
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
index 3425657256..f46f4dda5b 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/ArthasGrpcServer.java
@@ -15,6 +15,8 @@
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http2.Http2FrameCodecBuilder;
+import io.netty.util.concurrent.DefaultEventExecutorGroup;
+import io.netty.util.concurrent.EventExecutorGroup;
import java.lang.invoke.MethodHandles;
@@ -38,7 +40,7 @@ public ArthasGrpcServer(int port, String grpcServicePackageName) {
public void start() {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
- EventLoopGroup workerGroup = new NioEventLoopGroup();
+ EventLoopGroup workerGroup = new NioEventLoopGroup(10);
GrpcDispatcher grpcDispatcher = new GrpcDispatcher();
grpcDispatcher.loadGrpcService(grpcServicePackageName);
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/ErrorRes.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/ErrorRes.java
index c7cbe8d7ea..5045283271 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/ErrorRes.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/ErrorRes.java
@@ -8,6 +8,7 @@
* @description: ErrorRes
*/
@ProtobufClass
+@Deprecated
public class ErrorRes {
private String errorMsg;
diff --git a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
index abfb30559e..2a0185f568 100644
--- a/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
+++ b/arthas-grpc-server/src/main/java/com/taobao/arthas/grpc/server/handler/GrpcDispatcher.java
@@ -1,9 +1,9 @@
package com.taobao.arthas.grpc.server.handler;
+
import com.taobao.arthas.grpc.server.handler.annotation.GrpcMethod;
import com.taobao.arthas.grpc.server.handler.annotation.GrpcService;
-import com.taobao.arthas.grpc.server.protobuf.ProtobufCodec;
-import com.taobao.arthas.grpc.server.protobuf.ProtobufProxy;
+import com.taobao.arthas.grpc.server.utils.ByteUtil;
import com.taobao.arthas.grpc.server.utils.ReflectUtil;
import java.lang.invoke.MethodHandle;
@@ -22,11 +22,17 @@
*/
public class GrpcDispatcher {
- private static final String DEFAULT_GRPC_SERVICE_PACKAGE_NAME = "com.taobao.arthas.grpc.server.service.impl";
+ public static final String DEFAULT_GRPC_SERVICE_PACKAGE_NAME = "com.taobao.arthas.grpc.server.service.impl";
+
+ public static Map grpcMethodInvokeMap = new HashMap<>();
+
+ public static Map requestParseFromMap = new HashMap<>();
+ public static Map requestToByteArrayMap = new HashMap<>();
- private Map grpcMethodInvokeMap = new HashMap<>();
+ public static Map responseParseFromMap = new HashMap<>();
+ public static Map responseToByteArrayMap = new HashMap<>();
- private Map grpcMethodStreamMap = new HashMap<>();
+ public static Map grpcMethodStreamMap = new HashMap<>();
public void loadGrpcService(String grpcServicePackageName) {
List