From 326f56fe1e5ffafbd62d5ccf98fe2502042b0c66 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Tue, 30 Jun 2020 19:57:10 +0800 Subject: [PATCH 01/18] transform commands of pkg klass100: classloader, dump, getstatic, jad, mc, ognl, redefine, sc, sm --- .../command/klass100/ClassLoaderCommand.java | 241 +++++++++-------- .../command/klass100/DumpClassCommand.java | 76 +++--- .../command/klass100/GetStaticCommand.java | 71 +++-- .../core/command/klass100/JadCommand.java | 80 +++--- .../klass100/MemoryCompilerCommand.java | 20 +- .../core/command/klass100/OgnlCommand.java | 15 +- .../command/klass100/RedefineCommand.java | 27 +- .../command/klass100/SearchClassCommand.java | 49 ++-- .../command/klass100/SearchMethodCommand.java | 74 ++---- .../core/command/model/ClassLoaderModel.java | 93 +++++++ .../core/command/model/ClassLoaderVO.java | 78 ++++++ .../arthas/core/command/model/ClassSetVO.java | 51 ++++ .../arthas/core/command/model/ClassVO.java | 197 ++++++++++++++ .../core/command/model/DumpClassModel.java | 41 +++ .../arthas/core/command/model/FieldVO.java | 61 +++++ .../core/command/model/GetStaticModel.java | 56 ++++ .../arthas/core/command/model/JadModel.java | 55 ++++ .../command/model/MemoryCompilerModel.java | 32 +++ .../arthas/core/command/model/MethodVO.java | 99 +++++++ .../arthas/core/command/model/ObjectVO.java | 34 +++ .../arthas/core/command/model/OgnlModel.java | 33 +++ .../core/command/model/RedefineModel.java | 45 ++++ .../core/command/model/RowAffectModel.java | 30 +++ .../core/command/model/SearchClassModel.java | 74 ++++++ .../core/command/model/SearchMethodModel.java | 40 +++ .../core/command/view/ClassLoaderView.java | 140 ++++++++++ .../core/command/view/DumpClassView.java | 51 ++++ .../core/command/view/GetStaticView.java | 29 +++ .../arthas/core/command/view/JadView.java | 42 +++ .../core/command/view/MemoryCompilerView.java | 17 ++ .../arthas/core/command/view/OgnlView.java | 19 ++ .../core/command/view/RedefineView.java | 22 ++ .../core/command/view/ResultViewResolver.java | 9 + .../core/command/view/RowAffectView.java | 14 + .../core/command/view/SearchClassView.java | 26 ++ .../core/command/view/SearchMethodView.java | 39 +++ .../taobao/arthas/core/util/ClassUtils.java | 244 ++++++++++++++++++ .../taobao/arthas/core/util/ResultUtils.java | 50 ++++ .../taobao/arthas/core/util/StringUtils.java | 20 +- .../arthas/core/util/TypeRenderUtils.java | 155 +++++++++++ 40 files changed, 2216 insertions(+), 333 deletions(-) create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderVO.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/ClassSetVO.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/ClassVO.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/DumpClassModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/FieldVO.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/GetStaticModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/JadModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/MemoryCompilerModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/MethodVO.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/ObjectVO.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/OgnlModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/RedefineModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/RowAffectModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/SearchClassModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/SearchMethodModel.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/ClassLoaderView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/DumpClassView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/GetStaticView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/JadView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/MemoryCompilerView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/OgnlView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/RedefineView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/RowAffectView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/SearchClassView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/view/SearchMethodView.java create mode 100644 core/src/main/java/com/taobao/arthas/core/util/ResultUtils.java diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java index d6c9f6fcd07..a9020d400c6 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java @@ -1,28 +1,31 @@ package com.taobao.arthas.core.command.klass100; +import com.alibaba.arthas.deps.org.slf4j.Logger; +import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.ClassLoaderModel; +import com.taobao.arthas.core.command.model.ClassLoaderVO; +import com.taobao.arthas.core.command.model.ClassSetVO; +import com.taobao.arthas.core.command.model.ClassVO; +import com.taobao.arthas.core.command.model.MessageModel; +import com.taobao.arthas.core.command.model.RowAffectModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.shell.handlers.Handler; import com.taobao.arthas.core.util.ClassUtils; -import com.taobao.arthas.core.util.StringUtils; +import com.taobao.arthas.core.util.ResultUtils; import com.taobao.arthas.core.util.affect.RowAffect; -import com.taobao.arthas.core.view.ObjectView; import com.taobao.middleware.cli.annotations.Description; import com.taobao.middleware.cli.annotations.Name; import com.taobao.middleware.cli.annotations.Option; import com.taobao.middleware.cli.annotations.Summary; -import com.taobao.text.Decoration; -import com.taobao.text.ui.Element; -import com.taobao.text.ui.LabelElement; -import com.taobao.text.ui.RowElement; -import com.taobao.text.ui.TableElement; -import com.taobao.text.ui.TreeElement; -import com.taobao.text.util.RenderUtil; import java.lang.instrument.Instrumentation; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; @@ -35,6 +38,7 @@ import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicBoolean; @Name("classloader") @Summary("Show classloader info") @@ -49,6 +53,8 @@ " classloader -c 659e0bfd --load demo.MathGame\n" + Constants.WIKI + Constants.WIKI_HOME + "classloader") public class ClassLoaderCommand extends AnnotatedCommand { + + private Logger logger = LoggerFactory.getLogger(ClassLoaderCommand.class); private boolean isTree = false; private String hashCode; private boolean all = false; @@ -58,6 +64,8 @@ public class ClassLoaderCommand extends AnnotatedCommand { private String loadClass = null; + private AtomicBoolean isInterrupted = new AtomicBoolean(false); + @Option(shortName = "t", longName = "tree", flag = true) @Description("Display ClassLoader tree") public void setTree(boolean tree) { @@ -102,6 +110,9 @@ public void setLoadClass(String className) { @Override public void process(CommandProcess process) { + // ctrl-C support + process.interruptHandler(new ClassLoaderInterruptHandler(process, isInterrupted)); + Instrumentation inst = process.session().getInstrumentation(); if (all) { processAllClasses(process, inst); @@ -143,12 +154,10 @@ private void processClassLoaderStats(CommandProcess process, Instrumentation ins TreeMap sorted = new TreeMap(new ValueComparator(classLoaderStats)); sorted.putAll(classLoaderStats); + process.appendResult(new ClassLoaderModel().setClassLoaderStats(sorted)); - Element element = renderStat(sorted); - process.write(RenderUtil.render(element, process.width())) - .write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); affect.rCnt(sorted.keySet().size()); - process.write(affect + "\n"); + process.appendResult(new RowAffectModel(affect)); process.end(); } @@ -156,27 +165,45 @@ private void processClassLoaders(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); List classLoaderInfos = includeReflectionClassLoader ? getAllClassLoaderInfo(inst) : getAllClassLoaderInfo(inst, new SunReflectionClassLoaderFilter()); - Element element = isTree ? renderTree(classLoaderInfos) : renderTable(classLoaderInfos); - process.write(RenderUtil.render(element, process.width())) - .write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); + + List classLoaderVOs = new ArrayList(classLoaderInfos.size()); + for (ClassLoaderInfo classLoaderInfo : classLoaderInfos) { + ClassLoaderVO classLoaderVO = ClassUtils.createClassLoaderVO(classLoaderInfo.classLoader); + classLoaderVO.setLoadedCount(classLoaderInfo.loadedClassCount()); + classLoaderVOs.add(classLoaderVO); + } + if (isTree){ + classLoaderVOs = processClassLoaderTree(classLoaderVOs); + } + process.appendResult(new ClassLoaderModel().setClassLoaders(classLoaderVOs).setTree(isTree)); + affect.rCnt(classLoaderInfos.size()); - process.write(affect + "\n"); + process.appendResult(new RowAffectModel(affect)); process.end(); } // 根据 hashCode 来打印URLClassLoader的urls private void processClassLoader(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); - Set allClassLoader = getAllClassLoaders(inst); for (ClassLoader cl : allClassLoader) { if (Integer.toHexString(cl.hashCode()).equals(hashCode)) { - process.write(RenderUtil.render(renderClassLoaderUrls(cl), process.width())); + if (cl instanceof URLClassLoader) { + List classLoaderUrls = getClassLoaderUrls(cl); + affect.rCnt(classLoaderUrls.size()); + if (classLoaderUrls.isEmpty()){ + process.appendResult(new MessageModel("urls is empty.")); + } else { + process.appendResult(new ClassLoaderModel().setUrls(classLoaderUrls)); + affect.rCnt(classLoaderUrls.size()); + } + } else { + process.appendResult(new MessageModel("not a URLClassLoader.")); } + break; } - process.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); - affect.rCnt(allClassLoader.size()); - process.write(affect + "\n"); + } + process.appendResult(new RowAffectModel(affect)); process.end(); } @@ -185,25 +212,25 @@ private void processResources(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); int rowCount = 0; Set allClassLoader = getAllClassLoaders(inst); + List resources = new ArrayList(); for (ClassLoader cl : allClassLoader) { if (Integer.toHexString(cl.hashCode()).equals(hashCode)) { - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); try { Enumeration urls = cl.getResources(resource); while (urls.hasMoreElements()) { URL url = urls.nextElement(); - table.row(url.toString()); + resources.add(url.toString()); rowCount++; } } catch (Throwable e) { - e.printStackTrace(); + logger.warn("get resource failed, resource: {}", resource, e); } - process.write(RenderUtil.render(table, process.width()) + "\n"); } } - process.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); affect.rCnt(rowCount); - process.write(affect + "\n"); + + process.appendResult(new ClassLoaderModel().setResources(resources)); + process.appendResult(new RowAffectModel(affect)); process.end(); } @@ -214,36 +241,46 @@ private void processLoadClass(CommandProcess process, Instrumentation inst) { if (Integer.toHexString(cl.hashCode()).equals(hashCode)) { try { Class clazz = cl.loadClass(this.loadClass); - process.write("load class success.\n"); - process.write(RenderUtil.render(ClassUtils.renderClassInfo(clazz), process.width()) + "\n"); + process.appendResult(new MessageModel("load class success.")); + ClassVO classInfo = ClassUtils.createClassInfo(clazz, true, false); + process.appendResult(new ClassLoaderModel().setLoadClass(classInfo)); } catch (Throwable e) { - e.printStackTrace(); - process.write("load class error.\n" + StringUtils.objectToString(new ObjectView(e, 1).draw())); + logger.warn("load class error, class: {}", this.loadClass, e); + process.end(-1, "load class error, class:"+this.loadClass+", error: "+e.toString()); + break; } } } - process.write("\n"); process.end(); } private void processAllClasses(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); - process.write(RenderUtil.render(renderClasses(hashCode, inst), process.width())); - process.write(affect + "\n"); + getAllClasses(hashCode, inst, affect, process); + if (checkInterrupted(process)) { + return; + } + process.appendResult(new RowAffectModel(affect)); process.end(); } + private boolean checkInterrupted(CommandProcess process) { + if (isInterrupted.get()) { + process.end(1, "Interrupted by user"); + return true; + } + return false; + } + /** * 获取到所有的class, 还有它们的classloader,按classloader归类好,统一输出每个classloader里有哪些class *

* 当hashCode是null,则把所有的classloader的都打印 * - * @param hashCode - * @return */ @SuppressWarnings("rawtypes") - private static Element renderClasses(String hashCode, Instrumentation inst) { + private void getAllClasses(String hashCode, Instrumentation inst, RowAffect affect, CommandProcess process) { int hashCodeInt = -1; if (hashCode != null) { hashCodeInt = Integer.valueOf(hashCode, 16); @@ -285,99 +322,71 @@ public int compare(Class o1, Class o2) { classSet.add(clazz); } - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - - if (!bootstrapClassSet.isEmpty()) { - table.row(new LabelElement("hash:null, BootstrapClassLoader").style(Decoration.bold.bold())); - for (Class clazz : bootstrapClassSet) { - table.row(new LabelElement(clazz.getName())); - } - table.row(new LabelElement(" ")); - } + //convert to vo + int pageSize = 256; + processClassSet(process, ClassUtils.createClassLoaderVO(null), bootstrapClassSet, pageSize); + affect.rCnt(bootstrapClassSet.size()); for (Entry> entry : classLoaderClassMap.entrySet()) { + if (checkInterrupted(process)) { + return; + } ClassLoader classLoader = entry.getKey(); SortedSet classSet = entry.getValue(); - - table.row(new LabelElement("hash:" + classLoader.hashCode() + ", " + classLoader.toString()) - .style(Decoration.bold.bold())); - for (Class clazz : classSet) { - table.row(new LabelElement(clazz.getName())); + processClassSet(process, ClassUtils.createClassLoaderVO(classLoader), classSet, pageSize); + affect.rCnt(classSet.size()); + } } - table.row(new LabelElement(" ")); + private void processClassSet(final CommandProcess process, final ClassLoaderVO classLoaderVO, Collection classes, int pageSize) { + + ResultUtils.processClassNames(classes, pageSize, new ResultUtils.PaginationHandler>() { + @Override + public boolean handle(List classNames, int segment) { + process.appendResult(new ClassLoaderModel().setClassSet(new ClassSetVO(classLoaderVO, classNames, segment))); + return !checkInterrupted(process); } - return table; + }); } - private static Element renderClassLoaderUrls(ClassLoader classLoader) { - StringBuilder sb = new StringBuilder(); + private static List getClassLoaderUrls(ClassLoader classLoader) { + List urlStrs = new ArrayList(); if (classLoader instanceof URLClassLoader) { URLClassLoader cl = (URLClassLoader) classLoader; URL[] urls = cl.getURLs(); if (urls != null) { for (URL url : urls) { - sb.append(url.toString() + "\n"); + urlStrs.add(url.toString()); } - return new LabelElement(sb.toString()); - } else { - return new LabelElement("urls is empty."); } - } else { - return new LabelElement("not a URLClassLoader.\n"); } + return urlStrs; } // 以树状列出ClassLoader的继承结构 - private static Element renderTree(List classLoaderInfos) { - TreeElement root = new TreeElement(); - - List parentNullClassLoaders = new ArrayList(); - List parentNotNullClassLoaders = new ArrayList(); - for (ClassLoaderInfo info : classLoaderInfos) { - if (info.parent() == null) { - parentNullClassLoaders.add(info); + private static List processClassLoaderTree(List classLoaders) { + List rootClassLoaders = new ArrayList(); + List parentNotNullClassLoaders = new ArrayList(); + for (ClassLoaderVO classLoaderVO : classLoaders) { + if (classLoaderVO.getParent() == null) { + rootClassLoaders.add(classLoaderVO); } else { - parentNotNullClassLoaders.add(info); + parentNotNullClassLoaders.add(classLoaderVO); } } - for (ClassLoaderInfo info : parentNullClassLoaders) { - if (info.parent() == null) { - TreeElement parent = new TreeElement(info.getName()); - renderParent(parent, info, parentNotNullClassLoaders); - root.addChild(parent); - } - } - - return root; - } - - // 统计所有的ClassLoader的信息 - private static TableElement renderTable(List classLoaderInfos) { - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - table.add(new RowElement().style(Decoration.bold.bold()).add("name", "loadedCount", "hash", "parent")); - for (ClassLoaderInfo info : classLoaderInfos) { - table.row(info.getName(), "" + info.loadedClassCount(), info.hashCodeStr(), info.parentStr()); - } - return table; + for (ClassLoaderVO classLoaderVO : rootClassLoaders) { + buildTree(classLoaderVO, parentNotNullClassLoaders); } - private static TableElement renderStat(Map classLoaderStats) { - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - table.add(new RowElement().style(Decoration.bold.bold()).add("name", "numberOfInstances", "loadedCountTotal")); - for (Map.Entry entry : classLoaderStats.entrySet()) { - table.row(entry.getKey(), "" + entry.getValue().getNumberOfInstance(), "" + entry.getValue().getLoadedCount()); - } - return table; + return rootClassLoaders; } - private static void renderParent(TreeElement node, ClassLoaderInfo parent, List classLoaderInfos) { - for (ClassLoaderInfo info : classLoaderInfos) { - if (info.parent() == parent.classLoader) { - TreeElement child = new TreeElement(info.getName()); - node.addChild(child); - renderParent(child, info, classLoaderInfos); + private static void buildTree(ClassLoaderVO parent, List parentNotNullClassLoaders) { + for (ClassLoaderVO classLoaderVO : parentNotNullClassLoaders) { + if (parent.getName().equals(classLoaderVO.getParent())){ + parent.addChild(classLoaderVO); + buildTree(classLoaderVO, parentNotNullClassLoaders); } } } @@ -532,15 +541,16 @@ private interface Filter { } private static class SunReflectionClassLoaderFilter implements Filter { - private static final String REFLECTION_CLASSLOADER = "sun.reflect.DelegatingClassLoader"; + private static final List REFLECTION_CLASSLOADERS = Arrays.asList("sun.reflect.DelegatingClassLoader", + "jdk.internal.reflect.DelegatingClassLoader"); @Override public boolean accept(ClassLoader classLoader) { - return !REFLECTION_CLASSLOADER.equals(classLoader.getClass().getName()); + return !REFLECTION_CLASSLOADERS.contains(classLoader.getClass().getName()); } } - private static class ClassLoaderStat { + public static class ClassLoaderStat { private int loadedCount; private int numberOfInstance; @@ -552,11 +562,11 @@ void addNumberOfInstance(int count) { this.numberOfInstance += count; } - int getLoadedCount() { + public int getLoadedCount() { return loadedCount; } - int getNumberOfInstance() { + public int getNumberOfInstance() { return numberOfInstance; } } @@ -583,4 +593,19 @@ public int compare(String o1, String o2) { return unsortedStats.get(o2).getLoadedCount() - unsortedStats.get(o1).getLoadedCount(); } } + + private class ClassLoaderInterruptHandler implements Handler { + private final CommandProcess process; + private final AtomicBoolean isInterrupted; + + public ClassLoaderInterruptHandler(CommandProcess process, AtomicBoolean isInterrupted) { + this.process = process; + this.isInterrupted = isInterrupted; + } + + @Override + public void handle(Void event) { + isInterrupted.set(true); + } + } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java index 6687d6a2430..b1b1cb36f9b 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java @@ -3,14 +3,18 @@ import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.ClassVO; +import com.taobao.arthas.core.command.model.DumpClassModel; +import com.taobao.arthas.core.command.model.MessageModel; +import com.taobao.arthas.core.command.model.RowAffectModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.util.ClassUtils; import com.taobao.arthas.core.util.InstrumentationUtils; import com.taobao.arthas.core.util.SearchUtils; -import com.taobao.arthas.core.util.StringUtils; -import com.taobao.arthas.core.util.TypeRenderUtils; import com.taobao.arthas.core.util.affect.RowAffect; import com.taobao.middleware.cli.annotations.Argument; import com.taobao.middleware.cli.annotations.DefaultValue; @@ -18,19 +22,15 @@ import com.taobao.middleware.cli.annotations.Name; import com.taobao.middleware.cli.annotations.Option; import com.taobao.middleware.cli.annotations.Summary; -import com.taobao.text.Color; -import com.taobao.text.Decoration; -import com.taobao.text.ui.LabelElement; -import com.taobao.text.ui.TableElement; -import com.taobao.text.util.RenderUtil; import java.io.File; import java.lang.instrument.Instrumentation; import java.lang.instrument.UnmodifiableClassException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Set; -import static com.taobao.text.ui.Element.label; /** * Dump class byte array @@ -89,28 +89,27 @@ public void setLimit(int limit) { @Override public void process(CommandProcess process) { RowAffect effect = new RowAffect(); - + StatusModel statusModel = new StatusModel(-1, "unknown error"); try { if (directory != null) { File dir = new File(directory); if (dir.isFile()) { - process.write(directory + " :is not a directory, please check it\n"); + process.end(-1, directory + " :is not a directory, please check it"); return; } } Instrumentation inst = process.session().getInstrumentation(); Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, code); - if (matchedClasses == null || matchedClasses.isEmpty()) { - processNoMatch(process); + processNoMatch(process, statusModel); } else if (matchedClasses.size() > limit) { - processMatches(process, matchedClasses); + processMatches(process, matchedClasses, statusModel); } else { - processMatch(process, effect, inst, matchedClasses); + processMatch(process, effect, inst, matchedClasses, statusModel); } } finally { - process.write(effect + "\n"); - process.end(); + process.appendResult(new RowAffectModel(effect)); + process.end(statusModel.getStatusCode(), statusModel.getMessage()); } } @@ -121,50 +120,39 @@ public void complete(Completion completion) { } } - private void processMatch(CommandProcess process, RowAffect effect, Instrumentation inst, Set> matchedClasses) { + private void processMatch(CommandProcess process, RowAffect effect, Instrumentation inst, Set> matchedClasses, StatusModel statusModel) { try { Map, File> classFiles = dump(inst, matchedClasses); - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - table.row(new LabelElement("HASHCODE").style(Decoration.bold.bold()), - new LabelElement("CLASSLOADER").style(Decoration.bold.bold()), - new LabelElement("LOCATION").style(Decoration.bold.bold())); - + List dumpedClasses = new ArrayList(classFiles.size()); for (Map.Entry, File> entry : classFiles.entrySet()) { Class clazz = entry.getKey(); File file = entry.getValue(); - table.row(label(StringUtils.classLoaderHash(clazz)).style(Decoration.bold.fg(Color.red)), - TypeRenderUtils.drawClassLoader(clazz), - label(file.getCanonicalPath()).style(Decoration.bold.fg(Color.red))); + ClassVO classVO = ClassUtils.createSimpleClassInfo(clazz); + classVO.setLocation(file.getCanonicalPath()); + dumpedClasses.add(classVO); } + process.appendResult(new DumpClassModel().setDumpedClassFiles(dumpedClasses)); - process.write(RenderUtil.render(table, process.width())) - .write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); effect.rCnt(classFiles.keySet().size()); + statusModel.setStatus(0); } catch (Throwable t) { logger.error("dump: fail to dump classes: " + matchedClasses, t); } } - private void processMatches(CommandProcess process, Set> matchedClasses) { - process.write(String.format( - "Found more than %d class for: %s, Please Try to specify the classloader with the -c option, or try to use --limit option.\n", - limit, classPattern)); - - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - table.row(new LabelElement("NAME").style(Decoration.bold.bold()), - new LabelElement("HASHCODE").style(Decoration.bold.bold()), - new LabelElement("CLASSLOADER").style(Decoration.bold.bold())); - - for (Class c : matchedClasses) { - table.row(label(c.getName()), label(StringUtils.classLoaderHash(c)).style(Decoration.bold.fg(Color.red)), - TypeRenderUtils.drawClassLoader(c)); - } + private void processMatches(CommandProcess process, Set> matchedClasses, StatusModel statusModel) { + String msg = String.format( + "Found more than %d class for: %s, Please Try to specify the classloader with the -c option, or try to use --limit option.", + limit, classPattern); + process.appendResult(new MessageModel(msg)); - process.write(RenderUtil.render(table, process.width()) + "\n"); + List classVOs = ClassUtils.createClassVOList(matchedClasses); + process.appendResult(new DumpClassModel().setMatchedClasses(classVOs)); + statusModel.setStatus(-1, msg); } - private void processNoMatch(CommandProcess process) { - process.write("No class found for: " + classPattern + "\n"); + private void processNoMatch(CommandProcess process, StatusModel statusModel) { + statusModel.setStatus(-1, "No class found for: " + classPattern); } private Map, File> dump(Instrumentation inst, Set> classes) throws UnmodifiableClassException { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java index ed0296a120b..1035d10dab5 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java @@ -5,35 +5,32 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.express.ExpressException; import com.taobao.arthas.core.command.express.ExpressFactory; +import com.taobao.arthas.core.command.model.ClassVO; +import com.taobao.arthas.core.command.model.GetStaticModel; +import com.taobao.arthas.core.command.model.MessageModel; +import com.taobao.arthas.core.command.model.RowAffectModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.util.ClassUtils; import com.taobao.arthas.core.util.SearchUtils; import com.taobao.arthas.core.util.StringUtils; -import com.taobao.arthas.core.util.TypeRenderUtils; import com.taobao.arthas.core.util.affect.RowAffect; import com.taobao.arthas.core.util.matcher.Matcher; import com.taobao.arthas.core.util.matcher.RegexMatcher; import com.taobao.arthas.core.util.matcher.WildcardMatcher; -import com.taobao.arthas.core.view.ObjectView; import com.taobao.middleware.cli.annotations.Argument; import com.taobao.middleware.cli.annotations.Description; import com.taobao.middleware.cli.annotations.Name; import com.taobao.middleware.cli.annotations.Option; import com.taobao.middleware.cli.annotations.Summary; -import com.taobao.text.Color; -import com.taobao.text.Decoration; -import com.taobao.text.ui.Element; -import com.taobao.text.ui.LabelElement; -import com.taobao.text.ui.TableElement; -import com.taobao.text.util.RenderUtil; import java.lang.instrument.Instrumentation; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.util.List; import java.util.Set; -import static com.taobao.text.ui.Element.label; - /** * @author diecui1202 on 2017/9/27. */ @@ -96,23 +93,23 @@ public void process(CommandProcess process) { RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); Set> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, hashCode); - + StatusModel statusModel = new StatusModel(-1, "unknown error"); try { if (matchedClasses == null || matchedClasses.isEmpty()) { - process.write("No class found for: " + classPattern + "\n"); + statusModel.setStatus(-1, "No class found for: " + classPattern); } else if (matchedClasses.size() > 1) { - processMatches(process, matchedClasses); + processMatches(process, matchedClasses, statusModel); } else { - processExactMatch(process, affect, inst, matchedClasses); + processExactMatch(process, affect, inst, matchedClasses, statusModel); } } finally { - process.write(affect + "\n"); - process.end(); + process.appendResult(new RowAffectModel(affect)); + process.end(statusModel.getStatusCode(), statusModel.getMessage()); } } private void processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, - Set> matchedClasses) { + Set> matchedClasses, StatusModel statusModel) { Matcher fieldNameMatcher = fieldNameMatcher(); Class clazz = matchedClasses.iterator().next(); @@ -133,45 +130,41 @@ private void processExactMatch(CommandProcess process, RowAffect affect, Instrum value = ExpressFactory.threadLocalExpress(value).get(express); } - String result = StringUtils.objectToString(expand >= 0 ? new ObjectView(value, expand).draw() : value); - process.write("field: " + field.getName() + "\n" + result + "\n"); + process.appendResult(new GetStaticModel(field.getName(), value, expand)); affect.rCnt(1); } catch (IllegalAccessException e) { logger.warn("getstatic: failed to get static value, class: {}, field: {} ", clazz, field.getName(), e); - process.write("Failed to get static, exception message: " + e.getMessage() - + ", please check $HOME/logs/arthas/arthas.log for more details. \n"); + process.appendResult(new MessageModel("Failed to get static, exception message: " + e.getMessage() + + ", please check $HOME/logs/arthas/arthas.log for more details. ")); } catch (ExpressException e) { logger.warn("getstatic: failed to get express value, class: {}, field: {}, express: {}", clazz, field.getName(), express, e); - process.write("Failed to get static, exception message: " + e.getMessage() - + ", please check $HOME/logs/arthas/arthas.log for more details. \n"); + process.appendResult(new MessageModel("Failed to get static, exception message: " + e.getMessage() + + ", please check $HOME/logs/arthas/arthas.log for more details. ")); } finally { found = true; } } if (!found) { - process.write("getstatic: no matched static field was found\n"); + statusModel.setStatus(-1, "getstatic: no matched static field was found"); + } else { + statusModel.setStatus(0, null); } } - private void processMatches(CommandProcess process, Set> matchedClasses) { - Element usage = new LabelElement("getstatic -c " + classPattern + " " + fieldPattern).style( - Decoration.bold.fg(Color.blue)); - process.write("\n Found more than one class for: " + classPattern + ", Please use " + RenderUtil.render(usage, - process.width())); + private void processMatches(CommandProcess process, Set> matchedClasses, StatusModel statusModel) { - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - table.row(new LabelElement("HASHCODE").style(Decoration.bold.bold()), - new LabelElement("CLASSLOADER").style(Decoration.bold.bold())); - - for (Class c : matchedClasses) { - ClassLoader classLoader = c.getClassLoader(); - table.row(label(Integer.toHexString(classLoader.hashCode())).style(Decoration.bold.fg(Color.red)), - TypeRenderUtils.drawClassLoader(c)); - } +// Element usage = new LabelElement("getstatic -c " + classPattern + " " + fieldPattern).style( +// Decoration.bold.fg(Color.blue)); +// process.write("\n Found more than one class for: " + classPattern + ", Please use " + RenderUtil.render(usage, process.width())); + //TODO support message style + String usage = "getstatic -c " + classPattern + " " + fieldPattern; + process.appendResult(new MessageModel("Found more than one class for: " + classPattern + ", Please use: "+usage)); - process.write(RenderUtil.render(table, process.width()) + "\n"); + List matchedClassVOs = ClassUtils.createClassVOList(matchedClasses); + process.appendResult(new GetStaticModel(matchedClassVOs)); + statusModel.setStatus(-1, "Found more than one class for: " + classPattern + ", Please use: "+usage); } private Matcher fieldNameMatcher() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java index 0e008409e6d..8b7a60a5062 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java @@ -3,6 +3,11 @@ import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.ClassVO; +import com.taobao.arthas.core.command.model.JadModel; +import com.taobao.arthas.core.command.model.MessageModel; +import com.taobao.arthas.core.command.model.RowAffectModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -11,30 +16,21 @@ import com.taobao.arthas.core.util.Decompiler; import com.taobao.arthas.core.util.InstrumentationUtils; import com.taobao.arthas.core.util.SearchUtils; -import com.taobao.arthas.core.util.TypeRenderUtils; import com.taobao.arthas.core.util.affect.RowAffect; import com.taobao.middleware.cli.annotations.Argument; import com.taobao.middleware.cli.annotations.Description; import com.taobao.middleware.cli.annotations.Name; import com.taobao.middleware.cli.annotations.Option; import com.taobao.middleware.cli.annotations.Summary; -import com.taobao.text.Color; -import com.taobao.text.Decoration; -import com.taobao.text.lang.LangRenderUtil; -import com.taobao.text.ui.Element; -import com.taobao.text.ui.LabelElement; -import com.taobao.text.ui.TableElement; -import com.taobao.text.util.RenderUtil; import java.io.File; import java.lang.instrument.Instrumentation; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; -import static com.taobao.text.ui.Element.label; - /** * @author diecui1202 on 15/11/24. * @author hengyunabc 2018-11-16 @@ -106,28 +102,30 @@ public void process(CommandProcess process) { Instrumentation inst = process.session().getInstrumentation(); Set> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, code); + StatusModel statusModel = new StatusModel(-1, "unknown error"); try { if (matchedClasses == null || matchedClasses.isEmpty()) { - processNoMatch(process); + statusModel = processNoMatch(process); } else if (matchedClasses.size() > 1) { - processMatches(process, matchedClasses); + statusModel = processMatches(process, matchedClasses); } else { // matchedClasses size is 1 // find inner classes. Set> withInnerClasses = SearchUtils.searchClassOnly(inst, matchedClasses.iterator().next().getName() + "$*", false, code); if(withInnerClasses.isEmpty()) { withInnerClasses = matchedClasses; } - processExactMatch(process, affect, inst, matchedClasses, withInnerClasses); + statusModel = processExactMatch(process, affect, inst, matchedClasses, withInnerClasses); } } finally { if (!this.sourceOnly) { - process.write(affect + "\n"); + process.appendResult(new RowAffectModel(affect)); } - process.end(); + process.end(statusModel.getStatusCode(), statusModel.getMessage()); } } - private void processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, Set> matchedClasses, Set> withInnerClasses) { + private StatusModel processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, Set> matchedClasses, Set> withInnerClasses) { + StatusModel statusModel = new StatusModel(); Class c = matchedClasses.iterator().next(); Set> allClasses = new HashSet>(withInnerClasses); allClasses.add(c); @@ -146,46 +144,42 @@ private void processExactMatch(CommandProcess process, RowAffect affect, Instrum source = "unknown"; } - if (this.sourceOnly) { - process.write(LangRenderUtil.render(source) + "\n"); - return; + JadModel jadModel = new JadModel(); + jadModel.setSource(source); + if (!this.sourceOnly) { + jadModel.setClassInfo(ClassUtils.createSimpleClassInfo(c)); + jadModel.setLocation(ClassUtils.getCodeSource(c.getProtectionDomain().getCodeSource())); } + process.appendResult(jadModel); - - process.write("\n"); - process.write(RenderUtil.render(new LabelElement("ClassLoader: ").style(Decoration.bold.fg(Color.red)), process.width())); - process.write(RenderUtil.render(TypeRenderUtils.drawClassLoader(c), process.width()) + "\n"); - process.write(RenderUtil.render(new LabelElement("Location: ").style(Decoration.bold.fg(Color.red)), process.width())); - process.write(RenderUtil.render(new LabelElement(ClassUtils.getCodeSource( - c.getProtectionDomain().getCodeSource())).style(Decoration.bold.fg(Color.blue)), process.width()) + "\n"); - process.write(LangRenderUtil.render(source) + "\n"); - process.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); affect.rCnt(classFiles.keySet().size()); + statusModel.setStatus(0); } catch (Throwable t) { logger.error("jad: fail to decompile class: " + c.getName(), t); + statusModel.setStatus(-1, "jad: fail to decompile class: " + c.getName()); } + return statusModel; } - private void processMatches(CommandProcess process, Set> matchedClasses) { - Element usage = new LabelElement("jad -c " + classPattern).style(Decoration.bold.fg(Color.blue)); - process.write("\n Found more than one class for: " + classPattern + ", Please use " - + RenderUtil.render(usage, process.width())); + private StatusModel processMatches(CommandProcess process, Set> matchedClasses) { + //Element usage = new LabelElement("jad -c " + classPattern).style(Decoration.bold.fg(Color.blue)); + //process.write("\n Found more than one class for: " + classPattern + ", Please use " + // + RenderUtil.render(usage, process.width())); - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - table.row(new LabelElement("HASHCODE").style(Decoration.bold.bold()), - new LabelElement("CLASSLOADER").style(Decoration.bold.bold())); + String usage = "jad -c " + classPattern; + String msg = " Found more than one class for: " + classPattern + ", Please use " + usage; + process.appendResult(new MessageModel(msg)); - for (Class c : matchedClasses) { - ClassLoader classLoader = c.getClassLoader(); - table.row(label(Integer.toHexString(classLoader.hashCode())).style(Decoration.bold.fg(Color.red)), - TypeRenderUtils.drawClassLoader(c)); - } + List classVOs = ClassUtils.createClassVOList(matchedClasses); + JadModel jadModel = new JadModel(); + jadModel.setMatchedClasses(classVOs); + process.appendResult(jadModel); - process.write(RenderUtil.render(table, process.width()) + "\n"); + return new StatusModel(-1, msg); } - private void processNoMatch(CommandProcess process) { - process.write("No class found for: " + classPattern + "\n"); + private StatusModel processNoMatch(CommandProcess process) { + return new StatusModel().setStatus(-1, "No class found for: " + classPattern); } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java index 0ed22c5fb41..e0f6e68c71b 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java @@ -3,6 +3,7 @@ import java.io.File; import java.lang.instrument.Instrumentation; import java.nio.charset.Charset; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -11,6 +12,8 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.compiler.DynamicCompiler; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.MemoryCompilerModel; +import com.taobao.arthas.core.command.model.RowAffectModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -70,7 +73,7 @@ public void setDirectory(String directory) { @Override public void process(final CommandProcess process) { - int exitCode = 0; + int exitCode = -1; RowAffect affect = new RowAffect(); try { @@ -81,8 +84,8 @@ public void process(final CommandProcess process) { } else { classloader = ClassLoaderUtils.getClassLoader(inst, hashCode); if (classloader == null) { - process.write("Can not find classloader with hashCode: " + hashCode + ".\n"); exitCode = -1; + process.end(-1, "Can not find classloader with hashCode: " + hashCode + "."); return; } } @@ -112,21 +115,22 @@ public void process(final CommandProcess process) { outputDir = new File("").getAbsoluteFile(); } - process.write("Memory compiler output:\n"); + List files = new ArrayList(); for (Entry entry : byteCodes.entrySet()) { File byteCodeFile = new File(outputDir, entry.getKey().replace('.', '/') + ".class"); FileUtils.writeByteArrayToFile(byteCodeFile, entry.getValue()); - process.write(byteCodeFile.getAbsolutePath() + '\n'); + files.add(byteCodeFile.getAbsolutePath()); affect.rCnt(1); } - + process.appendResult(new MemoryCompilerModel(files)); + exitCode = 0; } catch (Throwable e) { logger.warn("Memory compiler error", e); - process.write("Memory compiler error, exception message: " + e.getMessage() - + ", please check $HOME/logs/arthas/arthas.log for more details. \n"); + process.end(-1, "Memory compiler error, exception message: " + e.getMessage() + + ", please check $HOME/logs/arthas/arthas.log for more details."); exitCode = -1; } finally { - process.write(affect + "\n"); + process.appendResult(new RowAffectModel(affect)); process.end(exitCode); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java index f5979d6de5b..33f65ad7407 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java @@ -8,11 +8,10 @@ import com.taobao.arthas.core.command.express.Express; import com.taobao.arthas.core.command.express.ExpressException; import com.taobao.arthas.core.command.express.ExpressFactory; +import com.taobao.arthas.core.command.model.OgnlModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ClassLoaderUtils; -import com.taobao.arthas.core.util.StringUtils; -import com.taobao.arthas.core.view.ObjectView; import com.taobao.middleware.cli.annotations.Argument; import com.taobao.middleware.cli.annotations.Description; import com.taobao.middleware.cli.annotations.Name; @@ -73,7 +72,7 @@ public void process(CommandProcess process) { } if (classLoader == null) { - process.write("Can not find classloader with hashCode: " + hashCode + ".\n"); + process.end(-1, "Can not find classloader with hashCode: " + hashCode + "."); exitCode = -1; return; } @@ -81,12 +80,14 @@ public void process(CommandProcess process) { Express unpooledExpress = ExpressFactory.unpooledExpress(classLoader); try { Object value = unpooledExpress.get(express); - String result = StringUtils.objectToString(expand >= 0 ? new ObjectView(value, expand).draw() : value); - process.write(result + "\n"); + OgnlModel ognlModel = new OgnlModel() + .setValue(value) + .setExpand(expand); + process.appendResult(ognlModel); } catch (ExpressException e) { logger.warn("ognl: failed execute express: " + express, e); - process.write("Failed to execute ognl, exception message: " + e.getMessage() - + ", please check $HOME/logs/arthas/arthas.log for more details. \n"); + process.end(-1, "Failed to execute ognl, exception message: " + e.getMessage() + + ", please check $HOME/logs/arthas/arthas.log for more details. "); exitCode = -1; } } finally { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java index 5bcdc278038..33f320a0eb4 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java @@ -14,6 +14,7 @@ import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.RedefineModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -58,23 +59,20 @@ public void setPaths(List paths) { @Override public void process(CommandProcess process) { + RedefineModel redefineModel = new RedefineModel(); Instrumentation inst = process.session().getInstrumentation(); - for (String path : paths) { File file = new File(path); if (!file.exists()) { - process.write("file does not exist, path:" + path + "\n"); - process.end(); + process.end(-1, "file does not exist, path:" + path); return; } if (!file.isFile()) { - process.write("not a normal file, path:" + path + "\n"); - process.end(); + process.end(-1, "not a normal file, path:" + path); return; } if (file.length() >= MAX_FILE_SIZE) { - process.write("file size: " + file.length() + " >= " + MAX_FILE_SIZE + ", path: " + path + "\n"); - process.end(); + process.end(-1, "file size: " + file.length() + " >= " + MAX_FILE_SIZE + ", path: " + path); return; } } @@ -92,7 +90,8 @@ public void process(CommandProcess process) { bytesMap.put(clazzName, bytes); } catch (Exception e) { - process.write("" + e + "\n"); + logger.warn("load class file failed: "+path, e); + process.end(-1, "load class file failed: " +path+", error: " + e); } finally { if (f != null) { try { @@ -105,8 +104,7 @@ public void process(CommandProcess process) { } if (bytesMap.size() != paths.size()) { - process.write("paths may contains same class name!\n"); - process.end(); + process.end(-1, "paths may contains same class name!"); return; } @@ -118,21 +116,20 @@ public void process(CommandProcess process) { continue; } definitions.add(new ClassDefinition(clazz, bytesMap.get(clazz.getName()))); + redefineModel.addRedefineClass(clazz.getName()); logger.info("Try redefine class name: {}, ClassLoader: {}", clazz.getName(), clazz.getClassLoader()); } } try { if (definitions.isEmpty()) { - process.write("These classes are not found in the JVM and may not be loaded: " + bytesMap.keySet() - + "\n"); - process.end(); + process.end(-1, "These classes are not found in the JVM and may not be loaded: " + bytesMap.keySet()); return; } inst.redefineClasses(definitions.toArray(new ClassDefinition[0])); - process.write("redefine success, size: " + definitions.size() + "\n"); + process.appendResult(redefineModel); } catch (Exception e) { - process.write("redefine error! " + e + "\n"); + process.end(-1, "redefine error! " + e); } process.end(); diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java index 1274c01c3de..1953f1fb04e 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java @@ -8,11 +8,15 @@ import java.util.List; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.SearchClassModel; +import com.taobao.arthas.core.command.model.ClassVO; +import com.taobao.arthas.core.command.model.RowAffectModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ClassUtils; +import com.taobao.arthas.core.util.ResultUtils; import com.taobao.arthas.core.util.SearchUtils; import com.taobao.arthas.core.util.StringUtils; import com.taobao.arthas.core.util.affect.RowAffect; @@ -21,7 +25,6 @@ import com.taobao.middleware.cli.annotations.Name; import com.taobao.middleware.cli.annotations.Option; import com.taobao.middleware.cli.annotations.Summary; -import com.taobao.text.util.RenderUtil; /** * 展示类信息 @@ -44,6 +47,7 @@ public class SearchClassCommand extends AnnotatedCommand { private boolean isRegEx = false; private String hashCode = null; private Integer expand; + private int numberOfLimit = 100; @Argument(argName = "class-pattern", index = 0) @Description("Class name pattern, use either '.' or '/' as separator") @@ -81,36 +85,51 @@ public void setHashCode(String hashCode) { this.hashCode = hashCode; } + @Option(shortName = "n", longName = "limits") + @Description("Maximum number of matching classes with details (100 by default)") + public void setNumberOfLimit(int numberOfLimit) { + this.numberOfLimit = numberOfLimit; + } + @Override - public void process(CommandProcess process) { + public void process(final CommandProcess process) { // TODO: null check RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); - List> matchedClasses = new ArrayList>(SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode)); - Collections.sort(matchedClasses, new Comparator>() { + List matchedClasses = new ArrayList(SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode)); + Collections.sort(matchedClasses, new Comparator() { @Override - public int compare(Class c1, Class c2) { + public int compare(Class c1, Class c2) { return StringUtils.classname(c1).compareTo(StringUtils.classname(c2)); } }); + if (isDetail) { + if (matchedClasses.size() > numberOfLimit) { + process.end(-1, "Matching classes are too many: "+matchedClasses.size()); + return; + } for (Class clazz : matchedClasses) { - processClass(process, clazz); + ClassVO classInfo = ClassUtils.createClassInfo(clazz, isDetail, isField); + process.appendResult(new SearchClassModel(classInfo, isDetail, isField, expand)); + } + } else { + int pageSize = 256; + ResultUtils.processClassNames(matchedClasses, pageSize, new ResultUtils.PaginationHandler>() { + @Override + public boolean handle(List classNames, int segment) { + process.appendResult(new SearchClassModel(classNames, segment)); + return true; + } + }); } + affect.rCnt(matchedClasses.size()); - process.write(affect + "\n"); + process.appendResult(new RowAffectModel(affect)); process.end(); } - private void processClass(CommandProcess process, Class clazz) { - if (isDetail) { - process.write(RenderUtil.render(ClassUtils.renderClassInfo(clazz, isField, expand), process.width()) + "\n"); - } else { - process.write(clazz.getName() + "\n"); - } - } - @Override public void complete(Completion completion) { if (!CompletionUtils.completeClassName(completion)) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java index c40e0093f85..d9add0132d8 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java @@ -1,8 +1,5 @@ package com.taobao.arthas.core.command.klass100; -import static com.taobao.text.Decoration.bold; -import static com.taobao.text.ui.Element.label; -import static java.lang.String.format; import java.lang.instrument.Instrumentation; import java.lang.reflect.Constructor; @@ -12,13 +9,16 @@ import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.SearchMethodModel; +import com.taobao.arthas.core.command.model.MethodVO; +import com.taobao.arthas.core.command.model.RowAffectModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.util.ClassUtils; import com.taobao.arthas.core.util.SearchUtils; import com.taobao.arthas.core.util.StringUtils; -import com.taobao.arthas.core.util.TypeRenderUtils; import com.taobao.arthas.core.util.affect.RowAffect; import com.taobao.arthas.core.util.matcher.Matcher; import com.taobao.arthas.core.util.matcher.RegexMatcher; @@ -28,9 +28,6 @@ import com.taobao.middleware.cli.annotations.Name; import com.taobao.middleware.cli.annotations.Option; import com.taobao.middleware.cli.annotations.Summary; -import com.taobao.text.ui.Element; -import com.taobao.text.ui.TableElement; -import com.taobao.text.util.RenderUtil; /** * 展示方法信息 @@ -55,6 +52,7 @@ public class SearchMethodCommand extends AnnotatedCommand { private String hashCode = null; private boolean isDetail = false; private boolean isRegEx = false; + private int numberOfLimit = 100; @Argument(argName = "class-pattern", index = 0) @Description("Class name pattern, use either '.' or '/' as separator") @@ -86,6 +84,12 @@ public void setHashCode(String hashCode) { this.hashCode = hashCode; } + @Option(shortName = "n", longName = "limits") + @Description("Maximum number of matching classes (100 by default)") + public void setNumberOfLimit(int numberOfLimit) { + this.numberOfLimit = numberOfLimit; + } + @Override public void process(CommandProcess process) { RowAffect affect = new RowAffect(); @@ -94,47 +98,40 @@ public void process(CommandProcess process) { Matcher methodNameMatcher = methodNameMatcher(); Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode); + if (matchedClasses.size() > numberOfLimit) { + process.end(-1, "Matching classes are too many: "+matchedClasses.size()); + return; + } for (Class clazz : matchedClasses) { try { for (Constructor constructor : clazz.getDeclaredConstructors()) { - String methodNameWithDescriptor = com.alibaba.arthas.deps.org.objectweb.asm.commons.Method.getMethod(constructor).toString(); if (!methodNameMatcher.matching("")) { continue; } - if (isDetail) { - process.write(RenderUtil.render(renderConstructor(constructor, clazz), process.width()) + "\n"); - } else { - String line = format("%s %s%n", clazz.getName(), methodNameWithDescriptor); - process.write(line); - } + MethodVO methodInfo = ClassUtils.createMethodInfo(constructor, clazz, isDetail); + process.appendResult(new SearchMethodModel(methodInfo, isDetail)); affect.rCnt(1); } for (Method method : clazz.getDeclaredMethods()) { - String methodNameWithDescriptor = com.alibaba.arthas.deps.org.objectweb.asm.commons.Method.getMethod(method).toString(); if (!methodNameMatcher.matching(method.getName())) { continue; } - - if (isDetail) { - process.write(RenderUtil.render(renderMethod(method, clazz), process.width()) + "\n"); - } else { - String line = format("%s %s%n", clazz.getName(), methodNameWithDescriptor); - process.write(line); - } + MethodVO methodInfo = ClassUtils.createMethodInfo(method, clazz, isDetail); + process.appendResult(new SearchMethodModel(methodInfo, isDetail)); affect.rCnt(1); } } catch (Error e) { //print failed className String msg = String.format("process class failed: %s, error: %s", clazz.getName(), e.toString()); logger.error(msg, e); - process.write(msg).write("\n"); - throw e; + process.end(1, msg); + return; } } - process.write(affect + "\n"); + process.appendResult(new RowAffectModel(affect)); process.end(); } @@ -146,33 +143,6 @@ private Matcher methodNameMatcher() { return isRegEx ? new RegexMatcher(methodPattern) : new WildcardMatcher(methodPattern); } - private Element renderMethod(Method method, Class clazz) { - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - - table.row(label("declaring-class").style(bold.bold()), label(method.getDeclaringClass().getName())) - .row(label("method-name").style(bold.bold()), label(method.getName()).style(bold.bold())) - .row(label("modifier").style(bold.bold()), label(StringUtils.modifier(method.getModifiers(), ','))) - .row(label("annotation").style(bold.bold()), label(TypeRenderUtils.drawAnnotation(method))) - .row(label("parameters").style(bold.bold()), label(TypeRenderUtils.drawParameters(method))) - .row(label("return").style(bold.bold()), label(TypeRenderUtils.drawReturn(method))) - .row(label("exceptions").style(bold.bold()), label(TypeRenderUtils.drawExceptions(method))) - .row(label("classLoaderHash").style(bold.bold()), label(StringUtils.classLoaderHash(clazz))); - return table; - } - - private Element renderConstructor(Constructor constructor, Class clazz) { - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - - table.row(label("declaring-class").style(bold.bold()), label(constructor.getDeclaringClass().getName())) - .row(label("constructor-name").style(bold.bold()), label("").style(bold.bold())) - .row(label("modifier").style(bold.bold()), label(StringUtils.modifier(constructor.getModifiers(), ','))) - .row(label("annotation").style(bold.bold()), label(TypeRenderUtils.drawAnnotation(constructor.getDeclaredAnnotations()))) - .row(label("parameters").style(bold.bold()), label(TypeRenderUtils.drawParameters(constructor))) - .row(label("exceptions").style(bold.bold()), label(TypeRenderUtils.drawExceptions(constructor))) - .row(label("classLoaderHash").style(bold.bold()), label(StringUtils.classLoaderHash(clazz))); - return table; - } - @Override public void complete(Completion completion) { int argumentIndex = CompletionUtils.detectArgumentIndex(completion); diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderModel.java new file mode 100644 index 00000000000..607a1b4136b --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderModel.java @@ -0,0 +1,93 @@ +package com.taobao.arthas.core.command.model; + +import com.taobao.arthas.core.command.klass100.ClassLoaderCommand.ClassLoaderStat; + +import java.util.List; +import java.util.Map; + +/** + * @author gongdewei 2020/4/21 + */ +public class ClassLoaderModel extends ResultModel { + + private ClassSetVO classSet; + private List resources; + private ClassVO loadClass; + private List urls; + //classloader -l -t + private List classLoaders; + private Boolean tree; + + private Map classLoaderStats; + + public ClassLoaderModel() { + } + + @Override + public String getType() { + return "classloader"; + } + + public ClassSetVO getClassSet() { + return classSet; + } + + public ClassLoaderModel setClassSet(ClassSetVO classSet) { + this.classSet = classSet; + return this; + } + + public List getResources() { + return resources; + } + + public ClassLoaderModel setResources(List resources) { + this.resources = resources; + return this; + } + + public ClassVO getLoadClass() { + return loadClass; + } + + public ClassLoaderModel setLoadClass(ClassVO loadClass) { + this.loadClass = loadClass; + return this; + } + + public List getUrls() { + return urls; + } + + public ClassLoaderModel setUrls(List urls) { + this.urls = urls; + return this; + } + + public List getClassLoaders() { + return classLoaders; + } + + public ClassLoaderModel setClassLoaders(List classLoaders) { + this.classLoaders = classLoaders; + return this; + } + + public Boolean getTree() { + return tree; + } + + public ClassLoaderModel setTree(Boolean tree) { + this.tree = tree; + return this; + } + + public Map getClassLoaderStats() { + return classLoaderStats; + } + + public ClassLoaderModel setClassLoaderStats(Map classLoaderStats) { + this.classLoaderStats = classLoaderStats; + return this; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderVO.java new file mode 100644 index 00000000000..7f9ebf9096c --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderVO.java @@ -0,0 +1,78 @@ +package com.taobao.arthas.core.command.model; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author gongdewei 2020/4/21 + */ +public class ClassLoaderVO { + private String name; + private String hash; + private String parent; + private Integer loadedCount; + private Integer numberOfInstances; + private List children; + + public ClassLoaderVO() { + } + + public void addChild(ClassLoaderVO child){ + if (this.children == null){ + synchronized (this){ + if (this.children == null) { + this.children = new ArrayList(); + } + } + } + this.children.add(child); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public String getParent() { + return parent; + } + + public void setParent(String parent) { + this.parent = parent; + } + + public Integer getLoadedCount() { + return loadedCount; + } + + public void setLoadedCount(Integer loadedCount) { + this.loadedCount = loadedCount; + } + + public Integer getNumberOfInstances() { + return numberOfInstances; + } + + public void setNumberOfInstances(Integer numberOfInstances) { + this.numberOfInstances = numberOfInstances; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/ClassSetVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/ClassSetVO.java new file mode 100644 index 00000000000..3cb3e3219a8 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/ClassSetVO.java @@ -0,0 +1,51 @@ +package com.taobao.arthas.core.command.model; + +import java.util.Collection; + +/** + * @author gongdewei 2020/4/21 + */ +public class ClassSetVO implements Countable { + private ClassLoaderVO classloader; + private Collection classes; + private int segment; + + public ClassSetVO(ClassLoaderVO classloader, Collection classes) { + this(classloader, classes, 0); + } + + public ClassSetVO(ClassLoaderVO classloader, Collection classes, int segment) { + this.classloader = classloader; + this.classes = classes; + this.segment = segment; + } + + public ClassLoaderVO getClassloader() { + return classloader; + } + + public void setClassloader(ClassLoaderVO classloader) { + this.classloader = classloader; + } + + public Collection getClasses() { + return classes; + } + + public void setClasses(Collection classes) { + this.classes = classes; + } + + public int getSegment() { + return segment; + } + + public void setSegment(int segment) { + this.segment = segment; + } + + @Override + public int size() { + return classes != null ? classes.size() : 1; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/ClassVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/ClassVO.java new file mode 100644 index 00000000000..e8ef107211d --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/ClassVO.java @@ -0,0 +1,197 @@ +package com.taobao.arthas.core.command.model; + +/** + * @author gongdewei 2020/4/8 + */ +public class ClassVO { + + private String name; + private String classInfo; + private String codeSource; + private Boolean isInterface; + private Boolean isAnnotation; + private Boolean isEnum; + private Boolean isAnonymousClass; + private Boolean isArray; + private Boolean isLocalClass; + private Boolean isMemberClass; + private Boolean isPrimitive; + private Boolean isSynthetic; + private String simpleName; + private String modifier; + private String[] annotations; + private String[] interfaces; + private String[] superClass; + private String[] classloader; + private String classLoaderHash; + private FieldVO[] fields; + private String location; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getClassInfo() { + return classInfo; + } + + public void setClassInfo(String classInfo) { + this.classInfo = classInfo; + } + + public String getCodeSource() { + return codeSource; + } + + public void setCodeSource(String codeSource) { + this.codeSource = codeSource; + } + + public Boolean getInterface() { + return isInterface; + } + + public void setInterface(Boolean anInterface) { + isInterface = anInterface; + } + + public Boolean getAnnotation() { + return isAnnotation; + } + + public void setAnnotation(Boolean annotation) { + isAnnotation = annotation; + } + + public Boolean getEnum() { + return isEnum; + } + + public void setEnum(Boolean anEnum) { + isEnum = anEnum; + } + + public Boolean getAnonymousClass() { + return isAnonymousClass; + } + + public void setAnonymousClass(Boolean anonymousClass) { + isAnonymousClass = anonymousClass; + } + + public Boolean getArray() { + return isArray; + } + + public void setArray(Boolean array) { + isArray = array; + } + + public Boolean getLocalClass() { + return isLocalClass; + } + + public void setLocalClass(Boolean localClass) { + isLocalClass = localClass; + } + + public Boolean getMemberClass() { + return isMemberClass; + } + + public void setMemberClass(Boolean memberClass) { + isMemberClass = memberClass; + } + + public Boolean getPrimitive() { + return isPrimitive; + } + + public void setPrimitive(Boolean primitive) { + isPrimitive = primitive; + } + + public Boolean getSynthetic() { + return isSynthetic; + } + + public void setSynthetic(Boolean synthetic) { + isSynthetic = synthetic; + } + + public String getSimpleName() { + return simpleName; + } + + public void setSimpleName(String simpleName) { + this.simpleName = simpleName; + } + + public String getModifier() { + return modifier; + } + + public void setModifier(String modifier) { + this.modifier = modifier; + } + + public String[] getAnnotations() { + return annotations; + } + + public void setAnnotations(String[] annotations) { + this.annotations = annotations; + } + + public String[] getInterfaces() { + return interfaces; + } + + public void setInterfaces(String[] interfaces) { + this.interfaces = interfaces; + } + + public String[] getSuperClass() { + return superClass; + } + + public void setSuperClass(String[] superClass) { + this.superClass = superClass; + } + + public String[] getClassloader() { + return classloader; + } + + public void setClassloader(String[] classloader) { + this.classloader = classloader; + } + + public String getClassLoaderHash() { + return classLoaderHash; + } + + public void setClassLoaderHash(String classLoaderHash) { + this.classLoaderHash = classLoaderHash; + } + + public FieldVO[] getFields() { + return fields; + } + + public void setFields(FieldVO[] fields) { + this.fields = fields; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassModel.java new file mode 100644 index 00000000000..4c393660958 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassModel.java @@ -0,0 +1,41 @@ +package com.taobao.arthas.core.command.model; + +import java.util.Collection; +import java.util.List; + +/** + * @author gongdewei 2020/4/21 + */ +public class DumpClassModel extends ResultModel { + + private List dumpedClassFiles; + + private Collection matchedClasses; + + public DumpClassModel() { + } + + @Override + public String getType() { + return "dump"; + } + + public List getDumpedClassFiles() { + return dumpedClassFiles; + } + + public DumpClassModel setDumpedClassFiles(List dumpedClassFiles) { + this.dumpedClassFiles = dumpedClassFiles; + return this; + } + + public Collection getMatchedClasses() { + return matchedClasses; + } + + public DumpClassModel setMatchedClasses(Collection matchedClasses) { + this.matchedClasses = matchedClasses; + return this; + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/FieldVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/FieldVO.java new file mode 100644 index 00000000000..79615ff4d9b --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/FieldVO.java @@ -0,0 +1,61 @@ +package com.taobao.arthas.core.command.model; + +/** + * @author gongdewei 2020/4/8 + */ +public class FieldVO { + private String name; + private String type; + private String modifier; + private String[] annotations; + private Object value; + private boolean isStatic; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getModifier() { + return modifier; + } + + public void setModifier(String modifier) { + this.modifier = modifier; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public String[] getAnnotations() { + return annotations; + } + + public void setAnnotations(String[] annotations) { + this.annotations = annotations; + } + + public boolean isStatic() { + return isStatic; + } + + public void setStatic(boolean aStatic) { + isStatic = aStatic; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/GetStaticModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/GetStaticModel.java new file mode 100644 index 00000000000..b4c62842d4b --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/GetStaticModel.java @@ -0,0 +1,56 @@ +package com.taobao.arthas.core.command.model; + +import java.util.Collection; + +/** + * @author gongdewei 2020/4/20 + */ +public class GetStaticModel extends ResultModel { + + private ObjectVO field; + private Collection matchedClasses; + + //only for view + private transient int expand; + + public GetStaticModel() { + } + + public GetStaticModel(String fieldName, Object fieldValue, int expand) { + this.field = new ObjectVO(fieldName, fieldValue); + this.expand = expand; + } + + public GetStaticModel(Collection matchedClasses) { + this.matchedClasses = matchedClasses; + } + + public ObjectVO getField() { + return field; + } + + public void setField(ObjectVO field) { + this.field = field; + } + + public Collection getMatchedClasses() { + return matchedClasses; + } + + public void setMatchedClasses(Collection matchedClasses) { + this.matchedClasses = matchedClasses; + } + + public int expand() { + return expand; + } + + public void setExpand(int expand) { + this.expand = expand; + } + + @Override + public String getType() { + return "getstatic"; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/JadModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/JadModel.java new file mode 100644 index 00000000000..e108a9a29a7 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/JadModel.java @@ -0,0 +1,55 @@ +package com.taobao.arthas.core.command.model; + +import java.util.Collection; + +/** + * @author gongdewei 2020/4/22 + */ +public class JadModel extends ResultModel { + private ClassVO classInfo; + private String location; + private String source; + + //match multiple classes + private Collection matchedClasses; + + @Override + public String getType() { + return "jad"; + } + + public JadModel() { + } + + public ClassVO getClassInfo() { + return classInfo; + } + + public void setClassInfo(ClassVO classInfo) { + this.classInfo = classInfo; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public Collection getMatchedClasses() { + return matchedClasses; + } + + public void setMatchedClasses(Collection matchedClasses) { + this.matchedClasses = matchedClasses; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/MemoryCompilerModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/MemoryCompilerModel.java new file mode 100644 index 00000000000..59d9b732ced --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/MemoryCompilerModel.java @@ -0,0 +1,32 @@ +package com.taobao.arthas.core.command.model; + +import java.util.List; + +/** + * @author gongdewei 2020/4/20 + */ +public class MemoryCompilerModel extends ResultModel { + + private List files; + + public MemoryCompilerModel() { + } + + public MemoryCompilerModel(List files) { + this.files = files; + } + + public void setFiles(List files) { + this.files = files; + } + + public List getFiles() { + return files; + } + + @Override + public String getType() { + return "mc"; + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/MethodVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/MethodVO.java new file mode 100644 index 00000000000..2f6cdaceb89 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/MethodVO.java @@ -0,0 +1,99 @@ +package com.taobao.arthas.core.command.model; + +/** + * Method or Constructor VO + * @author gongdewei 2020/4/9 + */ +public class MethodVO { + + private String declaringClass; + private String methodName; + private String modifier; + private String[] annotations; + private String[] parameters; + private String returnType; + private String[] exceptions; + private String classLoaderHash; + private String descriptor; + private boolean constructor; + + public String getDeclaringClass() { + return declaringClass; + } + + public void setDeclaringClass(String declaringClass) { + this.declaringClass = declaringClass; + } + + public String getMethodName() { + return methodName; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + public String getModifier() { + return modifier; + } + + public void setModifier(String modifier) { + this.modifier = modifier; + } + + public String[] getAnnotations() { + return annotations; + } + + public void setAnnotations(String[] annotations) { + this.annotations = annotations; + } + + public String[] getParameters() { + return parameters; + } + + public void setParameters(String[] parameters) { + this.parameters = parameters; + } + + public String getReturnType() { + return returnType; + } + + public void setReturnType(String returnType) { + this.returnType = returnType; + } + + public String[] getExceptions() { + return exceptions; + } + + public void setExceptions(String[] exceptions) { + this.exceptions = exceptions; + } + + public String getClassLoaderHash() { + return classLoaderHash; + } + + public void setClassLoaderHash(String classLoaderHash) { + this.classLoaderHash = classLoaderHash; + } + + public boolean isConstructor() { + return constructor; + } + + public void setConstructor(boolean constructor) { + this.constructor = constructor; + } + + public String getDescriptor() { + return descriptor; + } + + public void setDescriptor(String descriptor) { + this.descriptor = descriptor; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/ObjectVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/ObjectVO.java new file mode 100644 index 00000000000..621857f6708 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/ObjectVO.java @@ -0,0 +1,34 @@ +package com.taobao.arthas.core.command.model; + +/** + * @author gongdewei 2020/4/29 + */ +public class ObjectVO { + private String name; + private Object value; + + public ObjectVO(String name, Object value) { + this.name = name; + this.value = value; + } + + public ObjectVO(Object value) { + this.value = value; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/OgnlModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/OgnlModel.java new file mode 100644 index 00000000000..d90f79e0d29 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/OgnlModel.java @@ -0,0 +1,33 @@ +package com.taobao.arthas.core.command.model; + +/** + * @author gongdewei 2020/4/29 + */ +public class OgnlModel extends ResultModel { + private Object value; + private int expand = 1; + + + @Override + public String getType() { + return "ognl"; + } + + public Object getValue() { + return value; + } + + public OgnlModel setValue(Object value) { + this.value = value; + return this; + } + + public int getExpand() { + return expand; + } + + public OgnlModel setExpand(int expand) { + this.expand = expand; + return this; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/RedefineModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/RedefineModel.java new file mode 100644 index 00000000000..0b6a178335d --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/RedefineModel.java @@ -0,0 +1,45 @@ +package com.taobao.arthas.core.command.model; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author gongdewei 2020/4/16 + */ +public class RedefineModel extends ResultModel { + + private int redefinitionCount; + + private List redefinedClasses; + + public RedefineModel() { + redefinedClasses = new ArrayList(); + } + + public void addRedefineClass(String className) { + redefinedClasses.add(className); + redefinitionCount++; + } + + public int getRedefinitionCount() { + return redefinitionCount; + } + + public void setRedefinitionCount(int redefinitionCount) { + this.redefinitionCount = redefinitionCount; + } + + public List getRedefinedClasses() { + return redefinedClasses; + } + + public void setRedefinedClasses(List redefinedClasses) { + this.redefinedClasses = redefinedClasses; + } + + @Override + public String getType() { + return "redefine"; + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/RowAffectModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/RowAffectModel.java new file mode 100644 index 00000000000..05a05636793 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/RowAffectModel.java @@ -0,0 +1,30 @@ +package com.taobao.arthas.core.command.model; + +import com.taobao.arthas.core.util.affect.RowAffect; + +/** + * @author gongdewei 2020/4/8 + */ +public class RowAffectModel extends ResultModel { + private RowAffect affect; + + public RowAffectModel() { + } + + public RowAffectModel(RowAffect affect) { + this.affect = affect; + } + + @Override + public String getType() { + return "row_affect"; + } + + public int getRowCount() { + return affect.rCnt(); + } + + public RowAffect affect() { + return affect; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/SearchClassModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/SearchClassModel.java new file mode 100644 index 00000000000..7541ab14ab8 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/SearchClassModel.java @@ -0,0 +1,74 @@ +package com.taobao.arthas.core.command.model; + + +import java.util.List; + +/** + * Class info of SearchClassCommand + * @author gongdewei 2020/04/08 + */ +public class SearchClassModel extends ResultModel { + private ClassVO classInfo; + private boolean withField; + private boolean detail; + private Integer expand; + private List classNames; + private int segment; + + public SearchClassModel() { + } + + public SearchClassModel(ClassVO classInfo, boolean detail, boolean withField, Integer expand) { + this.classInfo = classInfo; + this.detail = detail; + this.withField = withField; + this.expand = expand; + } + + public SearchClassModel(List classNames, int segment) { + this.classNames = classNames; + this.segment = segment; + } + + @Override + public String getType() { + return "sc"; + } + + public ClassVO getClassInfo() { + return classInfo; + } + + public void setClassInfo(ClassVO classInfo) { + this.classInfo = classInfo; + } + + public List getClassNames() { + return classNames; + } + + public void setClassNames(List classNames) { + this.classNames = classNames; + } + + public int getSegment() { + return segment; + } + + public void setSegment(int segment) { + this.segment = segment; + } + + public boolean isDetail() { + return detail; + } + + public boolean withField() { + return withField; + } + + public Integer expand() { + return expand; + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/SearchMethodModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/SearchMethodModel.java new file mode 100644 index 00000000000..ba77192a393 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/SearchMethodModel.java @@ -0,0 +1,40 @@ +package com.taobao.arthas.core.command.model; + + +/** + * Model of SearchMethodCommand + * @author gongdewei 2020/4/9 + */ +public class SearchMethodModel extends ResultModel { + private MethodVO methodInfo; + private boolean detail; + + public SearchMethodModel() { + } + + public SearchMethodModel(MethodVO methodInfo, boolean detail) { + this.methodInfo = methodInfo; + this.detail = detail; + } + + public MethodVO getMethodInfo() { + return methodInfo; + } + + public void setMethodInfo(MethodVO methodInfo) { + this.methodInfo = methodInfo; + } + + public boolean isDetail() { + return detail; + } + + public void setDetail(boolean detail) { + this.detail = detail; + } + + @Override + public String getType() { + return "sm"; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/ClassLoaderView.java b/core/src/main/java/com/taobao/arthas/core/command/view/ClassLoaderView.java new file mode 100644 index 00000000000..1cf5caeef60 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/ClassLoaderView.java @@ -0,0 +1,140 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.klass100.ClassLoaderCommand.ClassLoaderStat; +import com.taobao.arthas.core.command.model.ClassLoaderModel; +import com.taobao.arthas.core.command.model.ClassLoaderVO; +import com.taobao.arthas.core.command.model.ClassSetVO; +import com.taobao.arthas.core.command.model.ClassVO; +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.util.ClassUtils; +import com.taobao.text.Decoration; +import com.taobao.text.ui.*; +import com.taobao.text.util.RenderUtil; + +import java.util.List; +import java.util.Map; + +/** + * @author gongdewei 2020/4/21 + */ +public class ClassLoaderView extends ResultView { + + @Override + public void draw(CommandProcess process, ClassLoaderModel result) { + if (result.getClassSet() != null) { + drawAllClasses(process, result.getClassSet()); + } + if (result.getResources() != null) { + drawResources(process, result.getResources()); + } + if (result.getLoadClass() != null) { + drawLoadClass(process, result.getLoadClass()); + } + if (result.getUrls() != null) { + drawClassLoaderUrls(process, result.getUrls()); + } + if (result.getClassLoaders() != null){ + drawClassLoaders(process, result.getClassLoaders(), result.getTree()); + } + if (result.getClassLoaderStats() != null){ + drawClassLoaderStats(process, result.getClassLoaderStats()); + } + } + + private void drawClassLoaderStats(CommandProcess process, Map classLoaderStats) { + Element element = renderStat(classLoaderStats); + process.write(RenderUtil.render(element, process.width())) + .write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); + + } + + private static TableElement renderStat(Map classLoaderStats) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + table.add(new RowElement().style(Decoration.bold.bold()).add("name", "numberOfInstances", "loadedCountTotal")); + for (Map.Entry entry : classLoaderStats.entrySet()) { + table.row(entry.getKey(), "" + entry.getValue().getNumberOfInstance(), "" + entry.getValue().getLoadedCount()); + } + return table; + } + + private void drawClassLoaders(CommandProcess process, List classLoaders, Boolean isTree) { + Element element = isTree ? renderTree(classLoaders) : renderTable(classLoaders); + process.write(RenderUtil.render(element, process.width())) + .write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); + } + + private void drawClassLoaderUrls(CommandProcess process, List urls) { + process.write(RenderUtil.render(renderClassLoaderUrls(urls), process.width())); + process.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); + } + + private void drawLoadClass(CommandProcess process, ClassVO loadClass) { + process.write(RenderUtil.render(ClassUtils.renderClassInfo(loadClass), process.width()) + "\n"); + } + + private void drawAllClasses(CommandProcess process, ClassSetVO classSetVO) { + process.write(RenderUtil.render(renderClasses(classSetVO), process.width())); + process.write("\n"); + } + + private void drawResources(CommandProcess process, List resources) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + for (String resource : resources) { + table.row(resource); + } + process.write(RenderUtil.render(table, process.width()) + "\n"); + process.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); + } + + private Element renderClasses(ClassSetVO classSetVO) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + if (classSetVO.getSegment() == 0) { + table.row(new LabelElement("hash:" + classSetVO.getClassloader().getHash() + ", " + classSetVO.getClassloader().getName()) + .style(Decoration.bold.bold())); + } + for (String className : classSetVO.getClasses()) { + table.row(new LabelElement(className)); + } + return table; + } + + private static Element renderClassLoaderUrls(List urls) { + StringBuilder sb = new StringBuilder(); + for (String url : urls) { + sb.append(url).append("\n"); + } + return new LabelElement(sb.toString()); + } + + // 统计所有的ClassLoader的信息 + private static TableElement renderTable(List classLoaderInfos) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + table.add(new RowElement().style(Decoration.bold.bold()).add("name", "loadedCount", "hash", "parent")); + for (ClassLoaderVO classLoaderVO : classLoaderInfos) { + table.row(classLoaderVO.getName(), "" + classLoaderVO.getLoadedCount(), classLoaderVO.getHash(), classLoaderVO.getParent()); + } + return table; + } + + // 以树状列出ClassLoader的继承结构 + private static Element renderTree(List classLoaderInfos) { + TreeElement root = new TreeElement(); + for (ClassLoaderVO classLoader : classLoaderInfos) { + TreeElement child = new TreeElement(classLoader.getName()); + root.addChild(child); + renderSubtree(child, classLoader); + } + return root; + } + + private static void renderSubtree(TreeElement parent, ClassLoaderVO parentClassLoader) { + if (parentClassLoader.getChildren() == null){ + return; + } + for (ClassLoaderVO childClassLoader : parentClassLoader.getChildren()) { + TreeElement child = new TreeElement(childClassLoader.getName()); + parent.addChild(child); + renderSubtree(child, childClassLoader); + } + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/DumpClassView.java b/core/src/main/java/com/taobao/arthas/core/command/view/DumpClassView.java new file mode 100644 index 00000000000..9467261758f --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/DumpClassView.java @@ -0,0 +1,51 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.ClassVO; +import com.taobao.arthas.core.command.model.DumpClassModel; +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.util.ClassUtils; +import com.taobao.arthas.core.util.TypeRenderUtils; +import com.taobao.text.Color; +import com.taobao.text.Decoration; +import com.taobao.text.ui.Element; +import com.taobao.text.ui.LabelElement; +import com.taobao.text.ui.TableElement; +import com.taobao.text.util.RenderUtil; + +import java.util.List; + +import static com.taobao.text.ui.Element.label; + +/** + * @author gongdewei 2020/4/21 + */ +public class DumpClassView extends ResultView { + + @Override + public void draw(CommandProcess process, DumpClassModel result) { + if (result.getDumpedClassFiles() != null) { + drawDumpedClassFiles(process, result.getDumpedClassFiles()); + + } else if (result.getMatchedClasses() != null) { + Element table = ClassUtils.renderMatchedClasses(result.getMatchedClasses()); + process.write(RenderUtil.render(table)).write("\n"); + } + } + + private void drawDumpedClassFiles(CommandProcess process, List classFiles) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + table.row(new LabelElement("HASHCODE").style(Decoration.bold.bold()), + new LabelElement("CLASSLOADER").style(Decoration.bold.bold()), + new LabelElement("LOCATION").style(Decoration.bold.bold())); + + for (ClassVO clazz : classFiles) { + table.row(label(clazz.getClassLoaderHash()).style(Decoration.bold.fg(Color.red)), + TypeRenderUtils.drawClassLoader(clazz), + label(clazz.getLocation()).style(Decoration.bold.fg(Color.red))); + } + + process.write(RenderUtil.render(table, process.width())) + .write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/GetStaticView.java b/core/src/main/java/com/taobao/arthas/core/command/view/GetStaticView.java new file mode 100644 index 00000000000..8be21d43588 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/GetStaticView.java @@ -0,0 +1,29 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.GetStaticModel; +import com.taobao.arthas.core.command.model.ObjectVO; +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.util.ClassUtils; +import com.taobao.arthas.core.util.StringUtils; +import com.taobao.arthas.core.view.ObjectView; +import com.taobao.text.ui.Element; +import com.taobao.text.util.RenderUtil; + +/** + * @author gongdewei 2020/4/20 + */ +public class GetStaticView extends ResultView { + + @Override + public void draw(CommandProcess process, GetStaticModel result) { + int expand = result.expand(); + if (result.getField() != null) { + ObjectVO field = result.getField(); + String valueStr = StringUtils.objectToString(expand >= 0 ? new ObjectView(field.getValue(), expand).draw() : field.getValue()); + process.write("field: " + field.getName() + "\n" + valueStr + "\n"); + } else if (result.getMatchedClasses() != null) { + Element table = ClassUtils.renderMatchedClasses(result.getMatchedClasses()); + process.write(RenderUtil.render(table)).write("\n"); + } + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/JadView.java b/core/src/main/java/com/taobao/arthas/core/command/view/JadView.java new file mode 100644 index 00000000000..e80041bfd6a --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/JadView.java @@ -0,0 +1,42 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.ClassVO; +import com.taobao.arthas.core.command.model.JadModel; +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.util.ClassUtils; +import com.taobao.arthas.core.util.TypeRenderUtils; +import com.taobao.text.Color; +import com.taobao.text.Decoration; +import com.taobao.text.lang.LangRenderUtil; +import com.taobao.text.ui.Element; +import com.taobao.text.ui.LabelElement; +import com.taobao.text.util.RenderUtil; + +/** + * @author gongdewei 2020/4/22 + */ +public class JadView extends ResultView { + + @Override + public void draw(CommandProcess process, JadModel result) { + + if (result.getMatchedClasses() != null) { + Element table = ClassUtils.renderMatchedClasses(result.getMatchedClasses()); + process.write(RenderUtil.render(table)).write("\n"); + } else { + ClassVO classInfo = result.getClassInfo(); + if (classInfo != null) { + process.write("\n"); + process.write(RenderUtil.render(new LabelElement("ClassLoader: ").style(Decoration.bold.fg(Color.red)), process.width())); + process.write(RenderUtil.render(TypeRenderUtils.drawClassLoader(classInfo), process.width()) + "\n"); + } + if (result.getLocation() != null) { + process.write(RenderUtil.render(new LabelElement("Location: ").style(Decoration.bold.fg(Color.red)), process.width())); + process.write(RenderUtil.render(new LabelElement(result.getLocation()).style(Decoration.bold.fg(Color.blue)), process.width()) + "\n"); + } + process.write(LangRenderUtil.render(result.getSource()) + "\n"); + process.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); + } + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/MemoryCompilerView.java b/core/src/main/java/com/taobao/arthas/core/command/view/MemoryCompilerView.java new file mode 100644 index 00000000000..e0f69a6c9fa --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/MemoryCompilerView.java @@ -0,0 +1,17 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.MemoryCompilerModel; +import com.taobao.arthas.core.shell.command.CommandProcess; + +/** + * @author gongdewei 2020/4/20 + */ +public class MemoryCompilerView extends ResultView { + @Override + public void draw(CommandProcess process, MemoryCompilerModel result) { + process.write("Memory compiler output:\n"); + for (String file : result.getFiles()) { + process.write(file + '\n'); + } + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/OgnlView.java b/core/src/main/java/com/taobao/arthas/core/command/view/OgnlView.java new file mode 100644 index 00000000000..509e951979f --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/OgnlView.java @@ -0,0 +1,19 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.OgnlModel; +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.util.StringUtils; +import com.taobao.arthas.core.view.ObjectView; + +/** + * @author gongdewei 2020/4/29 + */ +public class OgnlView extends ResultView { + @Override + public void draw(CommandProcess process, OgnlModel result) { + int expand = result.getExpand(); + Object value = result.getValue(); + String resultStr = StringUtils.objectToString(expand >= 0 ? new ObjectView(value, expand).draw() : value); + process.write(resultStr).write("\n"); + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/RedefineView.java b/core/src/main/java/com/taobao/arthas/core/command/view/RedefineView.java new file mode 100644 index 00000000000..e364332aafd --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/RedefineView.java @@ -0,0 +1,22 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.RedefineModel; +import com.taobao.arthas.core.shell.command.CommandProcess; + +/** + * @author gongdewei 2020/4/16 + */ +public class RedefineView extends ResultView { + + @Override + public void draw(CommandProcess process, RedefineModel result) { + StringBuilder sb = new StringBuilder(); + for (String aClass : result.getRedefinedClasses()) { + sb.append(aClass).append("\n"); + } + process.write("redefine success, size: " + result.getRedefinitionCount()) + .write(", classes:\n") + .write(sb.toString()); + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/ResultViewResolver.java b/core/src/main/java/com/taobao/arthas/core/command/view/ResultViewResolver.java index 6071e71d4bd..2eab88e8094 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/view/ResultViewResolver.java +++ b/core/src/main/java/com/taobao/arthas/core/command/view/ResultViewResolver.java @@ -47,6 +47,15 @@ private void initResultViews() { registerView(ShutdownView.class); //klass100 + registerView(ClassLoaderView.class); + registerView(DumpClassView.class); + registerView(GetStaticView.class); + registerView(JadView.class); + registerView(MemoryCompilerView.class); + registerView(OgnlView.class); + registerView(RedefineView.class); + registerView(SearchClassView.class); + registerView(SearchMethodView.class); //logger diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/RowAffectView.java b/core/src/main/java/com/taobao/arthas/core/command/view/RowAffectView.java new file mode 100644 index 00000000000..0e82635f7d5 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/RowAffectView.java @@ -0,0 +1,14 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.RowAffectModel; +import com.taobao.arthas.core.shell.command.CommandProcess; + +/** + * @author gongdewei 2020/4/8 + */ +public class RowAffectView extends ResultView { + @Override + public void draw(CommandProcess process, RowAffectModel result) { + process.write(result.affect() + "\n"); + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/SearchClassView.java b/core/src/main/java/com/taobao/arthas/core/command/view/SearchClassView.java new file mode 100644 index 00000000000..ecd22c60534 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/SearchClassView.java @@ -0,0 +1,26 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.SearchClassModel; +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.util.ClassUtils; +import com.taobao.text.util.RenderUtil; + +/** + * @author gongdewei 2020/4/8 + */ +public class SearchClassView extends ResultView { + @Override + public void draw(CommandProcess process, SearchClassModel result) { + + if (result.isDetail()) { + process.write(RenderUtil.render(ClassUtils.renderClassInfo(result.getClassInfo(), + result.withField(), result.expand()), process.width())); + process.write("\n"); + } else if (result.getClassNames() != null) { + for (String className : result.getClassNames()) { + process.write(className).write("\n"); + } + } + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/SearchMethodView.java b/core/src/main/java/com/taobao/arthas/core/command/view/SearchMethodView.java new file mode 100644 index 00000000000..d58027069e9 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/view/SearchMethodView.java @@ -0,0 +1,39 @@ +package com.taobao.arthas.core.command.view; + +import com.taobao.arthas.core.command.model.SearchMethodModel; +import com.taobao.arthas.core.command.model.MethodVO; +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.util.ClassUtils; +import com.taobao.text.util.RenderUtil; + + +/** + * render for SearchMethodCommand + * @author gongdewei 2020/4/9 + */ +public class SearchMethodView extends ResultView { + @Override + public void draw(CommandProcess process, SearchMethodModel result) { + boolean detail = result.isDetail(); + MethodVO methodInfo = result.getMethodInfo(); + + if (detail) { + if (methodInfo.isConstructor()) { + //render constructor + process.write(RenderUtil.render(ClassUtils.renderConstructor(methodInfo), process.width()) + "\n"); + } else { + //render method + process.write(RenderUtil.render(ClassUtils.renderMethod(methodInfo), process.width()) + "\n"); + } + } else { + //java.util.List indexOf(Ljava/lang/Object;)I + //className methodName+Descriptor + process.write(methodInfo.getDeclaringClass()) + .write(" ") + .write(methodInfo.getMethodName()) + .write(methodInfo.getDescriptor()) + .write("\n"); + } + + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java b/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java index 4e6e28652bc..7def1fd300a 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java +++ b/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java @@ -2,12 +2,27 @@ import static com.taobao.text.ui.Element.label; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; import java.security.CodeSource; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import com.alibaba.arthas.deps.org.objectweb.asm.Type; +import com.taobao.arthas.core.command.model.ClassLoaderVO; +import com.taobao.arthas.core.command.model.ClassVO; +import com.taobao.arthas.core.command.model.MethodVO; +import com.taobao.text.Color; import com.taobao.text.Decoration; import com.taobao.text.ui.Element; +import com.taobao.text.ui.LabelElement; import com.taobao.text.ui.TableElement; +import static com.taobao.text.Decoration.bold; + /** * * @author hengyunabc 2018-10-18 @@ -31,6 +46,10 @@ public static Element renderClassInfo(Class clazz) { return renderClassInfo(clazz, false, null); } + public static Element renderClassInfo(ClassVO clazz) { + return renderClassInfo(clazz, false, null); + } + public static Element renderClassInfo(Class clazz, boolean isPrintField, Integer expand) { TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); CodeSource cs = clazz.getProtectionDomain().getCodeSource(); @@ -61,4 +80,229 @@ public static Element renderClassInfo(Class clazz, boolean isPrintField, Inte return table; } + public static Element renderClassInfo(ClassVO clazz, boolean isPrintField, Integer expand) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + + table.row(label("class-info").style(Decoration.bold.bold()), label(clazz.getClassInfo())) + .row(label("code-source").style(Decoration.bold.bold()), label(clazz.getCodeSource())) + .row(label("name").style(Decoration.bold.bold()), label(clazz.getName())) + .row(label("isInterface").style(Decoration.bold.bold()), label("" + clazz.getInterface())) + .row(label("isAnnotation").style(Decoration.bold.bold()), label("" + clazz.getAnnotation())) + .row(label("isEnum").style(Decoration.bold.bold()), label("" + clazz.getEnum())) + .row(label("isAnonymousClass").style(Decoration.bold.bold()), label("" + clazz.getAnonymousClass())) + .row(label("isArray").style(Decoration.bold.bold()), label("" + clazz.getArray())) + .row(label("isLocalClass").style(Decoration.bold.bold()), label("" + clazz.getLocalClass())) + .row(label("isMemberClass").style(Decoration.bold.bold()), label("" + clazz.getMemberClass())) + .row(label("isPrimitive").style(Decoration.bold.bold()), label("" + clazz.getPrimitive())) + .row(label("isSynthetic").style(Decoration.bold.bold()), label("" + clazz.getSynthetic())) + .row(label("simple-name").style(Decoration.bold.bold()), label(clazz.getSimpleName())) + .row(label("modifier").style(Decoration.bold.bold()), label(clazz.getModifier())) + .row(label("annotation").style(Decoration.bold.bold()), label(StringUtils.join(clazz.getAnnotations(), ","))) + .row(label("interfaces").style(Decoration.bold.bold()), label(StringUtils.join(clazz.getInterfaces(), ","))) + .row(label("super-class").style(Decoration.bold.bold()), TypeRenderUtils.drawSuperClass(clazz)) + .row(label("class-loader").style(Decoration.bold.bold()), TypeRenderUtils.drawClassLoader(clazz)) + .row(label("classLoaderHash").style(Decoration.bold.bold()), label(clazz.getClassLoaderHash())); + + if (isPrintField) { + table.row(label("fields").style(Decoration.bold.bold()), TypeRenderUtils.drawField(clazz, expand)); + } + return table; + } + + public static ClassVO createClassInfo(Class clazz, boolean detail, boolean withFields) { + CodeSource cs = clazz.getProtectionDomain().getCodeSource(); + ClassVO classInfo = new ClassVO(); + classInfo.setName(StringUtils.classname(clazz)); + if (detail) { + classInfo.setClassInfo(StringUtils.classname(clazz)); + classInfo.setCodeSource(ClassUtils.getCodeSource(cs)); + classInfo.setInterface(clazz.isInterface()); + classInfo.setAnnotation(clazz.isAnnotation()); + classInfo.setEnum(clazz.isEnum()); + classInfo.setAnonymousClass(clazz.isAnonymousClass()); + classInfo.setArray(clazz.isArray()); + classInfo.setLocalClass(clazz.isLocalClass()); + classInfo.setMemberClass(clazz.isMemberClass()); + classInfo.setPrimitive(clazz.isPrimitive()); + classInfo.setSynthetic(clazz.isSynthetic()); + classInfo.setSimpleName(clazz.getSimpleName()); + classInfo.setModifier(StringUtils.modifier(clazz.getModifiers(), ',')); + classInfo.setAnnotations(TypeRenderUtils.getAnnotations(clazz)); + classInfo.setInterfaces(TypeRenderUtils.getInterfaces(clazz)); + classInfo.setSuperClass(TypeRenderUtils.getSuperClass(clazz)); + classInfo.setClassloader(TypeRenderUtils.getClassloader(clazz)); + classInfo.setClassLoaderHash(StringUtils.classLoaderHash(clazz)); + } + if (withFields) { + classInfo.setFields(TypeRenderUtils.getFields(clazz)); + } + return classInfo; + } + + public static ClassVO createSimpleClassInfo(Class clazz) { + ClassVO classInfo = new ClassVO(); + classInfo.setName(StringUtils.classname(clazz)); + classInfo.setClassloader(TypeRenderUtils.getClassloader(clazz)); + classInfo.setClassLoaderHash(StringUtils.classLoaderHash(clazz)); + return classInfo; + } + + public static MethodVO createMethodInfo(Method method, Class clazz, boolean detail) { + MethodVO methodVO = new MethodVO(); + methodVO.setDeclaringClass(clazz.getName()); + methodVO.setMethodName(method.getName()); + methodVO.setDescriptor(Type.getMethodDescriptor(method)); + methodVO.setConstructor(false); + if (detail) { + methodVO.setModifier(StringUtils.modifier(method.getModifiers(), ',')); + methodVO.setAnnotations(TypeRenderUtils.getAnnotations(method.getDeclaredAnnotations())); + methodVO.setParameters(getClassNameList(method.getParameterTypes())); + methodVO.setReturnType(StringUtils.classname(method.getReturnType())); + methodVO.setExceptions(getClassNameList(method.getExceptionTypes())); + methodVO.setClassLoaderHash(StringUtils.classLoaderHash(clazz)); + } + return methodVO; + } + + public static MethodVO createMethodInfo(Constructor constructor, Class clazz, boolean detail) { + MethodVO methodVO = new MethodVO(); + methodVO.setDeclaringClass(clazz.getName()); + methodVO.setDescriptor(Type.getConstructorDescriptor(constructor)); + methodVO.setMethodName(""); + methodVO.setConstructor(true); + if (detail) { + methodVO.setModifier(StringUtils.modifier(constructor.getModifiers(), ',')); + methodVO.setAnnotations(TypeRenderUtils.getAnnotations(constructor.getDeclaredAnnotations())); + methodVO.setParameters(getClassNameList(constructor.getParameterTypes())); + methodVO.setExceptions(getClassNameList(constructor.getExceptionTypes())); + methodVO.setClassLoaderHash(StringUtils.classLoaderHash(clazz)); + } + return methodVO; + } + + + public static Element renderMethod(Method method, Class clazz) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + table.row(label("declaring-class").style(bold.bold()), label(method.getDeclaringClass().getName())) + .row(label("method-name").style(bold.bold()), label(method.getName()).style(bold.bold())) + .row(label("modifier").style(bold.bold()), label(StringUtils.modifier(method.getModifiers(), ','))) + .row(label("annotation").style(bold.bold()), label(TypeRenderUtils.drawAnnotation(method))) + .row(label("parameters").style(bold.bold()), label(TypeRenderUtils.drawParameters(method))) + .row(label("return").style(bold.bold()), label(TypeRenderUtils.drawReturn(method))) + .row(label("exceptions").style(bold.bold()), label(TypeRenderUtils.drawExceptions(method))) + .row(label("classLoaderHash").style(bold.bold()), label(StringUtils.classLoaderHash(clazz))); + return table; + } + + public static Element renderMethod(MethodVO method) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + table.row(label("declaring-class").style(bold.bold()), label(method.getDeclaringClass())) + .row(label("method-name").style(bold.bold()), label(method.getMethodName()).style(bold.bold())) + .row(label("modifier").style(bold.bold()), label(method.getModifier())) + .row(label("annotation").style(bold.bold()), label(TypeRenderUtils.drawAnnotation(method.getAnnotations()))) + .row(label("parameters").style(bold.bold()), label(TypeRenderUtils.drawParameters(method.getParameters()))) + .row(label("return").style(bold.bold()), label(method.getReturnType())) + .row(label("exceptions").style(bold.bold()), label(TypeRenderUtils.drawExceptions(method.getExceptions()))) + .row(label("classLoaderHash").style(bold.bold()), label(method.getClassLoaderHash())); + return table; + } + + public static Element renderConstructor(Constructor constructor, Class clazz) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + table.row(label("declaring-class").style(bold.bold()), label(constructor.getDeclaringClass().getName())) + .row(label("constructor-name").style(bold.bold()), label("").style(bold.bold())) + .row(label("modifier").style(bold.bold()), label(StringUtils.modifier(constructor.getModifiers(), ','))) + .row(label("annotation").style(bold.bold()), label(TypeRenderUtils.drawAnnotation(constructor.getDeclaredAnnotations()))) + .row(label("parameters").style(bold.bold()), label(TypeRenderUtils.drawParameters(constructor))) + .row(label("exceptions").style(bold.bold()), label(TypeRenderUtils.drawExceptions(constructor))) + .row(label("classLoaderHash").style(bold.bold()), label(StringUtils.classLoaderHash(clazz))); + return table; + } + + public static Element renderConstructor(MethodVO constructor) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + table.row(label("declaring-class").style(bold.bold()), label(constructor.getDeclaringClass())) + .row(label("constructor-name").style(bold.bold()), label("").style(bold.bold())) + .row(label("modifier").style(bold.bold()), label(constructor.getModifier())) + .row(label("annotation").style(bold.bold()), label(TypeRenderUtils.drawAnnotation(constructor.getAnnotations()))) + .row(label("parameters").style(bold.bold()), label(TypeRenderUtils.drawParameters(constructor.getParameters()))) + .row(label("exceptions").style(bold.bold()), label(TypeRenderUtils.drawExceptions(constructor.getExceptions()))) + .row(label("classLoaderHash").style(bold.bold()), label(constructor.getClassLoaderHash())); + return table; + } + + public static String[] getClassNameList(Class[] classes) { + List list = new ArrayList(); + for (Class anInterface : classes) { + list.add(StringUtils.classname(anInterface)); + } + return list.toArray(new String[0]); + } + + public static List createClassVOList(Set> matchedClasses) { + List classVOs = new ArrayList(matchedClasses.size()); + for (Class aClass : matchedClasses) { + ClassVO classVO = createSimpleClassInfo(aClass); + classVOs.add(classVO); + } + return classVOs; + } + + public static ClassLoaderVO createClassLoaderVO(ClassLoader classLoader) { + ClassLoaderVO classLoaderVO = new ClassLoaderVO(); + classLoaderVO.setHash(classLoaderHash(classLoader)); + classLoaderVO.setName(classLoader==null?"BootstrapClassLoader":classLoader.toString()); + ClassLoader parent = classLoader == null ? null : classLoader.getParent(); + classLoaderVO.setParent(parent==null?null:parent.toString()); + return classLoaderVO; + } + + public static String classLoaderHash(Class clazz) { + if (clazz == null || clazz.getClassLoader() == null) { + return "null"; + } + return Integer.toHexString(clazz.getClassLoader().hashCode()); + } + + public static String classLoaderHash(ClassLoader classLoader) { + if (classLoader == null ) { + return "null"; + } + return Integer.toHexString(classLoader.hashCode()); + } + + public static Element renderMatchedClasses(Collection matchedClasses) { + TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); + table.row(new LabelElement("NAME").style(Decoration.bold.bold()), + new LabelElement("HASHCODE").style(Decoration.bold.bold()), + new LabelElement("CLASSLOADER").style(Decoration.bold.bold())); + + for (ClassVO c : matchedClasses) { + table.row(label(c.getName()), + label(c.getClassLoaderHash()).style(Decoration.bold.fg(Color.red)), + TypeRenderUtils.drawClassLoader(c)); + } + return table; + } + + /** + * 转换增强字节码回调方法中的非标准类名 + * normalizeClassName: a/b/c/MyClass -> a.b.c.MyClass + * @param className maybe path class name + * @param normalizeClassNameMap + */ + public static String normalizeClassName(String className, Map normalizeClassNameMap) { + //如果类名包含'/',需要转换为标准类名 + String normalClassName = null; + if (className.indexOf('/') != -1) { + normalClassName = normalizeClassNameMap.get(className); + if (normalClassName == null) { + normalClassName = StringUtils.normalizeClassName(className); + normalizeClassNameMap.put(className, normalClassName); + } + } else { + normalClassName = className; + } + return normalClassName; + } } diff --git a/core/src/main/java/com/taobao/arthas/core/util/ResultUtils.java b/core/src/main/java/com/taobao/arthas/core/util/ResultUtils.java new file mode 100644 index 00000000000..9974990f66a --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/util/ResultUtils.java @@ -0,0 +1,50 @@ +package com.taobao.arthas.core.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * 命令结果处理工具类 + * @author gongdewei 2020/5/18 + */ +public class ResultUtils { + + /** + * 分页处理class列表,转换为className列表 + * @param classes + * @param pageSize + * @param handler + */ + public static void processClassNames(Collection classes, int pageSize, PaginationHandler> handler) { + List classNames = new ArrayList(pageSize); + int segment = 0; + for (Class aClass : classes) { + classNames.add(aClass.getName()); + //slice segment + if(classNames.size() >= pageSize) { + handler.handle(classNames, segment++); + classNames = new ArrayList(pageSize); + } + } + //last segment + if (classNames.size() > 0) { + handler.handle(classNames, segment++); + } + } + + /** + * 分页数据处理回调接口 + * @param + */ + public interface PaginationHandler { + + /** + * 处理分页数据 + * @param list + * @param segment + * @return true 继续处理剩余数据, false 终止处理 + */ + boolean handle(T list, int segment); + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/util/StringUtils.java b/core/src/main/java/com/taobao/arthas/core/util/StringUtils.java index 320f67eed18..54c7974c222 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/StringUtils.java +++ b/core/src/main/java/com/taobao/arthas/core/util/StringUtils.java @@ -71,7 +71,7 @@ public static String normalizeClassName(String className) { return StringUtils.replace(className, "/", "."); } - public static String concat(String seperator, Class... types) { + public static String concat(String separator, Class... types) { if (types == null || types.length == 0) { return Constants.EMPTY_STRING; } @@ -80,7 +80,23 @@ public static String concat(String seperator, Class... types) { for (int i = 0; i < types.length; i++) { builder.append(classname(types[i])); if (i < types.length - 1) { - builder.append(seperator); + builder.append(separator); + } + } + + return builder.toString(); + } + + public static String concat(String separator, String... strs) { + if (strs == null || strs.length == 0) { + return Constants.EMPTY_STRING; + } + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < strs.length; i++) { + builder.append(strs[i]); + if (i < strs.length - 1) { + builder.append(separator); } } diff --git a/core/src/main/java/com/taobao/arthas/core/util/TypeRenderUtils.java b/core/src/main/java/com/taobao/arthas/core/util/TypeRenderUtils.java index d6e2202ae2f..f0771733f6b 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/TypeRenderUtils.java +++ b/core/src/main/java/com/taobao/arthas/core/util/TypeRenderUtils.java @@ -1,5 +1,7 @@ package com.taobao.arthas.core.util; +import com.taobao.arthas.core.command.model.ClassVO; +import com.taobao.arthas.core.command.model.FieldVO; import com.taobao.arthas.core.view.ObjectView; import com.taobao.text.ui.Element; import com.taobao.text.ui.TableElement; @@ -10,6 +12,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -41,6 +44,10 @@ public static String drawParameters(Constructor constructor) { return StringUtils.concat("\n", constructor.getParameterTypes()); } + public static String drawParameters(String[] parameterTypes) { + return StringUtils.concat("\n", parameterTypes); + } + public static String drawReturn(Method method) { return StringUtils.classname(method.getReturnType()); } @@ -53,6 +60,10 @@ public static String drawExceptions(Constructor constructor) { return StringUtils.concat("\n", constructor.getExceptionTypes()); } + public static String drawExceptions(String[] exceptionTypes) { + return StringUtils.concat("\n", exceptionTypes); + } + public static Element drawSuperClass(Class clazz) { TreeElement root = new TreeElement(); TreeElement parent = root; @@ -76,6 +87,10 @@ public static Element drawSuperClass(Class clazz) { return root; } + public static Element drawSuperClass(ClassVO clazz) { + return drawTree(clazz.getSuperClass()); + } + public static Element drawClassLoader(Class clazz) { TreeElement root = new TreeElement(); TreeElement parent = root; @@ -97,6 +112,22 @@ public static Element drawClassLoader(Class clazz) { return root; } + public static Element drawClassLoader(ClassVO clazz) { + String[] classloaders = clazz.getClassloader(); + return drawTree(classloaders); + } + + public static Element drawTree(String[] nodes) { + TreeElement root = new TreeElement(); + TreeElement parent = root; + for (String node : nodes) { + TreeElement child = new TreeElement(label(node)); + parent.addChild(child); + parent = child; + } + return root; + } + public static Element drawField(Class clazz, Integer expand) { TableElement fieldsTable = new TableElement(1).leftCellPadding(0).rightCellPadding(0); Field[] fields = clazz.getDeclaredFields(); @@ -126,6 +157,36 @@ public static Element drawField(Class clazz, Integer expand) { return fieldsTable; } + public static Element drawField(ClassVO clazz, Integer expand) { + TableElement fieldsTable = new TableElement(1).leftCellPadding(0).rightCellPadding(0); + FieldVO[] fields = clazz.getFields(); + if (fields == null || fields.length == 0) { + return fieldsTable; + } + + for (FieldVO field : fields) { + TableElement fieldTable = new TableElement().leftCellPadding(0).rightCellPadding(1); + fieldTable.row("name", field.getName()) + .row("type", field.getType()) + .row("modifier", field.getModifier()); + + String[] annotations = field.getAnnotations(); + if (annotations != null && annotations.length > 0) { + fieldTable.row("annotation", drawAnnotation(annotations)); + } + + if (field.isStatic()) { + Object o = (expand != null && expand >= 0) ? new ObjectView(field.getValue(), expand).draw() : field.getValue(); + fieldTable.row("value", StringUtils.objectToString(o)); + } + + fieldTable.row(label("")); + fieldsTable.row(fieldTable); + } + + return fieldsTable; + } + public static String renderMethodSignature(Method method) { StringBuilder sb = new StringBuilder(); sb.append(StringUtils.modifier(method.getModifiers(), ' ')).append(" "); @@ -162,4 +223,98 @@ public static String drawAnnotation(Annotation... annotations) { } return StringUtils.concat(",", types.toArray(new Class[0])); } + + public static String drawAnnotation(String... annotations) { + return StringUtils.concat(",", annotations); + } + + public static String[] getAnnotations(Class clazz) { + return getAnnotations(clazz.getDeclaredAnnotations()); + } + + public static String[] getAnnotations(Annotation[] annotations) { + List list = new ArrayList(); + if (annotations != null && annotations.length > 0) { + for (Annotation annotation : annotations) { + list.add(StringUtils.classname(annotation.annotationType())); + } + } + return list.toArray(new String[0]); + } + + public static String[] getInterfaces(Class clazz) { + Class[] interfaces = clazz.getInterfaces(); + return ClassUtils.getClassNameList(interfaces); + } + + public static String[] getSuperClass(Class clazz) { + List list = new ArrayList(); + Class superClass = clazz.getSuperclass(); + if (null != superClass) { + list.add(StringUtils.classname(superClass)); + while (true) { + superClass = superClass.getSuperclass(); + if (null == superClass) { + break; + } + list.add(StringUtils.classname(superClass)); + } + } + return list.toArray(new String[0]); + } + + public static String[] getClassloader(Class clazz) { + List list = new ArrayList(); + ClassLoader loader = clazz.getClassLoader(); + if (null != loader) { + list.add(loader.toString()); + while (true) { + loader = loader.getParent(); + if (null == loader) { + break; + } + list.add(loader.toString()); + } + } + return list.toArray(new String[0]); + } + + public static FieldVO[] getFields(Class clazz) { + Field[] fields = clazz.getDeclaredFields(); + if (fields == null || fields.length == 0) { + return new FieldVO[0]; + } + + List list = new ArrayList(fields.length); + for (Field field : fields) { + FieldVO fieldVO = new FieldVO(); + fieldVO.setName(field.getName()); + fieldVO.setType(StringUtils.classname(field.getType())); + fieldVO.setModifier(StringUtils.modifier(field.getModifiers(), ',')); + fieldVO.setAnnotations(getAnnotations(field.getAnnotations())); + if (Modifier.isStatic(field.getModifiers())) { + fieldVO.setStatic(true); + fieldVO.setValue(getFieldValue(field)); + } else { + fieldVO.setStatic(false); + } + list.add(fieldVO); + } + return list.toArray(new FieldVO[0]); + } + + private static Object getFieldValue(Field field) { + final boolean isAccessible = field.isAccessible(); + try { + field.setAccessible(true); + Object value = field.get(null); + return value; + } catch (IllegalAccessException e) { + // no op + } finally { + field.setAccessible(isAccessible); + } + return null; + } + } From 015a8c354d52b152259b49b149dab8ba97f2592e Mon Sep 17 00:00:00 2001 From: gongdewei Date: Wed, 1 Jul 2020 20:28:07 +0800 Subject: [PATCH 02/18] remove unused code --- .../taobao/arthas/core/util/ClassUtils.java | 81 ------------ .../arthas/core/util/TypeRenderUtils.java | 118 ------------------ 2 files changed, 199 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java b/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java index 7def1fd300a..48dbf2a6256 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java +++ b/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java @@ -8,7 +8,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.Set; import com.alibaba.arthas.deps.org.objectweb.asm.Type; @@ -42,44 +41,10 @@ public static boolean isLambdaClass(Class clazz) { return clazz.getName().contains("$$Lambda$"); } - public static Element renderClassInfo(Class clazz) { - return renderClassInfo(clazz, false, null); - } - public static Element renderClassInfo(ClassVO clazz) { return renderClassInfo(clazz, false, null); } - public static Element renderClassInfo(Class clazz, boolean isPrintField, Integer expand) { - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - CodeSource cs = clazz.getProtectionDomain().getCodeSource(); - - table.row(label("class-info").style(Decoration.bold.bold()), label(StringUtils.classname(clazz))) - .row(label("code-source").style(Decoration.bold.bold()), label(getCodeSource(cs))) - .row(label("name").style(Decoration.bold.bold()), label(StringUtils.classname(clazz))) - .row(label("isInterface").style(Decoration.bold.bold()), label("" + clazz.isInterface())) - .row(label("isAnnotation").style(Decoration.bold.bold()), label("" + clazz.isAnnotation())) - .row(label("isEnum").style(Decoration.bold.bold()), label("" + clazz.isEnum())) - .row(label("isAnonymousClass").style(Decoration.bold.bold()), label("" + clazz.isAnonymousClass())) - .row(label("isArray").style(Decoration.bold.bold()), label("" + clazz.isArray())) - .row(label("isLocalClass").style(Decoration.bold.bold()), label("" + clazz.isLocalClass())) - .row(label("isMemberClass").style(Decoration.bold.bold()), label("" + clazz.isMemberClass())) - .row(label("isPrimitive").style(Decoration.bold.bold()), label("" + clazz.isPrimitive())) - .row(label("isSynthetic").style(Decoration.bold.bold()), label("" + clazz.isSynthetic())) - .row(label("simple-name").style(Decoration.bold.bold()), label(clazz.getSimpleName())) - .row(label("modifier").style(Decoration.bold.bold()), label(StringUtils.modifier(clazz.getModifiers(), ','))) - .row(label("annotation").style(Decoration.bold.bold()), label(TypeRenderUtils.drawAnnotation(clazz))) - .row(label("interfaces").style(Decoration.bold.bold()), label(TypeRenderUtils.drawInterface(clazz))) - .row(label("super-class").style(Decoration.bold.bold()), TypeRenderUtils.drawSuperClass(clazz)) - .row(label("class-loader").style(Decoration.bold.bold()), TypeRenderUtils.drawClassLoader(clazz)) - .row(label("classLoaderHash").style(Decoration.bold.bold()), label(StringUtils.classLoaderHash(clazz))); - - if (isPrintField) { - table.row(label("fields").style(Decoration.bold.bold()), TypeRenderUtils.drawField(clazz, expand)); - } - return table; - } - public static Element renderClassInfo(ClassVO clazz, boolean isPrintField, Integer expand) { TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); @@ -180,20 +145,6 @@ public static MethodVO createMethodInfo(Constructor constructor, Class clazz, bo return methodVO; } - - public static Element renderMethod(Method method, Class clazz) { - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - table.row(label("declaring-class").style(bold.bold()), label(method.getDeclaringClass().getName())) - .row(label("method-name").style(bold.bold()), label(method.getName()).style(bold.bold())) - .row(label("modifier").style(bold.bold()), label(StringUtils.modifier(method.getModifiers(), ','))) - .row(label("annotation").style(bold.bold()), label(TypeRenderUtils.drawAnnotation(method))) - .row(label("parameters").style(bold.bold()), label(TypeRenderUtils.drawParameters(method))) - .row(label("return").style(bold.bold()), label(TypeRenderUtils.drawReturn(method))) - .row(label("exceptions").style(bold.bold()), label(TypeRenderUtils.drawExceptions(method))) - .row(label("classLoaderHash").style(bold.bold()), label(StringUtils.classLoaderHash(clazz))); - return table; - } - public static Element renderMethod(MethodVO method) { TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); table.row(label("declaring-class").style(bold.bold()), label(method.getDeclaringClass())) @@ -207,18 +158,6 @@ public static Element renderMethod(MethodVO method) { return table; } - public static Element renderConstructor(Constructor constructor, Class clazz) { - TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); - table.row(label("declaring-class").style(bold.bold()), label(constructor.getDeclaringClass().getName())) - .row(label("constructor-name").style(bold.bold()), label("").style(bold.bold())) - .row(label("modifier").style(bold.bold()), label(StringUtils.modifier(constructor.getModifiers(), ','))) - .row(label("annotation").style(bold.bold()), label(TypeRenderUtils.drawAnnotation(constructor.getDeclaredAnnotations()))) - .row(label("parameters").style(bold.bold()), label(TypeRenderUtils.drawParameters(constructor))) - .row(label("exceptions").style(bold.bold()), label(TypeRenderUtils.drawExceptions(constructor))) - .row(label("classLoaderHash").style(bold.bold()), label(StringUtils.classLoaderHash(clazz))); - return table; - } - public static Element renderConstructor(MethodVO constructor) { TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); table.row(label("declaring-class").style(bold.bold()), label(constructor.getDeclaringClass())) @@ -285,24 +224,4 @@ public static Element renderMatchedClasses(Collection matchedClasses) { return table; } - /** - * 转换增强字节码回调方法中的非标准类名 - * normalizeClassName: a/b/c/MyClass -> a.b.c.MyClass - * @param className maybe path class name - * @param normalizeClassNameMap - */ - public static String normalizeClassName(String className, Map normalizeClassNameMap) { - //如果类名包含'/',需要转换为标准类名 - String normalClassName = null; - if (className.indexOf('/') != -1) { - normalClassName = normalizeClassNameMap.get(className); - if (normalClassName == null) { - normalClassName = StringUtils.normalizeClassName(className); - normalizeClassNameMap.put(className, normalClassName); - } - } else { - normalClassName = className; - } - return normalClassName; - } } diff --git a/core/src/main/java/com/taobao/arthas/core/util/TypeRenderUtils.java b/core/src/main/java/com/taobao/arthas/core/util/TypeRenderUtils.java index f0771733f6b..72475e5bfba 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/TypeRenderUtils.java +++ b/core/src/main/java/com/taobao/arthas/core/util/TypeRenderUtils.java @@ -24,14 +24,6 @@ */ public class TypeRenderUtils { - public static String drawAnnotation(Class clazz) { - return drawAnnotation(clazz.getDeclaredAnnotations()); - } - - public static String drawAnnotation(Method method) { - return drawAnnotation(method.getDeclaredAnnotations()); - } - public static String drawInterface(Class clazz) { return StringUtils.concat(",", clazz.getInterfaces()); } @@ -64,54 +56,10 @@ public static String drawExceptions(String[] exceptionTypes) { return StringUtils.concat("\n", exceptionTypes); } - public static Element drawSuperClass(Class clazz) { - TreeElement root = new TreeElement(); - TreeElement parent = root; - - Class superClass = clazz.getSuperclass(); - if (null != superClass) { - TreeElement child = new TreeElement(label(StringUtils.classname(superClass))); - parent.addChild(child); - parent = child; - - while (true) { - superClass = superClass.getSuperclass(); - if (null == superClass) { - break; - } - TreeElement tempChild = new TreeElement(label(StringUtils.classname(superClass))); - parent.addChild(tempChild); - parent = tempChild; - } - } - return root; - } - public static Element drawSuperClass(ClassVO clazz) { return drawTree(clazz.getSuperClass()); } - public static Element drawClassLoader(Class clazz) { - TreeElement root = new TreeElement(); - TreeElement parent = root; - ClassLoader loader = clazz.getClassLoader(); - if (null != loader) { - TreeElement child = new TreeElement(label(loader.toString())); - parent.addChild(child); - parent = child; - while (true) { - loader = loader.getParent(); - if (null == loader) { - break; - } - TreeElement tempChild = new TreeElement(label(loader.toString())); - parent.addChild(tempChild); - parent = tempChild; - } - } - return root; - } - public static Element drawClassLoader(ClassVO clazz) { String[] classloaders = clazz.getClassloader(); return drawTree(classloaders); @@ -128,35 +76,6 @@ public static Element drawTree(String[] nodes) { return root; } - public static Element drawField(Class clazz, Integer expand) { - TableElement fieldsTable = new TableElement(1).leftCellPadding(0).rightCellPadding(0); - Field[] fields = clazz.getDeclaredFields(); - if (fields == null || fields.length == 0) { - return fieldsTable; - } - - for (Field field : fields) { - TableElement fieldTable = new TableElement().leftCellPadding(0).rightCellPadding(1); - fieldTable.row("name", field.getName()) - .row("type", StringUtils.classname(field.getType())) - .row("modifier", StringUtils.modifier(field.getModifiers(), ',')); - - Annotation[] annotations = field.getAnnotations(); - if (annotations != null && annotations.length > 0) { - fieldTable.row("annotation", drawAnnotation(annotations)); - } - - if (Modifier.isStatic(field.getModifiers())) { - fieldTable.row("value", drawFieldValue(field, expand)); - } - - fieldTable.row(label("")); - fieldsTable.row(fieldTable); - } - - return fieldsTable; - } - public static Element drawField(ClassVO clazz, Integer expand) { TableElement fieldsTable = new TableElement(1).leftCellPadding(0).rightCellPadding(0); FieldVO[] fields = clazz.getFields(); @@ -187,43 +106,6 @@ public static Element drawField(ClassVO clazz, Integer expand) { return fieldsTable; } - public static String renderMethodSignature(Method method) { - StringBuilder sb = new StringBuilder(); - sb.append(StringUtils.modifier(method.getModifiers(), ' ')).append(" "); - sb.append(TypeRenderUtils.drawReturn(method)).append(" "); - sb.append(method.getName()).append(" "); - sb.append("("); - sb.append(StringUtils.concat(", ", method.getParameterTypes())); - sb.append(")"); - return sb.toString(); - } - - private static String drawFieldValue(Field field, Integer expand) { - final boolean isAccessible = field.isAccessible(); - try { - field.setAccessible(true); - Object value = field.get(null); - Object o = (expand != null && expand >= 0) ? new ObjectView(value, expand).draw() : value; - return StringUtils.objectToString(o); - } catch (IllegalAccessException e) { - // no op - } finally { - field.setAccessible(isAccessible); - } - return Constants.EMPTY_STRING; - } - - public static String drawAnnotation(Annotation... annotations) { - List> types = Collections.emptyList(); - if (annotations != null && annotations.length > 0) { - types = new LinkedList>(); - for (Annotation annotation : annotations) { - types.add(annotation.annotationType()); - } - } - return StringUtils.concat(",", types.toArray(new Class[0])); - } - public static String drawAnnotation(String... annotations) { return StringUtils.concat(",", annotations); } From f48ba5957764ad86418bfa7395ba642fa3ccb67d Mon Sep 17 00:00:00 2001 From: gongdewei Date: Tue, 7 Jul 2020 14:28:17 +0800 Subject: [PATCH 03/18] make AnnotatedCommand.process() return StatusModel instead of call process.end() anywhere --- .../core/command/basic1000/CatCommand.java | 42 +++----- .../core/command/basic1000/ClsCommand.java | 8 +- .../core/command/basic1000/EchoCommand.java | 6 +- .../core/command/basic1000/GrepCommand.java | 5 +- .../core/command/basic1000/HelpCommand.java | 5 +- .../command/basic1000/HistoryCommand.java | 5 +- .../core/command/basic1000/KeymapCommand.java | 11 ++- .../command/basic1000/OptionsCommand.java | 16 +--- .../core/command/basic1000/PwdCommand.java | 5 +- .../core/command/basic1000/ResetCommand.java | 9 +- .../command/basic1000/SessionCommand.java | 5 +- .../command/basic1000/ShutdownCommand.java | 4 +- .../core/command/basic1000/StopCommand.java | 4 +- .../command/basic1000/SystemEnvCommand.java | 8 +- .../basic1000/SystemPropertyCommand.java | 10 +- .../core/command/basic1000/TeeCommand.java | 5 +- .../command/basic1000/VMOptionCommand.java | 14 +-- .../command/basic1000/VersionCommand.java | 5 +- .../core/command/hidden/JulyCommand.java | 6 +- .../core/command/hidden/ThanksCommand.java | 6 +- .../command/klass100/ClassLoaderCommand.java | 88 ++++++++--------- .../command/klass100/DumpClassCommand.java | 54 +++++------ .../command/klass100/GetStaticCommand.java | 96 +++++++++---------- .../core/command/klass100/JadCommand.java | 20 ++-- .../klass100/MemoryCompilerCommand.java | 14 +-- .../core/command/klass100/OgnlCommand.java | 19 ++-- .../command/klass100/RedefineCommand.java | 24 ++--- .../command/klass100/SearchClassCommand.java | 13 ++- .../command/klass100/SearchMethodCommand.java | 58 +++++------ .../core/command/logger/LoggerCommand.java | 4 +- .../core/command/model/StatusModel.java | 51 ++++++++++ .../command/monitor200/DashboardCommand.java | 5 +- .../command/monitor200/EnhancerCommand.java | 5 +- .../command/monitor200/HeapDumpCommand.java | 4 +- .../core/command/monitor200/JvmCommand.java | 5 +- .../core/command/monitor200/MBeanCommand.java | 5 +- .../monitor200/PerfCounterCommand.java | 5 +- .../command/monitor200/ProfilerCommand.java | 9 +- .../command/monitor200/ThreadCommand.java | 5 +- .../command/monitor200/TimeTunnelCommand.java | 5 +- .../core/shell/command/AnnotatedCommand.java | 4 +- .../command/impl/AnnotatedCommandImpl.java | 14 ++- 42 files changed, 378 insertions(+), 308 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java index 54149a60e0d..f53fec57e4b 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java @@ -8,6 +8,7 @@ import com.taobao.arthas.core.command.model.CatModel; import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -47,28 +48,31 @@ public void setSizeLimit(Integer sizeLimit) { } @Override - public void process(CommandProcess process) { - if (!verifyOptions(process)) { - return; + public StatusModel process(CommandProcess process) { + if (sizeLimit > maxSizeLimit) { + return StatusModel.failure(-1, "sizeLimit cannot be large than: " + maxSizeLimit); + } + + //目前不支持过滤,限制http请求执行的文件大小 + int maxSizeLimitOfNonTty = 128 * 1024; + if (!process.session().isTty() && sizeLimit > maxSizeLimitOfNonTty) { + return StatusModel.failure(-1, "When executing in non-tty session, sizeLimit cannot be large than: " + maxSizeLimitOfNonTty); } for (String file : files) { File f = new File(file); if (!f.exists()) { - process.end(-1, "cat " + file + ": No such file or directory"); - return; + return StatusModel.failure(-1, "cat " + file + ": No such file or directory"); } if (f.isDirectory()) { - process.end(-1, "cat " + file + ": Is a directory"); - return; + return StatusModel.failure(-1, "cat " + file + ": Is a directory"); } } for (String file : files) { File f = new File(file); if (f.length() > sizeLimit) { - process.end(-1, "cat " + file + ": Is too large, size: " + f.length()); - return; + return StatusModel.failure(-1, "cat " + file + ": Is too large, size: " + f.length()); } try { String fileToString = FileUtils.readFileToString(f, @@ -76,27 +80,11 @@ public void process(CommandProcess process) { process.appendResult(new CatModel(file, fileToString)); } catch (IOException e) { logger.error("cat read file error. name: " + file, e); - process.end(1, "cat read file error: " + e.getMessage()); - return; + return StatusModel.failure(1, "cat read file error: " + e.getMessage()); } } - process.end(); - } - - private boolean verifyOptions(CommandProcess process) { - if (sizeLimit > maxSizeLimit) { - process.end(-1, "sizeLimit cannot be large than: " + maxSizeLimit); - return false; - } - - //目前不支持过滤,限制http请求执行的文件大小 - int maxSizeLimitOfNonTty = 128 * 1024; - if (!process.session().isTty() && sizeLimit > maxSizeLimitOfNonTty) { - process.end(-1, "When executing in non-tty session, sizeLimit cannot be large than: " + maxSizeLimitOfNonTty); - return false; - } - return true; + return StatusModel.success(); } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java index 6ad72ed0814..c82309be51d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java @@ -1,5 +1,6 @@ package com.taobao.arthas.core.command.basic1000; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Name; @@ -10,12 +11,11 @@ @Summary("Clear the screen") public class ClsCommand extends AnnotatedCommand { @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { if (!process.session().isTty()) { - process.end(-1, "Command 'cls' is only support tty session."); - return; + return StatusModel.failure(-1, "Command 'cls' is only support tty session."); } process.write(RenderUtil.cls()).write("\n"); - process.end(); + return StatusModel.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/EchoCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/EchoCommand.java index b1db3f084c7..a20a8d18af3 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/EchoCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/EchoCommand.java @@ -2,7 +2,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.EchoModel; -import com.taobao.arthas.core.command.model.MessageModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Argument; @@ -30,12 +30,12 @@ public void setMessage(String message) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { if (message != null) { process.appendResult(new EchoModel(message)); } - process.end(); + return StatusModel.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java index d1db00b0ff4..1c4174928cb 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java @@ -1,6 +1,7 @@ package com.taobao.arthas.core.command.basic1000; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Argument; @@ -167,7 +168,7 @@ public int getMaxCount() { } @Override - public void process(CommandProcess process) { - process.end(-1, "The grep command only for pipes. See 'grep --help'\n"); + public StatusModel process(CommandProcess process) { + return StatusModel.failure(-1, "The grep command only for pipes. See 'grep --help'\n"); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HelpCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HelpCommand.java index 6e1d5f23ea0..d423107a49c 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HelpCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HelpCommand.java @@ -4,6 +4,7 @@ import com.taobao.arthas.core.command.model.CommandOptionVO; import com.taobao.arthas.core.command.model.CommandVO; import com.taobao.arthas.core.command.model.HelpModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -39,7 +40,7 @@ public void setCmd(String cmd) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { List commands = allCommands(process.session()); Command targetCmd = findCommand(commands); if (targetCmd == null) { @@ -47,7 +48,7 @@ public void process(CommandProcess process) { } else { process.appendResult(createHelpDetailModel(targetCmd)); } - process.end(); + return StatusModel.success(); } public HelpModel createHelpDetailModel(Command targetCmd) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java index 407970edcb3..3aa0a959949 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java @@ -5,6 +5,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.HistoryModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; @@ -45,7 +46,7 @@ public void setNumber(int n) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { Session session = process.session(); //TODO 修改term history实现方式,统一使用HistoryManager Object termObject = session.get(Session.TTY); @@ -84,6 +85,6 @@ public void process(CommandProcess process) { } } - process.end(); + return StatusModel.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java index 7bb044d6875..e5bf512b24f 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java @@ -4,6 +4,7 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.common.IOUtils; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.term.impl.Helper; @@ -34,10 +35,9 @@ public class KeymapCommand extends AnnotatedCommand { private static final Logger logger = LoggerFactory.getLogger(KeymapCommand.class); @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { if (!process.session().isTty()) { - process.end(-1, "Command 'keymap' is only support tty session."); - return; + return StatusModel.failure(-1, "Command 'keymap' is only support tty session."); } InputStream inputrc = Helper.loadInputRcFile(); @@ -63,11 +63,12 @@ public void process(CommandProcess process) { } process.write(RenderUtil.render(table, process.width())); - } catch (IOException e) { + return StatusModel.success(); + } catch (Throwable e) { logger.error("read inputrc file error.", e); + return StatusModel.failure(-1, "read inputrc file error."); } finally { IOUtils.close(inputrc); - process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java index 07960f71023..6fc63d1f91f 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java @@ -68,25 +68,19 @@ public void setOptionValue(String optionValue) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { try { - StatusModel statusModel = null; if (isShow()) { - statusModel = processShow(process); + return processShow(process); } else if (isShowName()) { - statusModel = processShowName(process); + return processShowName(process); } else { - statusModel = processChangeNameValue(process); + return processChangeNameValue(process); } - if (statusModel != null) { - process.end(statusModel.getStatusCode(), statusModel.getMessage()); - } else { - process.end(-1, "command was not processed"); - } } catch (Throwable t) { logger.error("process options command error", t); - process.end(-1, "process options command error"); + return StatusModel.failure(-1, "process options command error"); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java index 718624c43dd..cb2f50e68c2 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java @@ -3,6 +3,7 @@ import java.io.File; import com.taobao.arthas.core.command.model.PwdModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Name; @@ -12,9 +13,9 @@ @Summary("Return working directory name") public class PwdCommand extends AnnotatedCommand { @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { String path = new File("").getAbsolutePath(); process.appendResult(new PwdModel(path)); - process.end(); + return StatusModel.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java index 834c2de6d99..df36bb3958e 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java @@ -3,6 +3,7 @@ import com.taobao.arthas.core.advisor.Enhancer; import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.ResetModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.matcher.Matcher; @@ -45,16 +46,18 @@ public void setRegEx(boolean regEx) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { Instrumentation inst = process.session().getInstrumentation(); Matcher matcher = SearchUtils.classNameMatcher(classPattern, isRegEx); try { EnhancerAffect enhancerAffect = Enhancer.reset(inst, matcher); process.appendResult(new ResetModel(enhancerAffect)); + return StatusModel.success(); } catch (UnmodifiableClassException e) { // ignore - } finally { - process.end(); + return StatusModel.failure(1, "unmodifiable class exception"); + } catch (Throwable e) { + return StatusModel.failure(-1, "process failure: "+e.toString()); } } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java index e532d6c9b66..c64c9405ff5 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java @@ -1,6 +1,7 @@ package com.taobao.arthas.core.command.basic1000; import com.taobao.arthas.core.command.model.SessionModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; @@ -21,7 +22,7 @@ public class SessionCommand extends AnnotatedCommand { @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { SessionModel result = new SessionModel(); Session session = process.session(); result.setJavaPid(session.getPid()); @@ -42,7 +43,7 @@ public void process(CommandProcess process) { result.setStatUrl(statUrl); process.appendResult(result); - process.end(); + return StatusModel.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java index e98067442b4..32dff750aa8 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java @@ -6,6 +6,7 @@ import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.ResetModel; import com.taobao.arthas.core.command.model.ShutdownModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.ShellServer; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -33,8 +34,9 @@ public class ShutdownCommand extends AnnotatedCommand { private static final Logger logger = LoggerFactory.getLogger(ShutdownCommand.class); @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { shutdown(process); + return StatusModel.success(); } public static void shutdown(CommandProcess process) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/StopCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/StopCommand.java index 42a4260e85e..767f6bdacb7 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/StopCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/StopCommand.java @@ -1,5 +1,6 @@ package com.taobao.arthas.core.command.basic1000; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Name; @@ -14,7 +15,8 @@ @Summary("Stop/Shutdown Arthas server and exit the console.") public class StopCommand extends AnnotatedCommand { @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { ShutdownCommand.shutdown(process); + return StatusModel.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java index c2191094c6c..6f631057129 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java @@ -1,6 +1,7 @@ package com.taobao.arthas.core.command.basic1000; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.command.model.SystemEnvModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -30,7 +31,7 @@ public void setOptionName(String envName) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { try { SystemEnvModel result = new SystemEnvModel(); if (StringUtils.isBlank(envName)) { @@ -42,10 +43,9 @@ public void process(CommandProcess process) { result.put(envName, value); } process.appendResult(result); + return StatusModel.success(); } catch (Throwable t) { - process.end(-1, "Error during setting system env: " + t.getMessage()); - } finally { - process.end(); + return StatusModel.failure(-1, "Error during setting system env: " + t.getMessage()); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java index cca75a2e896..c6797762077 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java @@ -39,7 +39,7 @@ public void setOptionValue(String propertyValue) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { try { if (StringUtils.isBlank(propertyName) && StringUtils.isBlank(propertyValue)) { @@ -49,8 +49,7 @@ public void process(CommandProcess process) { // view the specified system property String value = System.getProperty(propertyName); if (value == null) { - process.end(1, "There is no property with the key " + propertyName); - return; + return StatusModel.failure(1, "There is no property with the key " + propertyName); } else { process.appendResult(new SystemPropertyModel(propertyName, value)); } @@ -60,10 +59,9 @@ public void process(CommandProcess process) { process.appendResult(new MessageModel("Successfully changed the system property.")); process.appendResult(new SystemPropertyModel(propertyName, System.getProperty(propertyName))); } + return StatusModel.success(); } catch (Throwable t) { - process.end(-1, "Error during setting system property: " + t.getMessage()); - } finally { - process.end(); + return StatusModel.failure(-1, "Error during setting system property: " + t.getMessage()); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java index 3c8868c5a97..0f983c54f12 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java @@ -2,6 +2,7 @@ import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.*; @@ -33,8 +34,8 @@ public void setRegEx(boolean append) { } @Override - public void process(CommandProcess process) { - process.end(-1, "The tee command only for pipes. See 'tee --help'"); + public StatusModel process(CommandProcess process) { + return StatusModel.failure(-1, "The tee command only for pipes. See 'tee --help'"); } public String getFilePath() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java index 9ae903133a9..4fa14fd3c3e 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java @@ -12,6 +12,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.ChangeResultVO; import com.taobao.arthas.core.command.model.MessageModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.command.model.VMOptionModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -52,11 +53,11 @@ public void setOptionValue(String value) { } @Override - public void process(CommandProcess process) { - run(process, name, value); + public StatusModel process(CommandProcess process) { + return run(process, name, value); } - private static void run(CommandProcess process, String name, String value) { + private static StatusModel run(CommandProcess process, String name, String value) { try { HotSpotDiagnosticMXBean hotSpotDiagnosticMXBean = ManagementFactory .getPlatformMXBean(HotSpotDiagnosticMXBean.class); @@ -68,7 +69,7 @@ private static void run(CommandProcess process, String name, String value) { // view the specified option VMOption option = hotSpotDiagnosticMXBean.getVMOption(name); if (option == null) { - process.end(-1, "In order to change the system properties, you must specify the property value."); + return StatusModel.failure(-1, "In order to change the system properties, you must specify the property value."); } else { process.appendResult(new VMOptionModel(Arrays.asList(option))); } @@ -82,11 +83,10 @@ private static void run(CommandProcess process, String name, String value) { process.appendResult(new VMOptionModel(new ChangeResultVO(name, originValue, hotSpotDiagnosticMXBean.getVMOption(name).getValue()))); } + return StatusModel.success(); } catch (Throwable t) { logger.error("Error during setting vm option", t); - process.end(-1, "Error during setting vm option: " + t.getMessage()); - } finally { - process.end(); + return StatusModel.failure(-1, "Error during setting vm option: " + t.getMessage()); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VersionCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VersionCommand.java index b46ed80b845..716d103fce5 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VersionCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VersionCommand.java @@ -1,6 +1,7 @@ package com.taobao.arthas.core.command.basic1000; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.command.model.VersionModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; @@ -18,11 +19,11 @@ public class VersionCommand extends AnnotatedCommand { @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { VersionModel result = new VersionModel(); result.setVersion(ArthasBanner.version()); process.appendResult(result); - process.end(); + return StatusModel.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/hidden/JulyCommand.java b/core/src/main/java/com/taobao/arthas/core/command/hidden/JulyCommand.java index f67afbbd9bd..5ef7a440774 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/hidden/JulyCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/hidden/JulyCommand.java @@ -1,5 +1,6 @@ package com.taobao.arthas.core.command.hidden; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Hidden; @@ -14,8 +15,9 @@ @Hidden public class JulyCommand extends AnnotatedCommand { @Override - public void process(CommandProcess process) { - process.write(new String($$())).write("\n").end(); + public StatusModel process(CommandProcess process) { + process.write(new String($$())).write("\n"); + return StatusModel.success(); } private static byte[] $$() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/hidden/ThanksCommand.java b/core/src/main/java/com/taobao/arthas/core/command/hidden/ThanksCommand.java index d7b4adb790d..5f6ee63f9fe 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/hidden/ThanksCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/hidden/ThanksCommand.java @@ -1,5 +1,6 @@ package com.taobao.arthas.core.command.hidden; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ArthasBanner; @@ -18,7 +19,8 @@ @Hidden public class ThanksCommand extends AnnotatedCommand { @Override - public void process(CommandProcess process) { - process.write(ArthasBanner.credit()).write("\n").end(); + public StatusModel process(CommandProcess process) { + process.write(ArthasBanner.credit()).write("\n"); + return StatusModel.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java index a9020d400c6..f1bec9c6954 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java @@ -9,6 +9,7 @@ import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.handlers.Handler; @@ -109,23 +110,23 @@ public void setLoadClass(String className) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { // ctrl-C support process.interruptHandler(new ClassLoaderInterruptHandler(process, isInterrupted)); Instrumentation inst = process.session().getInstrumentation(); if (all) { - processAllClasses(process, inst); + return processAllClasses(process, inst); } else if (hashCode != null && resource != null) { - processResources(process, inst); + return processResources(process, inst); } else if (hashCode != null && this.loadClass != null) { - processLoadClass(process, inst); + return processLoadClass(process, inst); } else if (hashCode != null) { - processClassLoader(process, inst); - } else if (listClassLoader || isTree){ - processClassLoaders(process, inst); + return processClassLoader(process, inst); + } else if (listClassLoader || isTree) { + return processClassLoaders(process, inst); } else { - processClassLoaderStats(process, inst); + return processClassLoaderStats(process, inst); } } @@ -134,12 +135,13 @@ public void process(CommandProcess process) { * e.g. In JVM, there are 100 GrooyClassLoader instances, which loaded 200 classes in total * @param process * @param inst + * @return */ - private void processClassLoaderStats(CommandProcess process, Instrumentation inst) { + private StatusModel processClassLoaderStats(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); List classLoaderInfos = getAllClassLoaderInfo(inst); Map classLoaderStats = new HashMap(); - for (ClassLoaderInfo info: classLoaderInfos) { + for (ClassLoaderInfo info : classLoaderInfos) { String name = info.classLoader == null ? "BootstrapClassLoader" : info.classLoader.getClass().getName(); ClassLoaderStat stat = classLoaderStats.get(name); if (null == stat) { @@ -158,10 +160,10 @@ private void processClassLoaderStats(CommandProcess process, Instrumentation ins affect.rCnt(sorted.keySet().size()); process.appendResult(new RowAffectModel(affect)); - process.end(); + return StatusModel.success(); } - private void processClassLoaders(CommandProcess process, Instrumentation inst) { + private StatusModel processClassLoaders(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); List classLoaderInfos = includeReflectionClassLoader ? getAllClassLoaderInfo(inst) : getAllClassLoaderInfo(inst, new SunReflectionClassLoaderFilter()); @@ -172,18 +174,18 @@ private void processClassLoaders(CommandProcess process, Instrumentation inst) { classLoaderVO.setLoadedCount(classLoaderInfo.loadedClassCount()); classLoaderVOs.add(classLoaderVO); } - if (isTree){ + if (isTree) { classLoaderVOs = processClassLoaderTree(classLoaderVOs); } process.appendResult(new ClassLoaderModel().setClassLoaders(classLoaderVOs).setTree(isTree)); affect.rCnt(classLoaderInfos.size()); process.appendResult(new RowAffectModel(affect)); - process.end(); + return StatusModel.success(); } // 根据 hashCode 来打印URLClassLoader的urls - private void processClassLoader(CommandProcess process, Instrumentation inst) { + private StatusModel processClassLoader(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); Set allClassLoader = getAllClassLoaders(inst); for (ClassLoader cl : allClassLoader) { @@ -191,7 +193,7 @@ private void processClassLoader(CommandProcess process, Instrumentation inst) { if (cl instanceof URLClassLoader) { List classLoaderUrls = getClassLoaderUrls(cl); affect.rCnt(classLoaderUrls.size()); - if (classLoaderUrls.isEmpty()){ + if (classLoaderUrls.isEmpty()) { process.appendResult(new MessageModel("urls is empty.")); } else { process.appendResult(new ClassLoaderModel().setUrls(classLoaderUrls)); @@ -199,16 +201,16 @@ private void processClassLoader(CommandProcess process, Instrumentation inst) { } } else { process.appendResult(new MessageModel("not a URLClassLoader.")); - } + } break; - } + } } process.appendResult(new RowAffectModel(affect)); - process.end(); + return StatusModel.success(); } // 使用ClassLoader去getResources - private void processResources(CommandProcess process, Instrumentation inst) { + private StatusModel processResources(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); int rowCount = 0; Set allClassLoader = getAllClassLoaders(inst); @@ -231,11 +233,11 @@ private void processResources(CommandProcess process, Instrumentation inst) { process.appendResult(new ClassLoaderModel().setResources(resources)); process.appendResult(new RowAffectModel(affect)); - process.end(); + return StatusModel.success(); } // Use ClassLoader to loadClass - private void processLoadClass(CommandProcess process, Instrumentation inst) { + private StatusModel processLoadClass(CommandProcess process, Instrumentation inst) { Set allClassLoader = getAllClassLoaders(inst); for (ClassLoader cl : allClassLoader) { if (Integer.toHexString(cl.hashCode()).equals(hashCode)) { @@ -247,40 +249,33 @@ private void processLoadClass(CommandProcess process, Instrumentation inst) { } catch (Throwable e) { logger.warn("load class error, class: {}", this.loadClass, e); - process.end(-1, "load class error, class:"+this.loadClass+", error: "+e.toString()); - break; + return StatusModel.failure(-1, "load class error, class:" + this.loadClass + ", error: " + e.toString()); } } } - process.end(); + return StatusModel.success(); } - private void processAllClasses(CommandProcess process, Instrumentation inst) { + private StatusModel processAllClasses(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); - getAllClasses(hashCode, inst, affect, process); - if (checkInterrupted(process)) { - return; + StatusModel statusModel = getAllClasses(hashCode, inst, affect, process); + if (StatusModel.isFailed(statusModel)) { + return statusModel; } - process.appendResult(new RowAffectModel(affect)); - process.end(); - } - - private boolean checkInterrupted(CommandProcess process) { if (isInterrupted.get()) { - process.end(1, "Interrupted by user"); - return true; + return StatusModel.failure(1, "Interrupted by user"); } - return false; + process.appendResult(new RowAffectModel(affect)); + return StatusModel.success(); } /** * 获取到所有的class, 还有它们的classloader,按classloader归类好,统一输出每个classloader里有哪些class *

* 当hashCode是null,则把所有的classloader的都打印 - * */ @SuppressWarnings("rawtypes") - private void getAllClasses(String hashCode, Instrumentation inst, RowAffect affect, CommandProcess process) { + private StatusModel getAllClasses(String hashCode, Instrumentation inst, RowAffect affect, CommandProcess process) { int hashCodeInt = -1; if (hashCode != null) { hashCodeInt = Integer.valueOf(hashCode, 16); @@ -328,15 +323,16 @@ public int compare(Class o1, Class o2) { affect.rCnt(bootstrapClassSet.size()); for (Entry> entry : classLoaderClassMap.entrySet()) { - if (checkInterrupted(process)) { - return; + if (isInterrupted.get()) { + return StatusModel.failure(1, "Interrupted by user"); } ClassLoader classLoader = entry.getKey(); SortedSet classSet = entry.getValue(); processClassSet(process, ClassUtils.createClassLoaderVO(classLoader), classSet, pageSize); affect.rCnt(classSet.size()); } - } + return null; + } private void processClassSet(final CommandProcess process, final ClassLoaderVO classLoaderVO, Collection classes, int pageSize) { @@ -344,8 +340,8 @@ private void processClassSet(final CommandProcess process, final ClassLoaderVO c @Override public boolean handle(List classNames, int segment) { process.appendResult(new ClassLoaderModel().setClassSet(new ClassSetVO(classLoaderVO, classNames, segment))); - return !checkInterrupted(process); - } + return !isInterrupted.get(); + } }); } @@ -377,14 +373,14 @@ private static List processClassLoaderTree(List cl for (ClassLoaderVO classLoaderVO : rootClassLoaders) { buildTree(classLoaderVO, parentNotNullClassLoaders); - } + } return rootClassLoaders; } private static void buildTree(ClassLoaderVO parent, List parentNotNullClassLoaders) { for (ClassLoaderVO classLoaderVO : parentNotNullClassLoaders) { - if (parent.getName().equals(classLoaderVO.getParent())){ + if (parent.getName().equals(classLoaderVO.getParent())) { parent.addChild(classLoaderVO); buildTree(classLoaderVO, parentNotNullClassLoaders); } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java index b1b1cb36f9b..ed4fdeac169 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java @@ -87,29 +87,21 @@ public void setLimit(int limit) { } @Override - public void process(CommandProcess process) { - RowAffect effect = new RowAffect(); - StatusModel statusModel = new StatusModel(-1, "unknown error"); - try { - if (directory != null) { - File dir = new File(directory); - if (dir.isFile()) { - process.end(-1, directory + " :is not a directory, please check it"); - return; - } - } - Instrumentation inst = process.session().getInstrumentation(); - Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, code); - if (matchedClasses == null || matchedClasses.isEmpty()) { - processNoMatch(process, statusModel); - } else if (matchedClasses.size() > limit) { - processMatches(process, matchedClasses, statusModel); - } else { - processMatch(process, effect, inst, matchedClasses, statusModel); + public StatusModel process(CommandProcess process) { + if (directory != null) { + File dir = new File(directory); + if (dir.isFile()) { + return StatusModel.failure(-1, directory + " :is not a directory, please check it"); } - } finally { - process.appendResult(new RowAffectModel(effect)); - process.end(statusModel.getStatusCode(), statusModel.getMessage()); + } + Instrumentation inst = process.session().getInstrumentation(); + Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, code); + if (matchedClasses == null || matchedClasses.isEmpty()) { + return processNoMatch(process); + } else if (matchedClasses.size() > limit) { + return processMatches(process, matchedClasses); + } else { + return processMatch(process, inst, matchedClasses); } } @@ -120,7 +112,8 @@ public void complete(Completion completion) { } } - private void processMatch(CommandProcess process, RowAffect effect, Instrumentation inst, Set> matchedClasses, StatusModel statusModel) { + private StatusModel processMatch(CommandProcess process, Instrumentation inst, Set> matchedClasses) { + RowAffect effect = new RowAffect(); try { Map, File> classFiles = dump(inst, matchedClasses); List dumpedClasses = new ArrayList(classFiles.size()); @@ -130,17 +123,20 @@ private void processMatch(CommandProcess process, RowAffect effect, Instrumentat ClassVO classVO = ClassUtils.createSimpleClassInfo(clazz); classVO.setLocation(file.getCanonicalPath()); dumpedClasses.add(classVO); + effect.rCnt(1); } process.appendResult(new DumpClassModel().setDumpedClassFiles(dumpedClasses)); - effect.rCnt(classFiles.keySet().size()); - statusModel.setStatus(0); + return StatusModel.success(); } catch (Throwable t) { logger.error("dump: fail to dump classes: " + matchedClasses, t); + return StatusModel.failure(-1, "dump: fail to dump classes: " + matchedClasses); + } finally { + process.appendResult(new RowAffectModel(effect)); } } - private void processMatches(CommandProcess process, Set> matchedClasses, StatusModel statusModel) { + private StatusModel processMatches(CommandProcess process, Set> matchedClasses) { String msg = String.format( "Found more than %d class for: %s, Please Try to specify the classloader with the -c option, or try to use --limit option.", limit, classPattern); @@ -148,11 +144,11 @@ private void processMatches(CommandProcess process, Set> matchedClasses List classVOs = ClassUtils.createClassVOList(matchedClasses); process.appendResult(new DumpClassModel().setMatchedClasses(classVOs)); - statusModel.setStatus(-1, msg); + return StatusModel.failure(-1, msg); } - private void processNoMatch(CommandProcess process, StatusModel statusModel) { - statusModel.setStatus(-1, "No class found for: " + classPattern); + private StatusModel processNoMatch(CommandProcess process) { + return StatusModel.failure(-1, "No class found for: " + classPattern); } private Map, File> dump(Instrumentation inst, Set> classes) throws UnmodifiableClassException { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java index 1035d10dab5..99fc34ac5d4 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java @@ -89,71 +89,69 @@ public void setExpand(Integer expand) { } @Override - public void process(CommandProcess process) { - RowAffect affect = new RowAffect(); + public StatusModel process(CommandProcess process) { Instrumentation inst = process.session().getInstrumentation(); Set> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, hashCode); - StatusModel statusModel = new StatusModel(-1, "unknown error"); - try { - if (matchedClasses == null || matchedClasses.isEmpty()) { - statusModel.setStatus(-1, "No class found for: " + classPattern); - } else if (matchedClasses.size() > 1) { - processMatches(process, matchedClasses, statusModel); - } else { - processExactMatch(process, affect, inst, matchedClasses, statusModel); - } - } finally { - process.appendResult(new RowAffectModel(affect)); - process.end(statusModel.getStatusCode(), statusModel.getMessage()); + if (matchedClasses == null || matchedClasses.isEmpty()) { + return StatusModel.failure(-1, "No class found for: " + classPattern); + } else if (matchedClasses.size() > 1) { + return processMatches(process, matchedClasses); + } else { + return processExactMatch(process, inst, matchedClasses); } } - private void processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, - Set> matchedClasses, StatusModel statusModel) { + private StatusModel processExactMatch(CommandProcess process, Instrumentation inst, + Set> matchedClasses) { + RowAffect affect = new RowAffect(); Matcher fieldNameMatcher = fieldNameMatcher(); Class clazz = matchedClasses.iterator().next(); boolean found = false; - for (Field field : clazz.getDeclaredFields()) { - if (!Modifier.isStatic(field.getModifiers()) || !fieldNameMatcher.matching(field.getName())) { - continue; - } - if (!field.isAccessible()) { - field.setAccessible(true); - } - try { - Object value = field.get(null); - - if (!StringUtils.isEmpty(express)) { - value = ExpressFactory.threadLocalExpress(value).get(express); + try { + for (Field field : clazz.getDeclaredFields()) { + if (!Modifier.isStatic(field.getModifiers()) || !fieldNameMatcher.matching(field.getName())) { + continue; + } + if (!field.isAccessible()) { + field.setAccessible(true); + } + try { + Object value = field.get(null); + + if (!StringUtils.isEmpty(express)) { + value = ExpressFactory.threadLocalExpress(value).get(express); + } + + process.appendResult(new GetStaticModel(field.getName(), value, expand)); + + affect.rCnt(1); + } catch (IllegalAccessException e) { + logger.warn("getstatic: failed to get static value, class: {}, field: {} ", clazz, field.getName(), e); + process.appendResult(new MessageModel("Failed to get static, exception message: " + e.getMessage() + + ", please check $HOME/logs/arthas/arthas.log for more details. ")); + } catch (ExpressException e) { + logger.warn("getstatic: failed to get express value, class: {}, field: {}, express: {}", clazz, field.getName(), express, e); + process.appendResult(new MessageModel("Failed to get static, exception message: " + e.getMessage() + + ", please check $HOME/logs/arthas/arthas.log for more details. ")); + } finally { + found = true; } - - process.appendResult(new GetStaticModel(field.getName(), value, expand)); - - affect.rCnt(1); - } catch (IllegalAccessException e) { - logger.warn("getstatic: failed to get static value, class: {}, field: {} ", clazz, field.getName(), e); - process.appendResult(new MessageModel("Failed to get static, exception message: " + e.getMessage() - + ", please check $HOME/logs/arthas/arthas.log for more details. ")); - } catch (ExpressException e) { - logger.warn("getstatic: failed to get express value, class: {}, field: {}, express: {}", clazz, field.getName(), express, e); - process.appendResult(new MessageModel("Failed to get static, exception message: " + e.getMessage() - + ", please check $HOME/logs/arthas/arthas.log for more details. ")); - } finally { - found = true; } - } - if (!found) { - statusModel.setStatus(-1, "getstatic: no matched static field was found"); - } else { - statusModel.setStatus(0, null); + if (!found) { + return StatusModel.failure(-1, "getstatic: no matched static field was found"); + } else { + return StatusModel.success(); + } + } finally { + process.appendResult(new RowAffectModel(affect)); } } - private void processMatches(CommandProcess process, Set> matchedClasses, StatusModel statusModel) { + private StatusModel processMatches(CommandProcess process, Set> matchedClasses) { // Element usage = new LabelElement("getstatic -c " + classPattern + " " + fieldPattern).style( // Decoration.bold.fg(Color.blue)); @@ -164,7 +162,7 @@ private void processMatches(CommandProcess process, Set> matchedClasses List matchedClassVOs = ClassUtils.createClassVOList(matchedClasses); process.appendResult(new GetStaticModel(matchedClassVOs)); - statusModel.setStatus(-1, "Found more than one class for: " + classPattern + ", Please use: "+usage); + return StatusModel.failure(-1, "Found more than one class for: " + classPattern + ", Please use: "+usage); } private Matcher fieldNameMatcher() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java index 8b7a60a5062..6a6683fddbd 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java @@ -97,35 +97,32 @@ public void setSourceOnly(boolean sourceOnly) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); Set> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, code); - StatusModel statusModel = new StatusModel(-1, "unknown error"); try { if (matchedClasses == null || matchedClasses.isEmpty()) { - statusModel = processNoMatch(process); + return processNoMatch(process); } else if (matchedClasses.size() > 1) { - statusModel = processMatches(process, matchedClasses); + return processMatches(process, matchedClasses); } else { // matchedClasses size is 1 // find inner classes. Set> withInnerClasses = SearchUtils.searchClassOnly(inst, matchedClasses.iterator().next().getName() + "$*", false, code); if(withInnerClasses.isEmpty()) { withInnerClasses = matchedClasses; } - statusModel = processExactMatch(process, affect, inst, matchedClasses, withInnerClasses); + return processExactMatch(process, affect, inst, matchedClasses, withInnerClasses); } } finally { if (!this.sourceOnly) { process.appendResult(new RowAffectModel(affect)); } - process.end(statusModel.getStatusCode(), statusModel.getMessage()); } } private StatusModel processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, Set> matchedClasses, Set> withInnerClasses) { - StatusModel statusModel = new StatusModel(); Class c = matchedClasses.iterator().next(); Set> allClasses = new HashSet>(withInnerClasses); allClasses.add(c); @@ -153,12 +150,11 @@ private StatusModel processExactMatch(CommandProcess process, RowAffect affect, process.appendResult(jadModel); affect.rCnt(classFiles.keySet().size()); - statusModel.setStatus(0); + return StatusModel.success(); } catch (Throwable t) { logger.error("jad: fail to decompile class: " + c.getName(), t); - statusModel.setStatus(-1, "jad: fail to decompile class: " + c.getName()); + return StatusModel.failure(-1, "jad: fail to decompile class: " + c.getName()); } - return statusModel; } private StatusModel processMatches(CommandProcess process, Set> matchedClasses) { @@ -175,11 +171,11 @@ private StatusModel processMatches(CommandProcess process, Set> matched jadModel.setMatchedClasses(classVOs); process.appendResult(jadModel); - return new StatusModel(-1, msg); + return StatusModel.failure(-1, msg); } private StatusModel processNoMatch(CommandProcess process) { - return new StatusModel().setStatus(-1, "No class found for: " + classPattern); + return StatusModel.failure(-1, "No class found for: " + classPattern); } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java index e0f6e68c71b..052cfca61ca 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java @@ -14,6 +14,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.MemoryCompilerModel; import com.taobao.arthas.core.command.model.RowAffectModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -72,8 +73,7 @@ public void setDirectory(String directory) { } @Override - public void process(final CommandProcess process) { - int exitCode = -1; + public StatusModel process(final CommandProcess process) { RowAffect affect = new RowAffect(); try { @@ -84,9 +84,7 @@ public void process(final CommandProcess process) { } else { classloader = ClassLoaderUtils.getClassLoader(inst, hashCode); if (classloader == null) { - exitCode = -1; - process.end(-1, "Can not find classloader with hashCode: " + hashCode + "."); - return; + return StatusModel.failure(-1, "Can not find classloader with hashCode: " + hashCode + "."); } } @@ -123,15 +121,13 @@ public void process(final CommandProcess process) { affect.rCnt(1); } process.appendResult(new MemoryCompilerModel(files)); - exitCode = 0; + return StatusModel.success(); } catch (Throwable e) { logger.warn("Memory compiler error", e); - process.end(-1, "Memory compiler error, exception message: " + e.getMessage() + return StatusModel.failure(-1, "Memory compiler error, exception message: " + e.getMessage() + ", please check $HOME/logs/arthas/arthas.log for more details."); - exitCode = -1; } finally { process.appendResult(new RowAffectModel(affect)); - process.end(exitCode); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java index 33f65ad7407..d5b8143cc55 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java @@ -9,6 +9,7 @@ import com.taobao.arthas.core.command.express.ExpressException; import com.taobao.arthas.core.command.express.ExpressFactory; import com.taobao.arthas.core.command.model.OgnlModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ClassLoaderUtils; @@ -60,8 +61,7 @@ public void setExpand(Integer expand) { } @Override - public void process(CommandProcess process) { - int exitCode = 0; + public StatusModel process(CommandProcess process) { try { Instrumentation inst = process.session().getInstrumentation(); ClassLoader classLoader = null; @@ -72,9 +72,7 @@ public void process(CommandProcess process) { } if (classLoader == null) { - process.end(-1, "Can not find classloader with hashCode: " + hashCode + "."); - exitCode = -1; - return; + return StatusModel.failure(-1, "Can not find classloader with hashCode: " + hashCode + "."); } Express unpooledExpress = ExpressFactory.unpooledExpress(classLoader); @@ -86,12 +84,13 @@ public void process(CommandProcess process) { process.appendResult(ognlModel); } catch (ExpressException e) { logger.warn("ognl: failed execute express: " + express, e); - process.end(-1, "Failed to execute ognl, exception message: " + e.getMessage() - + ", please check $HOME/logs/arthas/arthas.log for more details. "); - exitCode = -1; + return StatusModel.failure(-1, "Failed to execute ognl, exception message: " + e.getMessage() + + ", please check $HOME/logs/arthas/arthas.log for more details. "); } - } finally { - process.end(exitCode); + return StatusModel.success(); + } catch(Throwable e){ + logger.error("process failure", e); + return StatusModel.failure(-1, "process failure: "+e.toString()); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java index 33f320a0eb4..70ef4362ff1 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java @@ -15,6 +15,7 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.RedefineModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -58,22 +59,19 @@ public void setPaths(List paths) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { RedefineModel redefineModel = new RedefineModel(); Instrumentation inst = process.session().getInstrumentation(); for (String path : paths) { File file = new File(path); if (!file.exists()) { - process.end(-1, "file does not exist, path:" + path); - return; + return StatusModel.failure(-1, "file does not exist, path:" + path); } if (!file.isFile()) { - process.end(-1, "not a normal file, path:" + path); - return; + return StatusModel.failure(-1, "not a normal file, path:" + path); } if (file.length() >= MAX_FILE_SIZE) { - process.end(-1, "file size: " + file.length() + " >= " + MAX_FILE_SIZE + ", path: " + path); - return; + return StatusModel.failure(-1, "file size: " + file.length() + " >= " + MAX_FILE_SIZE + ", path: " + path); } } @@ -91,7 +89,7 @@ public void process(CommandProcess process) { } catch (Exception e) { logger.warn("load class file failed: "+path, e); - process.end(-1, "load class file failed: " +path+", error: " + e); + return StatusModel.failure(-1, "load class file failed: " +path+", error: " + e); } finally { if (f != null) { try { @@ -104,8 +102,7 @@ public void process(CommandProcess process) { } if (bytesMap.size() != paths.size()) { - process.end(-1, "paths may contains same class name!"); - return; + return StatusModel.failure(-1, "paths may contains same class name!"); } List definitions = new ArrayList(); @@ -123,16 +120,15 @@ public void process(CommandProcess process) { try { if (definitions.isEmpty()) { - process.end(-1, "These classes are not found in the JVM and may not be loaded: " + bytesMap.keySet()); - return; + return StatusModel.failure(-1, "These classes are not found in the JVM and may not be loaded: " + bytesMap.keySet()); } inst.redefineClasses(definitions.toArray(new ClassDefinition[0])); process.appendResult(redefineModel); } catch (Exception e) { - process.end(-1, "redefine error! " + e); + return StatusModel.failure(-1, "redefine error! " + e); } - process.end(); + return StatusModel.success(); } private static String readClassName(final byte[] bytes) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java index 1953f1fb04e..467fcd8553d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java @@ -11,6 +11,7 @@ import com.taobao.arthas.core.command.model.SearchClassModel; import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.RowAffectModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -92,7 +93,7 @@ public void setNumberOfLimit(int numberOfLimit) { } @Override - public void process(final CommandProcess process) { + public StatusModel process(final CommandProcess process) { // TODO: null check RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); @@ -106,10 +107,9 @@ public int compare(Class c1, Class c2) { if (isDetail) { if (matchedClasses.size() > numberOfLimit) { - process.end(-1, "Matching classes are too many: "+matchedClasses.size()); - return; + return StatusModel.failure(-1, "Matching classes are too many: " + matchedClasses.size()); } - for (Class clazz : matchedClasses) { + for (Class clazz : matchedClasses) { ClassVO classInfo = ClassUtils.createClassInfo(clazz, isDetail, isField); process.appendResult(new SearchClassModel(classInfo, isDetail, isField, expand)); } @@ -120,14 +120,13 @@ public int compare(Class c1, Class c2) { public boolean handle(List classNames, int segment) { process.appendResult(new SearchClassModel(classNames, segment)); return true; - } + } }); } - affect.rCnt(matchedClasses.size()); process.appendResult(new RowAffectModel(affect)); - process.end(); + return StatusModel.success(); } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java index d9add0132d8..5b00d4fb044 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java @@ -12,6 +12,7 @@ import com.taobao.arthas.core.command.model.SearchMethodModel; import com.taobao.arthas.core.command.model.MethodVO; import com.taobao.arthas.core.command.model.RowAffectModel; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -91,7 +92,7 @@ public void setNumberOfLimit(int numberOfLimit) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); @@ -99,40 +100,41 @@ public void process(CommandProcess process) { Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode); if (matchedClasses.size() > numberOfLimit) { - process.end(-1, "Matching classes are too many: "+matchedClasses.size()); - return; + return StatusModel.failure(-1, "Matching classes are too many: "+matchedClasses.size()); } - for (Class clazz : matchedClasses) { - try { - for (Constructor constructor : clazz.getDeclaredConstructors()) { - if (!methodNameMatcher.matching("")) { - continue; + try { + for (Class clazz : matchedClasses) { + try { + for (Constructor constructor : clazz.getDeclaredConstructors()) { + if (!methodNameMatcher.matching("")) { + continue; + } + + MethodVO methodInfo = ClassUtils.createMethodInfo(constructor, clazz, isDetail); + process.appendResult(new SearchMethodModel(methodInfo, isDetail)); + affect.rCnt(1); } - MethodVO methodInfo = ClassUtils.createMethodInfo(constructor, clazz, isDetail); - process.appendResult(new SearchMethodModel(methodInfo, isDetail)); - affect.rCnt(1); - } - - for (Method method : clazz.getDeclaredMethods()) { - if (!methodNameMatcher.matching(method.getName())) { - continue; + for (Method method : clazz.getDeclaredMethods()) { + if (!methodNameMatcher.matching(method.getName())) { + continue; + } + MethodVO methodInfo = ClassUtils.createMethodInfo(method, clazz, isDetail); + process.appendResult(new SearchMethodModel(methodInfo, isDetail)); + affect.rCnt(1); } - MethodVO methodInfo = ClassUtils.createMethodInfo(method, clazz, isDetail); - process.appendResult(new SearchMethodModel(methodInfo, isDetail)); - affect.rCnt(1); + } catch (Error e) { + //print failed className + String msg = String.format("process class failed: %s, error: %s", clazz.getName(), e.toString()); + logger.error(msg, e); + return StatusModel.failure(1, msg); } - } catch (Error e) { - //print failed className - String msg = String.format("process class failed: %s, error: %s", clazz.getName(), e.toString()); - logger.error(msg, e); - process.end(1, msg); - return; } - } - process.appendResult(new RowAffectModel(affect)); - process.end(); + return StatusModel.success(); + } finally { + process.appendResult(new RowAffectModel(affect)); + } } private Matcher methodNameMatcher() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/logger/LoggerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/logger/LoggerCommand.java index a2a1d45d95d..89c3618b581 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/logger/LoggerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/logger/LoggerCommand.java @@ -21,6 +21,7 @@ import com.taobao.arthas.common.IOUtils; import com.taobao.arthas.common.ReflectUtils; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ClassLoaderUtils; @@ -110,7 +111,7 @@ public void setHaveAppender(boolean includeNoAppender) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { int status = 0; try { if (this.name != null && this.level != null) { @@ -121,6 +122,7 @@ public void process(CommandProcess process) { } finally { process.end(status); } + return StatusModel.IGNORED_STATUS; } public void level(CommandProcess process) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java index 4b43baf7c81..31cf2125d2b 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java @@ -1,17 +1,68 @@ package com.taobao.arthas.core.command.model; public class StatusModel extends ResultModel { + + /** + * 异步执行的命令返回此状态,注意避免状态码冲突 + */ + public static final StatusModel PENDING_STATUS = new StatusModel(0x300000); + + /** + * TODO 暂时兼容老代码使用,忽略检查此命令的status,命令改造完毕后需要移除此变量 + */ + public static final StatusModel IGNORED_STATUS = new StatusModel(0x100000); + + /** + * 命令执行成功的状态 + * @return + */ public static StatusModel success() { return new StatusModel(0); } + /** + * 命令执行失败 + * @param statusCode + * @param message + * @return + */ public static StatusModel failure(int statusCode, String message) { if (statusCode == 0) { throw new IllegalArgumentException("failure status code cannot be 0"); } + if (statusCode == PENDING_STATUS.statusCode) { + throw new IllegalArgumentException("failure status cannot equals to PENDING_STATUS"); + } return new StatusModel(statusCode, message); } + /** + * 判断是否为失败状态 + * @param statusModel + * @return + */ + public static boolean isFailed(StatusModel statusModel) { + return statusModel != null && statusModel.getStatusCode() != 0; + } + + /** + * 判断是否为异步执行等待状态 + * @param statusModel + * @return + */ + public static boolean isPending(StatusModel statusModel) { + return statusModel != null && statusModel.getStatusCode() == PENDING_STATUS.getStatusCode(); + } + + /** + * TODO 判断是否为IGNORE状态,兼容老代码使用,改造完毕后需要移除 + * @param statusModel + * @return + */ + public static boolean isIgnored(StatusModel statusModel) { + return statusModel != null && statusModel.getStatusCode() == IGNORED_STATUS.getStatusCode(); + } + private int statusCode; private String message; diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java index a6f3313976e..abfe4d60a91 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java @@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.handlers.Handler; @@ -77,7 +78,7 @@ public void setInterval(long interval) { @Override - public void process(final CommandProcess process) { + public StatusModel process(final CommandProcess process) { Session session = process.session(); timer = new Timer("Timer-for-arthas-dashboard-" + session.getSessionId(), true); @@ -110,6 +111,8 @@ public void handle(Void event) { // start the timer timer.scheduleAtFixedRate(new DashboardTimerTask(process), 0, getInterval()); + + return StatusModel.IGNORED_STATUS; } public synchronized void stop() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java index 6fb9bace28c..37ef8feff31 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java @@ -11,6 +11,7 @@ import com.taobao.arthas.core.advisor.AdviceWeaver; import com.taobao.arthas.core.advisor.Enhancer; import com.taobao.arthas.core.advisor.InvokeTraceable; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -77,7 +78,7 @@ AdviceListener getAdviceListenerWithId(CommandProcess process) { return getAdviceListener(process); } @Override - public void process(final CommandProcess process) { + public StatusModel process(final CommandProcess process) { // ctrl-C support process.interruptHandler(new CommandInterruptHandler(process)); // q exit support @@ -85,6 +86,8 @@ public void process(final CommandProcess process) { // start to enhance enhance(process); + + return StatusModel.IGNORED_STATUS; } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/HeapDumpCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/HeapDumpCommand.java index d1acf4a4142..b3dd98ae889 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/HeapDumpCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/HeapDumpCommand.java @@ -10,6 +10,7 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.sun.management.HotSpotDiagnosticMXBean; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Argument; @@ -47,7 +48,7 @@ public void setLive(boolean live) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { int status = 0; try { String dumpFile = file; @@ -72,6 +73,7 @@ public void process(CommandProcess process) { process.end(status); } + return StatusModel.IGNORED_STATUS; } private static void run(CommandProcess process, String file, boolean live) throws IOException { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/JvmCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/JvmCommand.java index 7f3f295c224..2a2f0aa2f6d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/JvmCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/JvmCommand.java @@ -1,6 +1,7 @@ package com.taobao.arthas.core.command.monitor200; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.StringUtils; @@ -42,7 +43,7 @@ public class JvmCommand extends AnnotatedCommand { private final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { RowAffect affect = new RowAffect(); TableElement table = new TableElement(2, 5).leftCellPadding(1).rightCellPadding(1); table.row(true, label("RUNTIME").style(Decoration.bold.bold())); @@ -81,6 +82,8 @@ public void process(CommandProcess process) { process.write(RenderUtil.render(table, process.width())); process.write(affect.toString()).write("\n"); process.end(); + + return StatusModel.IGNORED_STATUS; } private void drawFileDescriptorTable(TableElement table) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/MBeanCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/MBeanCommand.java index 12f7d157543..ac3bd74cfe5 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/MBeanCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/MBeanCommand.java @@ -3,6 +3,7 @@ import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.CliToken; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -140,7 +141,7 @@ public int getNumOfExecutions() { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { if (StringUtils.isEmpty(getName())) { listMBean(process); } else if (isMetaData()) { @@ -148,6 +149,8 @@ public void process(CommandProcess process) { } else { listAttribute(process); } + + return StatusModel.IGNORED_STATUS; } private void listMBean(CommandProcess process) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/PerfCounterCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/PerfCounterCommand.java index a388a7dba2c..b568fc463d6 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/PerfCounterCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/PerfCounterCommand.java @@ -12,6 +12,7 @@ import com.taobao.arthas.common.JavaVersionUtils; import com.taobao.arthas.common.PidUtils; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Description; @@ -50,7 +51,7 @@ public void setDetails(boolean details) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { try { TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); if (this.details) { @@ -81,6 +82,8 @@ public void process(CommandProcess process) { } finally { process.end(); } + + return StatusModel.IGNORED_STATUS; } private static List getPerfCounters() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java index 96c6a3bb052..eb9fd4e578a 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java @@ -16,6 +16,7 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.common.OSUtils; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.cli.CliToken; import com.taobao.arthas.core.shell.cli.Completion; @@ -269,14 +270,14 @@ private static String execute(AsyncProfiler asyncProfiler, String arg) } @Override - public void process(final CommandProcess process) { + public StatusModel process(final CommandProcess process) { int status = 0; try { ProfilerAction profilerAction = ProfilerAction.valueOf(action); if (ProfilerAction.actions.equals(profilerAction)) { process.write("Supported Actions: " + actions() + "\n"); - return; + return StatusModel.IGNORED_STATUS; } final AsyncProfiler asyncProfiler = this.profilerInstance(); @@ -285,7 +286,7 @@ public void process(final CommandProcess process) { if (actionArg == null) { process.write("actionArg can not be empty.\n"); status = 1; - return; + return StatusModel.IGNORED_STATUS; } String result = execute(asyncProfiler, this.actionArg); process.write(result); @@ -368,6 +369,8 @@ public void run() { } finally { process.end(status); } + + return StatusModel.IGNORED_STATUS; } private String outputFile() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java index eb8a5f44beb..784d85b17fe 100755 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java @@ -1,6 +1,7 @@ package com.taobao.arthas.core.command.monitor200; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ArrayUtils; @@ -105,7 +106,7 @@ public void setLockedSynchronizers(boolean lockedSynchronizers) { } @Override - public void process(CommandProcess process) { + public StatusModel process(CommandProcess process) { Affect affect = new RowAffect(); int status = 0; try { @@ -122,6 +123,8 @@ public void process(CommandProcess process) { process.write(affect + "\n"); process.end(status); } + + return StatusModel.IGNORED_STATUS; } private int processAllThreads(CommandProcess process) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java index 707d44114a7..a0a3d991cbc 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java @@ -8,6 +8,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.express.ExpressException; import com.taobao.arthas.core.command.express.ExpressFactory; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.handlers.command.CommandInterruptHandler; import com.taobao.arthas.core.shell.handlers.shell.QExitHandler; @@ -265,7 +266,7 @@ int putTimeTunnel(TimeFragment tt) { } @Override - public void process(final CommandProcess process) { + public StatusModel process(final CommandProcess process) { // 检查参数 checkArguments(); @@ -293,6 +294,8 @@ public void process(final CommandProcess process) { processShow(process); } } + + return StatusModel.IGNORED_STATUS; } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/shell/command/AnnotatedCommand.java b/core/src/main/java/com/taobao/arthas/core/shell/command/AnnotatedCommand.java index fc88c654754..e6764b36618 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/command/AnnotatedCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/command/AnnotatedCommand.java @@ -1,5 +1,6 @@ package com.taobao.arthas.core.shell.command; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.middleware.cli.CLI; @@ -31,8 +32,9 @@ public CLI cli() { * Process the command, when the command is done processing it should call the {@link CommandProcess#end()} method. * * @param process the command process + * @return statusModel of command execute */ - public abstract void process(CommandProcess process); + public abstract StatusModel process(CommandProcess process); /** * Perform command completion, when the command is done completing it should call {@link Completion#complete(List)} diff --git a/core/src/main/java/com/taobao/arthas/core/shell/command/impl/AnnotatedCommandImpl.java b/core/src/main/java/com/taobao/arthas/core/shell/command/impl/AnnotatedCommandImpl.java index 2310f6b3e7d..7343de347a2 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/command/impl/AnnotatedCommandImpl.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/command/impl/AnnotatedCommandImpl.java @@ -1,5 +1,6 @@ package com.taobao.arthas.core.shell.command.impl; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.Command; @@ -79,7 +80,18 @@ private void process(CommandProcess process) { return; } CLIConfigurator.inject(process.commandLine(), instance); - instance.process(process); + StatusModel status = instance.process(process); + if (status != null) { + if (StatusModel.isIgnored(status)) { + // TODO 暂时兼容老代码,改造完毕后不能返回IGNORED_STATUS状态 + + } else if (!StatusModel.isPending(status)) { + process.end(status.getStatusCode(), status.getMessage()); + } + } else { + //代码处理不正确,不应该返回null状态 + throw new IllegalStateException("Command exit status is null"); + } UserStatUtil.arthasUsageSuccess(name(), process.args()); } From ea2ed2303a53786c032dbcc825590365bc09c814 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Tue, 7 Jul 2020 15:31:05 +0800 Subject: [PATCH 04/18] change Command.process() return ExitStatus --- .../core/command/basic1000/CatCommand.java | 18 ++-- .../core/command/basic1000/ClsCommand.java | 8 +- .../core/command/basic1000/EchoCommand.java | 6 +- .../core/command/basic1000/GrepCommand.java | 6 +- .../core/command/basic1000/HelpCommand.java | 6 +- .../command/basic1000/HistoryCommand.java | 6 +- .../core/command/basic1000/KeymapCommand.java | 11 ++- .../command/basic1000/OptionsCommand.java | 24 ++--- .../core/command/basic1000/PwdCommand.java | 6 +- .../core/command/basic1000/ResetCommand.java | 10 +-- .../command/basic1000/SessionCommand.java | 6 +- .../command/basic1000/ShutdownCommand.java | 6 +- .../core/command/basic1000/StopCommand.java | 6 +- .../command/basic1000/SystemEnvCommand.java | 8 +- .../basic1000/SystemPropertyCommand.java | 10 +-- .../core/command/basic1000/TeeCommand.java | 6 +- .../command/basic1000/VMOptionCommand.java | 12 +-- .../command/basic1000/VersionCommand.java | 6 +- .../core/command/hidden/JulyCommand.java | 6 +- .../core/command/hidden/ThanksCommand.java | 6 +- .../command/klass100/ClassLoaderCommand.java | 42 ++++----- .../command/klass100/DumpClassCommand.java | 20 ++--- .../command/klass100/GetStaticCommand.java | 18 ++-- .../core/command/klass100/JadCommand.java | 18 ++-- .../klass100/MemoryCompilerCommand.java | 10 +-- .../core/command/klass100/OgnlCommand.java | 12 +-- .../command/klass100/RedefineCommand.java | 20 ++--- .../command/klass100/SearchClassCommand.java | 8 +- .../command/klass100/SearchMethodCommand.java | 10 +-- .../core/command/logger/LoggerCommand.java | 6 +- .../core/command/model/StatusModel.java | 72 --------------- .../command/monitor200/DashboardCommand.java | 6 +- .../command/monitor200/EnhancerCommand.java | 6 +- .../command/monitor200/HeapDumpCommand.java | 6 +- .../core/command/monitor200/JvmCommand.java | 6 +- .../core/command/monitor200/MBeanCommand.java | 6 +- .../monitor200/PerfCounterCommand.java | 6 +- .../command/monitor200/ProfilerCommand.java | 10 +-- .../command/monitor200/ThreadCommand.java | 6 +- .../command/monitor200/TimeTunnelCommand.java | 6 +- .../core/shell/command/AnnotatedCommand.java | 3 +- .../arthas/core/shell/command/ExitStatus.java | 89 +++++++++++++++++++ .../command/impl/AnnotatedCommandImpl.java | 8 +- 43 files changed, 291 insertions(+), 276 deletions(-) create mode 100644 core/src/main/java/com/taobao/arthas/core/shell/command/ExitStatus.java diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java index f53fec57e4b..dba163417bd 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java @@ -8,7 +8,7 @@ import com.taobao.arthas.core.command.model.CatModel; import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -48,31 +48,31 @@ public void setSizeLimit(Integer sizeLimit) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { if (sizeLimit > maxSizeLimit) { - return StatusModel.failure(-1, "sizeLimit cannot be large than: " + maxSizeLimit); + return ExitStatus.failure(-1, "sizeLimit cannot be large than: " + maxSizeLimit); } //目前不支持过滤,限制http请求执行的文件大小 int maxSizeLimitOfNonTty = 128 * 1024; if (!process.session().isTty() && sizeLimit > maxSizeLimitOfNonTty) { - return StatusModel.failure(-1, "When executing in non-tty session, sizeLimit cannot be large than: " + maxSizeLimitOfNonTty); + return ExitStatus.failure(-1, "When executing in non-tty session, sizeLimit cannot be large than: " + maxSizeLimitOfNonTty); } for (String file : files) { File f = new File(file); if (!f.exists()) { - return StatusModel.failure(-1, "cat " + file + ": No such file or directory"); + return ExitStatus.failure(-1, "cat " + file + ": No such file or directory"); } if (f.isDirectory()) { - return StatusModel.failure(-1, "cat " + file + ": Is a directory"); + return ExitStatus.failure(-1, "cat " + file + ": Is a directory"); } } for (String file : files) { File f = new File(file); if (f.length() > sizeLimit) { - return StatusModel.failure(-1, "cat " + file + ": Is too large, size: " + f.length()); + return ExitStatus.failure(-1, "cat " + file + ": Is too large, size: " + f.length()); } try { String fileToString = FileUtils.readFileToString(f, @@ -80,11 +80,11 @@ public StatusModel process(CommandProcess process) { process.appendResult(new CatModel(file, fileToString)); } catch (IOException e) { logger.error("cat read file error. name: " + file, e); - return StatusModel.failure(1, "cat read file error: " + e.getMessage()); + return ExitStatus.failure(1, "cat read file error: " + e.getMessage()); } } - return StatusModel.success(); + return ExitStatus.success(); } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java index c82309be51d..ca01c4351a6 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java @@ -1,6 +1,6 @@ package com.taobao.arthas.core.command.basic1000; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Name; @@ -11,11 +11,11 @@ @Summary("Clear the screen") public class ClsCommand extends AnnotatedCommand { @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { if (!process.session().isTty()) { - return StatusModel.failure(-1, "Command 'cls' is only support tty session."); + return ExitStatus.failure(-1, "Command 'cls' is only support tty session."); } process.write(RenderUtil.cls()).write("\n"); - return StatusModel.success(); + return ExitStatus.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/EchoCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/EchoCommand.java index a20a8d18af3..23ab2cf4adb 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/EchoCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/EchoCommand.java @@ -2,7 +2,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.EchoModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Argument; @@ -30,12 +30,12 @@ public void setMessage(String message) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { if (message != null) { process.appendResult(new EchoModel(message)); } - return StatusModel.success(); + return ExitStatus.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java index 1c4174928cb..cf8ecb955f7 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java @@ -1,7 +1,7 @@ package com.taobao.arthas.core.command.basic1000; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Argument; @@ -168,7 +168,7 @@ public int getMaxCount() { } @Override - public StatusModel process(CommandProcess process) { - return StatusModel.failure(-1, "The grep command only for pipes. See 'grep --help'\n"); + public ExitStatus process(CommandProcess process) { + return ExitStatus.failure(-1, "The grep command only for pipes. See 'grep --help'\n"); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HelpCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HelpCommand.java index d423107a49c..9546610e219 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HelpCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HelpCommand.java @@ -4,7 +4,7 @@ import com.taobao.arthas.core.command.model.CommandOptionVO; import com.taobao.arthas.core.command.model.CommandVO; import com.taobao.arthas.core.command.model.HelpModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -40,7 +40,7 @@ public void setCmd(String cmd) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { List commands = allCommands(process.session()); Command targetCmd = findCommand(commands); if (targetCmd == null) { @@ -48,7 +48,7 @@ public StatusModel process(CommandProcess process) { } else { process.appendResult(createHelpDetailModel(targetCmd)); } - return StatusModel.success(); + return ExitStatus.success(); } public HelpModel createHelpDetailModel(Command targetCmd) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java index 3aa0a959949..64e8960a503 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java @@ -5,7 +5,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.HistoryModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; @@ -46,7 +46,7 @@ public void setNumber(int n) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { Session session = process.session(); //TODO 修改term history实现方式,统一使用HistoryManager Object termObject = session.get(Session.TTY); @@ -85,6 +85,6 @@ public StatusModel process(CommandProcess process) { } } - return StatusModel.success(); + return ExitStatus.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java index e5bf512b24f..c6aeb07ec5f 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java @@ -4,7 +4,7 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.common.IOUtils; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.term.impl.Helper; @@ -18,7 +18,6 @@ import static com.taobao.text.ui.Element.label; import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -35,9 +34,9 @@ public class KeymapCommand extends AnnotatedCommand { private static final Logger logger = LoggerFactory.getLogger(KeymapCommand.class); @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { if (!process.session().isTty()) { - return StatusModel.failure(-1, "Command 'keymap' is only support tty session."); + return ExitStatus.failure(-1, "Command 'keymap' is only support tty session."); } InputStream inputrc = Helper.loadInputRcFile(); @@ -63,10 +62,10 @@ public StatusModel process(CommandProcess process) { } process.write(RenderUtil.render(table, process.width())); - return StatusModel.success(); + return ExitStatus.success(); } catch (Throwable e) { logger.error("read inputrc file error.", e); - return StatusModel.failure(-1, "read inputrc file error."); + return ExitStatus.failure(-1, "read inputrc file error."); } finally { IOUtils.close(inputrc); } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java index 6fc63d1f91f..9b6ee28ca30 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java @@ -6,7 +6,7 @@ import com.taobao.arthas.core.command.model.ChangeResultVO; import com.taobao.arthas.core.command.model.OptionVO; import com.taobao.arthas.core.command.model.OptionsModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.CliToken; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -68,7 +68,7 @@ public void setOptionValue(String optionValue) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { try { if (isShow()) { return processShow(process); @@ -80,7 +80,7 @@ public StatusModel process(CommandProcess process) { } catch (Throwable t) { logger.error("process options command error", t); - return StatusModel.failure(-1, "process options command error"); + return ExitStatus.failure(-1, "process options command error"); } } @@ -104,24 +104,24 @@ public void complete(Completion completion) { } } - private StatusModel processShow(CommandProcess process) throws IllegalAccessException { + private ExitStatus processShow(CommandProcess process) throws IllegalAccessException { Collection fields = findOptionFields(new RegexMatcher(".*")); process.appendResult(new OptionsModel(convertToOptionVOs(fields))); - return StatusModel.success(); + return ExitStatus.success(); } - private StatusModel processShowName(CommandProcess process) throws IllegalAccessException { + private ExitStatus processShowName(CommandProcess process) throws IllegalAccessException { Collection fields = findOptionFields(new EqualsMatcher(optionName)); process.appendResult(new OptionsModel(convertToOptionVOs(fields))); - return StatusModel.success(); + return ExitStatus.success(); } - private StatusModel processChangeNameValue(CommandProcess process) throws IllegalAccessException { + private ExitStatus processChangeNameValue(CommandProcess process) throws IllegalAccessException { Collection fields = findOptionFields(new EqualsMatcher(optionName)); // name not exists if (fields.isEmpty()) { - return StatusModel.failure(-1, format("options[%s] not found.", optionName)); + return ExitStatus.failure(-1, format("options[%s] not found.", optionName)); } Field field = fields.iterator().next(); @@ -149,16 +149,16 @@ private StatusModel processChangeNameValue(CommandProcess process) throws Illega } else if (isIn(type, short.class, String.class)) { FieldUtils.writeStaticField(field, afterValue = optionValue); } else { - return StatusModel.failure(-1, format("Options[%s] type[%s] was unsupported.", optionName, type.getSimpleName())); + return ExitStatus.failure(-1, format("Options[%s] type[%s] was unsupported.", optionName, type.getSimpleName())); } } catch (Throwable t) { - return StatusModel.failure(-1, format("Cannot cast option value[%s] to type[%s].", optionValue, type.getSimpleName())); + return ExitStatus.failure(-1, format("Cannot cast option value[%s] to type[%s].", optionValue, type.getSimpleName())); } ChangeResultVO changeResultVO = new ChangeResultVO(optionAnnotation.name(), beforeValue, afterValue); process.appendResult(new OptionsModel(changeResultVO)); - return StatusModel.success(); + return ExitStatus.success(); } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java index cb2f50e68c2..5dd1a16f0f7 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java @@ -3,7 +3,7 @@ import java.io.File; import com.taobao.arthas.core.command.model.PwdModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Name; @@ -13,9 +13,9 @@ @Summary("Return working directory name") public class PwdCommand extends AnnotatedCommand { @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { String path = new File("").getAbsolutePath(); process.appendResult(new PwdModel(path)); - return StatusModel.success(); + return ExitStatus.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java index df36bb3958e..2b454ea6ca7 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java @@ -3,7 +3,7 @@ import com.taobao.arthas.core.advisor.Enhancer; import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.ResetModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.matcher.Matcher; @@ -46,18 +46,18 @@ public void setRegEx(boolean regEx) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { Instrumentation inst = process.session().getInstrumentation(); Matcher matcher = SearchUtils.classNameMatcher(classPattern, isRegEx); try { EnhancerAffect enhancerAffect = Enhancer.reset(inst, matcher); process.appendResult(new ResetModel(enhancerAffect)); - return StatusModel.success(); + return ExitStatus.success(); } catch (UnmodifiableClassException e) { // ignore - return StatusModel.failure(1, "unmodifiable class exception"); + return ExitStatus.failure(1, "unmodifiable class exception"); } catch (Throwable e) { - return StatusModel.failure(-1, "process failure: "+e.toString()); + return ExitStatus.failure(-1, "process failure: "+e.toString()); } } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java index c64c9405ff5..092e645db0f 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java @@ -1,7 +1,7 @@ package com.taobao.arthas.core.command.basic1000; import com.taobao.arthas.core.command.model.SessionModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; @@ -22,7 +22,7 @@ public class SessionCommand extends AnnotatedCommand { @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { SessionModel result = new SessionModel(); Session session = process.session(); result.setJavaPid(session.getPid()); @@ -43,7 +43,7 @@ public StatusModel process(CommandProcess process) { result.setStatUrl(statUrl); process.appendResult(result); - return StatusModel.success(); + return ExitStatus.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java index 32dff750aa8..825f16da81a 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java @@ -6,7 +6,7 @@ import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.ResetModel; import com.taobao.arthas.core.command.model.ShutdownModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.ShellServer; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -34,9 +34,9 @@ public class ShutdownCommand extends AnnotatedCommand { private static final Logger logger = LoggerFactory.getLogger(ShutdownCommand.class); @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { shutdown(process); - return StatusModel.success(); + return ExitStatus.success(); } public static void shutdown(CommandProcess process) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/StopCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/StopCommand.java index 767f6bdacb7..30177e559ba 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/StopCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/StopCommand.java @@ -1,6 +1,6 @@ package com.taobao.arthas.core.command.basic1000; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Name; @@ -15,8 +15,8 @@ @Summary("Stop/Shutdown Arthas server and exit the console.") public class StopCommand extends AnnotatedCommand { @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { ShutdownCommand.shutdown(process); - return StatusModel.success(); + return ExitStatus.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java index 6f631057129..3cd460a8f5d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java @@ -1,7 +1,7 @@ package com.taobao.arthas.core.command.basic1000; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.command.model.SystemEnvModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -31,7 +31,7 @@ public void setOptionName(String envName) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { try { SystemEnvModel result = new SystemEnvModel(); if (StringUtils.isBlank(envName)) { @@ -43,9 +43,9 @@ public StatusModel process(CommandProcess process) { result.put(envName, value); } process.appendResult(result); - return StatusModel.success(); + return ExitStatus.success(); } catch (Throwable t) { - return StatusModel.failure(-1, "Error during setting system env: " + t.getMessage()); + return ExitStatus.failure(-1, "Error during setting system env: " + t.getMessage()); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java index c6797762077..b9b1b740f14 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java @@ -2,7 +2,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.MessageModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.command.model.SystemPropertyModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -39,7 +39,7 @@ public void setOptionValue(String propertyValue) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { try { if (StringUtils.isBlank(propertyName) && StringUtils.isBlank(propertyValue)) { @@ -49,7 +49,7 @@ public StatusModel process(CommandProcess process) { // view the specified system property String value = System.getProperty(propertyName); if (value == null) { - return StatusModel.failure(1, "There is no property with the key " + propertyName); + return ExitStatus.failure(1, "There is no property with the key " + propertyName); } else { process.appendResult(new SystemPropertyModel(propertyName, value)); } @@ -59,9 +59,9 @@ public StatusModel process(CommandProcess process) { process.appendResult(new MessageModel("Successfully changed the system property.")); process.appendResult(new SystemPropertyModel(propertyName, System.getProperty(propertyName))); } - return StatusModel.success(); + return ExitStatus.success(); } catch (Throwable t) { - return StatusModel.failure(-1, "Error during setting system property: " + t.getMessage()); + return ExitStatus.failure(-1, "Error during setting system property: " + t.getMessage()); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java index 0f983c54f12..c263b27f64a 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java @@ -2,7 +2,7 @@ import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.*; @@ -34,8 +34,8 @@ public void setRegEx(boolean append) { } @Override - public StatusModel process(CommandProcess process) { - return StatusModel.failure(-1, "The tee command only for pipes. See 'tee --help'"); + public ExitStatus process(CommandProcess process) { + return ExitStatus.failure(-1, "The tee command only for pipes. See 'tee --help'"); } public String getFilePath() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java index 4fa14fd3c3e..34ad8843245 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java @@ -12,7 +12,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.ChangeResultVO; import com.taobao.arthas.core.command.model.MessageModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.command.model.VMOptionModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -53,11 +53,11 @@ public void setOptionValue(String value) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { return run(process, name, value); } - private static StatusModel run(CommandProcess process, String name, String value) { + private static ExitStatus run(CommandProcess process, String name, String value) { try { HotSpotDiagnosticMXBean hotSpotDiagnosticMXBean = ManagementFactory .getPlatformMXBean(HotSpotDiagnosticMXBean.class); @@ -69,7 +69,7 @@ private static StatusModel run(CommandProcess process, String name, String value // view the specified option VMOption option = hotSpotDiagnosticMXBean.getVMOption(name); if (option == null) { - return StatusModel.failure(-1, "In order to change the system properties, you must specify the property value."); + return ExitStatus.failure(-1, "In order to change the system properties, you must specify the property value."); } else { process.appendResult(new VMOptionModel(Arrays.asList(option))); } @@ -83,10 +83,10 @@ private static StatusModel run(CommandProcess process, String name, String value process.appendResult(new VMOptionModel(new ChangeResultVO(name, originValue, hotSpotDiagnosticMXBean.getVMOption(name).getValue()))); } - return StatusModel.success(); + return ExitStatus.success(); } catch (Throwable t) { logger.error("Error during setting vm option", t); - return StatusModel.failure(-1, "Error during setting vm option: " + t.getMessage()); + return ExitStatus.failure(-1, "Error during setting vm option: " + t.getMessage()); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VersionCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VersionCommand.java index 716d103fce5..da2ffc3a302 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VersionCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VersionCommand.java @@ -1,7 +1,7 @@ package com.taobao.arthas.core.command.basic1000; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.command.model.VersionModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; @@ -19,11 +19,11 @@ public class VersionCommand extends AnnotatedCommand { @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { VersionModel result = new VersionModel(); result.setVersion(ArthasBanner.version()); process.appendResult(result); - return StatusModel.success(); + return ExitStatus.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/hidden/JulyCommand.java b/core/src/main/java/com/taobao/arthas/core/command/hidden/JulyCommand.java index 5ef7a440774..59fea15bcf9 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/hidden/JulyCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/hidden/JulyCommand.java @@ -1,6 +1,6 @@ package com.taobao.arthas.core.command.hidden; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Hidden; @@ -15,9 +15,9 @@ @Hidden public class JulyCommand extends AnnotatedCommand { @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { process.write(new String($$())).write("\n"); - return StatusModel.success(); + return ExitStatus.success(); } private static byte[] $$() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/hidden/ThanksCommand.java b/core/src/main/java/com/taobao/arthas/core/command/hidden/ThanksCommand.java index 5f6ee63f9fe..745ae86ad98 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/hidden/ThanksCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/hidden/ThanksCommand.java @@ -1,6 +1,6 @@ package com.taobao.arthas.core.command.hidden; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ArthasBanner; @@ -19,8 +19,8 @@ @Hidden public class ThanksCommand extends AnnotatedCommand { @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { process.write(ArthasBanner.credit()).write("\n"); - return StatusModel.success(); + return ExitStatus.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java index f1bec9c6954..fca642cef07 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java @@ -9,7 +9,7 @@ import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.handlers.Handler; @@ -110,7 +110,7 @@ public void setLoadClass(String className) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { // ctrl-C support process.interruptHandler(new ClassLoaderInterruptHandler(process, isInterrupted)); @@ -137,7 +137,7 @@ public StatusModel process(CommandProcess process) { * @param inst * @return */ - private StatusModel processClassLoaderStats(CommandProcess process, Instrumentation inst) { + private ExitStatus processClassLoaderStats(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); List classLoaderInfos = getAllClassLoaderInfo(inst); Map classLoaderStats = new HashMap(); @@ -160,10 +160,10 @@ private StatusModel processClassLoaderStats(CommandProcess process, Instrumentat affect.rCnt(sorted.keySet().size()); process.appendResult(new RowAffectModel(affect)); - return StatusModel.success(); + return ExitStatus.success(); } - private StatusModel processClassLoaders(CommandProcess process, Instrumentation inst) { + private ExitStatus processClassLoaders(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); List classLoaderInfos = includeReflectionClassLoader ? getAllClassLoaderInfo(inst) : getAllClassLoaderInfo(inst, new SunReflectionClassLoaderFilter()); @@ -181,11 +181,11 @@ private StatusModel processClassLoaders(CommandProcess process, Instrumentation affect.rCnt(classLoaderInfos.size()); process.appendResult(new RowAffectModel(affect)); - return StatusModel.success(); + return ExitStatus.success(); } // 根据 hashCode 来打印URLClassLoader的urls - private StatusModel processClassLoader(CommandProcess process, Instrumentation inst) { + private ExitStatus processClassLoader(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); Set allClassLoader = getAllClassLoaders(inst); for (ClassLoader cl : allClassLoader) { @@ -206,11 +206,11 @@ private StatusModel processClassLoader(CommandProcess process, Instrumentation i } } process.appendResult(new RowAffectModel(affect)); - return StatusModel.success(); + return ExitStatus.success(); } // 使用ClassLoader去getResources - private StatusModel processResources(CommandProcess process, Instrumentation inst) { + private ExitStatus processResources(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); int rowCount = 0; Set allClassLoader = getAllClassLoaders(inst); @@ -233,11 +233,11 @@ private StatusModel processResources(CommandProcess process, Instrumentation ins process.appendResult(new ClassLoaderModel().setResources(resources)); process.appendResult(new RowAffectModel(affect)); - return StatusModel.success(); + return ExitStatus.success(); } // Use ClassLoader to loadClass - private StatusModel processLoadClass(CommandProcess process, Instrumentation inst) { + private ExitStatus processLoadClass(CommandProcess process, Instrumentation inst) { Set allClassLoader = getAllClassLoaders(inst); for (ClassLoader cl : allClassLoader) { if (Integer.toHexString(cl.hashCode()).equals(hashCode)) { @@ -249,24 +249,24 @@ private StatusModel processLoadClass(CommandProcess process, Instrumentation ins } catch (Throwable e) { logger.warn("load class error, class: {}", this.loadClass, e); - return StatusModel.failure(-1, "load class error, class:" + this.loadClass + ", error: " + e.toString()); + return ExitStatus.failure(-1, "load class error, class:" + this.loadClass + ", error: " + e.toString()); } } } - return StatusModel.success(); + return ExitStatus.success(); } - private StatusModel processAllClasses(CommandProcess process, Instrumentation inst) { + private ExitStatus processAllClasses(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); - StatusModel statusModel = getAllClasses(hashCode, inst, affect, process); - if (StatusModel.isFailed(statusModel)) { - return statusModel; + ExitStatus exitStatus = getAllClasses(hashCode, inst, affect, process); + if (ExitStatus.isFailed(exitStatus)) { + return exitStatus; } if (isInterrupted.get()) { - return StatusModel.failure(1, "Interrupted by user"); + return ExitStatus.failure(1, "Interrupted by user"); } process.appendResult(new RowAffectModel(affect)); - return StatusModel.success(); + return ExitStatus.success(); } /** @@ -275,7 +275,7 @@ private StatusModel processAllClasses(CommandProcess process, Instrumentation in * 当hashCode是null,则把所有的classloader的都打印 */ @SuppressWarnings("rawtypes") - private StatusModel getAllClasses(String hashCode, Instrumentation inst, RowAffect affect, CommandProcess process) { + private ExitStatus getAllClasses(String hashCode, Instrumentation inst, RowAffect affect, CommandProcess process) { int hashCodeInt = -1; if (hashCode != null) { hashCodeInt = Integer.valueOf(hashCode, 16); @@ -324,7 +324,7 @@ public int compare(Class o1, Class o2) { for (Entry> entry : classLoaderClassMap.entrySet()) { if (isInterrupted.get()) { - return StatusModel.failure(1, "Interrupted by user"); + return ExitStatus.failure(1, "Interrupted by user"); } ClassLoader classLoader = entry.getKey(); SortedSet classSet = entry.getValue(); diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java index ed4fdeac169..20a7030eb00 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java @@ -7,7 +7,7 @@ import com.taobao.arthas.core.command.model.DumpClassModel; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -87,11 +87,11 @@ public void setLimit(int limit) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { if (directory != null) { File dir = new File(directory); if (dir.isFile()) { - return StatusModel.failure(-1, directory + " :is not a directory, please check it"); + return ExitStatus.failure(-1, directory + " :is not a directory, please check it"); } } Instrumentation inst = process.session().getInstrumentation(); @@ -112,7 +112,7 @@ public void complete(Completion completion) { } } - private StatusModel processMatch(CommandProcess process, Instrumentation inst, Set> matchedClasses) { + private ExitStatus processMatch(CommandProcess process, Instrumentation inst, Set> matchedClasses) { RowAffect effect = new RowAffect(); try { Map, File> classFiles = dump(inst, matchedClasses); @@ -127,16 +127,16 @@ private StatusModel processMatch(CommandProcess process, Instrumentation inst, S } process.appendResult(new DumpClassModel().setDumpedClassFiles(dumpedClasses)); - return StatusModel.success(); + return ExitStatus.success(); } catch (Throwable t) { logger.error("dump: fail to dump classes: " + matchedClasses, t); - return StatusModel.failure(-1, "dump: fail to dump classes: " + matchedClasses); + return ExitStatus.failure(-1, "dump: fail to dump classes: " + matchedClasses); } finally { process.appendResult(new RowAffectModel(effect)); } } - private StatusModel processMatches(CommandProcess process, Set> matchedClasses) { + private ExitStatus processMatches(CommandProcess process, Set> matchedClasses) { String msg = String.format( "Found more than %d class for: %s, Please Try to specify the classloader with the -c option, or try to use --limit option.", limit, classPattern); @@ -144,11 +144,11 @@ private StatusModel processMatches(CommandProcess process, Set> matched List classVOs = ClassUtils.createClassVOList(matchedClasses); process.appendResult(new DumpClassModel().setMatchedClasses(classVOs)); - return StatusModel.failure(-1, msg); + return ExitStatus.failure(-1, msg); } - private StatusModel processNoMatch(CommandProcess process) { - return StatusModel.failure(-1, "No class found for: " + classPattern); + private ExitStatus processNoMatch(CommandProcess process) { + return ExitStatus.failure(-1, "No class found for: " + classPattern); } private Map, File> dump(Instrumentation inst, Set> classes) throws UnmodifiableClassException { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java index 99fc34ac5d4..5d5b0750896 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java @@ -9,7 +9,7 @@ import com.taobao.arthas.core.command.model.GetStaticModel; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ClassUtils; @@ -89,11 +89,11 @@ public void setExpand(Integer expand) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { Instrumentation inst = process.session().getInstrumentation(); Set> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, hashCode); if (matchedClasses == null || matchedClasses.isEmpty()) { - return StatusModel.failure(-1, "No class found for: " + classPattern); + return ExitStatus.failure(-1, "No class found for: " + classPattern); } else if (matchedClasses.size() > 1) { return processMatches(process, matchedClasses); } else { @@ -101,8 +101,8 @@ public StatusModel process(CommandProcess process) { } } - private StatusModel processExactMatch(CommandProcess process, Instrumentation inst, - Set> matchedClasses) { + private ExitStatus processExactMatch(CommandProcess process, Instrumentation inst, + Set> matchedClasses) { RowAffect affect = new RowAffect(); Matcher fieldNameMatcher = fieldNameMatcher(); @@ -142,16 +142,16 @@ private StatusModel processExactMatch(CommandProcess process, Instrumentation in } if (!found) { - return StatusModel.failure(-1, "getstatic: no matched static field was found"); + return ExitStatus.failure(-1, "getstatic: no matched static field was found"); } else { - return StatusModel.success(); + return ExitStatus.success(); } } finally { process.appendResult(new RowAffectModel(affect)); } } - private StatusModel processMatches(CommandProcess process, Set> matchedClasses) { + private ExitStatus processMatches(CommandProcess process, Set> matchedClasses) { // Element usage = new LabelElement("getstatic -c " + classPattern + " " + fieldPattern).style( // Decoration.bold.fg(Color.blue)); @@ -162,7 +162,7 @@ private StatusModel processMatches(CommandProcess process, Set> matched List matchedClassVOs = ClassUtils.createClassVOList(matchedClasses); process.appendResult(new GetStaticModel(matchedClassVOs)); - return StatusModel.failure(-1, "Found more than one class for: " + classPattern + ", Please use: "+usage); + return ExitStatus.failure(-1, "Found more than one class for: " + classPattern + ", Please use: "+usage); } private Matcher fieldNameMatcher() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java index 6a6683fddbd..cf2ebc5f534 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java @@ -7,7 +7,7 @@ import com.taobao.arthas.core.command.model.JadModel; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -97,7 +97,7 @@ public void setSourceOnly(boolean sourceOnly) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); Set> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, code); @@ -122,7 +122,7 @@ public StatusModel process(CommandProcess process) { } } - private StatusModel processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, Set> matchedClasses, Set> withInnerClasses) { + private ExitStatus processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, Set> matchedClasses, Set> withInnerClasses) { Class c = matchedClasses.iterator().next(); Set> allClasses = new HashSet>(withInnerClasses); allClasses.add(c); @@ -150,14 +150,14 @@ private StatusModel processExactMatch(CommandProcess process, RowAffect affect, process.appendResult(jadModel); affect.rCnt(classFiles.keySet().size()); - return StatusModel.success(); + return ExitStatus.success(); } catch (Throwable t) { logger.error("jad: fail to decompile class: " + c.getName(), t); - return StatusModel.failure(-1, "jad: fail to decompile class: " + c.getName()); + return ExitStatus.failure(-1, "jad: fail to decompile class: " + c.getName()); } } - private StatusModel processMatches(CommandProcess process, Set> matchedClasses) { + private ExitStatus processMatches(CommandProcess process, Set> matchedClasses) { //Element usage = new LabelElement("jad -c " + classPattern).style(Decoration.bold.fg(Color.blue)); //process.write("\n Found more than one class for: " + classPattern + ", Please use " // + RenderUtil.render(usage, process.width())); @@ -171,11 +171,11 @@ private StatusModel processMatches(CommandProcess process, Set> matched jadModel.setMatchedClasses(classVOs); process.appendResult(jadModel); - return StatusModel.failure(-1, msg); + return ExitStatus.failure(-1, msg); } - private StatusModel processNoMatch(CommandProcess process) { - return StatusModel.failure(-1, "No class found for: " + classPattern); + private ExitStatus processNoMatch(CommandProcess process) { + return ExitStatus.failure(-1, "No class found for: " + classPattern); } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java index 052cfca61ca..834613ed0af 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java @@ -14,7 +14,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.MemoryCompilerModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -73,7 +73,7 @@ public void setDirectory(String directory) { } @Override - public StatusModel process(final CommandProcess process) { + public ExitStatus process(final CommandProcess process) { RowAffect affect = new RowAffect(); try { @@ -84,7 +84,7 @@ public StatusModel process(final CommandProcess process) { } else { classloader = ClassLoaderUtils.getClassLoader(inst, hashCode); if (classloader == null) { - return StatusModel.failure(-1, "Can not find classloader with hashCode: " + hashCode + "."); + return ExitStatus.failure(-1, "Can not find classloader with hashCode: " + hashCode + "."); } } @@ -121,10 +121,10 @@ public StatusModel process(final CommandProcess process) { affect.rCnt(1); } process.appendResult(new MemoryCompilerModel(files)); - return StatusModel.success(); + return ExitStatus.success(); } catch (Throwable e) { logger.warn("Memory compiler error", e); - return StatusModel.failure(-1, "Memory compiler error, exception message: " + e.getMessage() + return ExitStatus.failure(-1, "Memory compiler error, exception message: " + e.getMessage() + ", please check $HOME/logs/arthas/arthas.log for more details."); } finally { process.appendResult(new RowAffectModel(affect)); diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java index d5b8143cc55..dba62eedaa5 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java @@ -9,7 +9,7 @@ import com.taobao.arthas.core.command.express.ExpressException; import com.taobao.arthas.core.command.express.ExpressFactory; import com.taobao.arthas.core.command.model.OgnlModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ClassLoaderUtils; @@ -61,7 +61,7 @@ public void setExpand(Integer expand) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { try { Instrumentation inst = process.session().getInstrumentation(); ClassLoader classLoader = null; @@ -72,7 +72,7 @@ public StatusModel process(CommandProcess process) { } if (classLoader == null) { - return StatusModel.failure(-1, "Can not find classloader with hashCode: " + hashCode + "."); + return ExitStatus.failure(-1, "Can not find classloader with hashCode: " + hashCode + "."); } Express unpooledExpress = ExpressFactory.unpooledExpress(classLoader); @@ -84,13 +84,13 @@ public StatusModel process(CommandProcess process) { process.appendResult(ognlModel); } catch (ExpressException e) { logger.warn("ognl: failed execute express: " + express, e); - return StatusModel.failure(-1, "Failed to execute ognl, exception message: " + e.getMessage() + return ExitStatus.failure(-1, "Failed to execute ognl, exception message: " + e.getMessage() + ", please check $HOME/logs/arthas/arthas.log for more details. "); } - return StatusModel.success(); + return ExitStatus.success(); } catch(Throwable e){ logger.error("process failure", e); - return StatusModel.failure(-1, "process failure: "+e.toString()); + return ExitStatus.failure(-1, "process failure: "+e.toString()); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java index 70ef4362ff1..4c8b5202f32 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java @@ -15,7 +15,7 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.RedefineModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -59,19 +59,19 @@ public void setPaths(List paths) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { RedefineModel redefineModel = new RedefineModel(); Instrumentation inst = process.session().getInstrumentation(); for (String path : paths) { File file = new File(path); if (!file.exists()) { - return StatusModel.failure(-1, "file does not exist, path:" + path); + return ExitStatus.failure(-1, "file does not exist, path:" + path); } if (!file.isFile()) { - return StatusModel.failure(-1, "not a normal file, path:" + path); + return ExitStatus.failure(-1, "not a normal file, path:" + path); } if (file.length() >= MAX_FILE_SIZE) { - return StatusModel.failure(-1, "file size: " + file.length() + " >= " + MAX_FILE_SIZE + ", path: " + path); + return ExitStatus.failure(-1, "file size: " + file.length() + " >= " + MAX_FILE_SIZE + ", path: " + path); } } @@ -89,7 +89,7 @@ public StatusModel process(CommandProcess process) { } catch (Exception e) { logger.warn("load class file failed: "+path, e); - return StatusModel.failure(-1, "load class file failed: " +path+", error: " + e); + return ExitStatus.failure(-1, "load class file failed: " +path+", error: " + e); } finally { if (f != null) { try { @@ -102,7 +102,7 @@ public StatusModel process(CommandProcess process) { } if (bytesMap.size() != paths.size()) { - return StatusModel.failure(-1, "paths may contains same class name!"); + return ExitStatus.failure(-1, "paths may contains same class name!"); } List definitions = new ArrayList(); @@ -120,15 +120,15 @@ public StatusModel process(CommandProcess process) { try { if (definitions.isEmpty()) { - return StatusModel.failure(-1, "These classes are not found in the JVM and may not be loaded: " + bytesMap.keySet()); + return ExitStatus.failure(-1, "These classes are not found in the JVM and may not be loaded: " + bytesMap.keySet()); } inst.redefineClasses(definitions.toArray(new ClassDefinition[0])); process.appendResult(redefineModel); } catch (Exception e) { - return StatusModel.failure(-1, "redefine error! " + e); + return ExitStatus.failure(-1, "redefine error! " + e); } - return StatusModel.success(); + return ExitStatus.success(); } private static String readClassName(final byte[] bytes) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java index 467fcd8553d..d3a3c62b50d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java @@ -11,7 +11,7 @@ import com.taobao.arthas.core.command.model.SearchClassModel; import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -93,7 +93,7 @@ public void setNumberOfLimit(int numberOfLimit) { } @Override - public StatusModel process(final CommandProcess process) { + public ExitStatus process(final CommandProcess process) { // TODO: null check RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); @@ -107,7 +107,7 @@ public int compare(Class c1, Class c2) { if (isDetail) { if (matchedClasses.size() > numberOfLimit) { - return StatusModel.failure(-1, "Matching classes are too many: " + matchedClasses.size()); + return ExitStatus.failure(-1, "Matching classes are too many: " + matchedClasses.size()); } for (Class clazz : matchedClasses) { ClassVO classInfo = ClassUtils.createClassInfo(clazz, isDetail, isField); @@ -126,7 +126,7 @@ public boolean handle(List classNames, int segment) { affect.rCnt(matchedClasses.size()); process.appendResult(new RowAffectModel(affect)); - return StatusModel.success(); + return ExitStatus.success(); } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java index 5b00d4fb044..145a6798411 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java @@ -12,7 +12,7 @@ import com.taobao.arthas.core.command.model.SearchMethodModel; import com.taobao.arthas.core.command.model.MethodVO; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -92,7 +92,7 @@ public void setNumberOfLimit(int numberOfLimit) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); @@ -100,7 +100,7 @@ public StatusModel process(CommandProcess process) { Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode); if (matchedClasses.size() > numberOfLimit) { - return StatusModel.failure(-1, "Matching classes are too many: "+matchedClasses.size()); + return ExitStatus.failure(-1, "Matching classes are too many: "+matchedClasses.size()); } try { for (Class clazz : matchedClasses) { @@ -127,11 +127,11 @@ public StatusModel process(CommandProcess process) { //print failed className String msg = String.format("process class failed: %s, error: %s", clazz.getName(), e.toString()); logger.error(msg, e); - return StatusModel.failure(1, msg); + return ExitStatus.failure(1, msg); } } - return StatusModel.success(); + return ExitStatus.success(); } finally { process.appendResult(new RowAffectModel(affect)); } diff --git a/core/src/main/java/com/taobao/arthas/core/command/logger/LoggerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/logger/LoggerCommand.java index 89c3618b581..3e8c164670a 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/logger/LoggerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/logger/LoggerCommand.java @@ -21,7 +21,7 @@ import com.taobao.arthas.common.IOUtils; import com.taobao.arthas.common.ReflectUtils; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ClassLoaderUtils; @@ -111,7 +111,7 @@ public void setHaveAppender(boolean includeNoAppender) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { int status = 0; try { if (this.name != null && this.level != null) { @@ -122,7 +122,7 @@ public StatusModel process(CommandProcess process) { } finally { process.end(status); } - return StatusModel.IGNORED_STATUS; + return ExitStatus.IGNORED_STATUS; } public void level(CommandProcess process) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java index 31cf2125d2b..6c10e36172b 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java @@ -1,68 +1,6 @@ package com.taobao.arthas.core.command.model; public class StatusModel extends ResultModel { - - /** - * 异步执行的命令返回此状态,注意避免状态码冲突 - */ - public static final StatusModel PENDING_STATUS = new StatusModel(0x300000); - - /** - * TODO 暂时兼容老代码使用,忽略检查此命令的status,命令改造完毕后需要移除此变量 - */ - public static final StatusModel IGNORED_STATUS = new StatusModel(0x100000); - - /** - * 命令执行成功的状态 - * @return - */ - public static StatusModel success() { - return new StatusModel(0); - } - - /** - * 命令执行失败 - * @param statusCode - * @param message - * @return - */ - public static StatusModel failure(int statusCode, String message) { - if (statusCode == 0) { - throw new IllegalArgumentException("failure status code cannot be 0"); - } - if (statusCode == PENDING_STATUS.statusCode) { - throw new IllegalArgumentException("failure status cannot equals to PENDING_STATUS"); - } - return new StatusModel(statusCode, message); - } - - /** - * 判断是否为失败状态 - * @param statusModel - * @return - */ - public static boolean isFailed(StatusModel statusModel) { - return statusModel != null && statusModel.getStatusCode() != 0; - } - - /** - * 判断是否为异步执行等待状态 - * @param statusModel - * @return - */ - public static boolean isPending(StatusModel statusModel) { - return statusModel != null && statusModel.getStatusCode() == PENDING_STATUS.getStatusCode(); - } - - /** - * TODO 判断是否为IGNORE状态,兼容老代码使用,改造完毕后需要移除 - * @param statusModel - * @return - */ - public static boolean isIgnored(StatusModel statusModel) { - return statusModel != null && statusModel.getStatusCode() == IGNORED_STATUS.getStatusCode(); - } - private int statusCode; private String message; @@ -82,20 +20,10 @@ public int getStatusCode() { return statusCode; } - public StatusModel setStatusCode(int statusCode) { - this.statusCode = statusCode; - return this; - } - public String getMessage() { return message; } - public StatusModel setMessage(String message) { - this.message = message; - return this; - } - public StatusModel setStatus(int statusCode, String message) { this.statusCode = statusCode; this.message = message; diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java index abfe4d60a91..6eafb3c0282 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java @@ -5,7 +5,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.handlers.Handler; @@ -78,7 +78,7 @@ public void setInterval(long interval) { @Override - public StatusModel process(final CommandProcess process) { + public ExitStatus process(final CommandProcess process) { Session session = process.session(); timer = new Timer("Timer-for-arthas-dashboard-" + session.getSessionId(), true); @@ -112,7 +112,7 @@ public void handle(Void event) { // start the timer timer.scheduleAtFixedRate(new DashboardTimerTask(process), 0, getInterval()); - return StatusModel.IGNORED_STATUS; + return ExitStatus.IGNORED_STATUS; } public synchronized void stop() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java index 37ef8feff31..1d13138411c 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java @@ -11,7 +11,7 @@ import com.taobao.arthas.core.advisor.AdviceWeaver; import com.taobao.arthas.core.advisor.Enhancer; import com.taobao.arthas.core.advisor.InvokeTraceable; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -78,7 +78,7 @@ AdviceListener getAdviceListenerWithId(CommandProcess process) { return getAdviceListener(process); } @Override - public StatusModel process(final CommandProcess process) { + public ExitStatus process(final CommandProcess process) { // ctrl-C support process.interruptHandler(new CommandInterruptHandler(process)); // q exit support @@ -87,7 +87,7 @@ public StatusModel process(final CommandProcess process) { // start to enhance enhance(process); - return StatusModel.IGNORED_STATUS; + return ExitStatus.IGNORED_STATUS; } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/HeapDumpCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/HeapDumpCommand.java index b3dd98ae889..85dd1a5d345 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/HeapDumpCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/HeapDumpCommand.java @@ -10,7 +10,7 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.sun.management.HotSpotDiagnosticMXBean; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Argument; @@ -48,7 +48,7 @@ public void setLive(boolean live) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { int status = 0; try { String dumpFile = file; @@ -73,7 +73,7 @@ public StatusModel process(CommandProcess process) { process.end(status); } - return StatusModel.IGNORED_STATUS; + return ExitStatus.IGNORED_STATUS; } private static void run(CommandProcess process, String file, boolean live) throws IOException { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/JvmCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/JvmCommand.java index 2a2f0aa2f6d..21923bc5721 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/JvmCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/JvmCommand.java @@ -1,7 +1,7 @@ package com.taobao.arthas.core.command.monitor200; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.StringUtils; @@ -43,7 +43,7 @@ public class JvmCommand extends AnnotatedCommand { private final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { RowAffect affect = new RowAffect(); TableElement table = new TableElement(2, 5).leftCellPadding(1).rightCellPadding(1); table.row(true, label("RUNTIME").style(Decoration.bold.bold())); @@ -83,7 +83,7 @@ public StatusModel process(CommandProcess process) { process.write(affect.toString()).write("\n"); process.end(); - return StatusModel.IGNORED_STATUS; + return ExitStatus.IGNORED_STATUS; } private void drawFileDescriptorTable(TableElement table) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/MBeanCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/MBeanCommand.java index ac3bd74cfe5..df453584c5d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/MBeanCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/MBeanCommand.java @@ -3,7 +3,7 @@ import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.CliToken; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -141,7 +141,7 @@ public int getNumOfExecutions() { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { if (StringUtils.isEmpty(getName())) { listMBean(process); } else if (isMetaData()) { @@ -150,7 +150,7 @@ public StatusModel process(CommandProcess process) { listAttribute(process); } - return StatusModel.IGNORED_STATUS; + return ExitStatus.IGNORED_STATUS; } private void listMBean(CommandProcess process) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/PerfCounterCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/PerfCounterCommand.java index b568fc463d6..1a05621d1ab 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/PerfCounterCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/PerfCounterCommand.java @@ -12,7 +12,7 @@ import com.taobao.arthas.common.JavaVersionUtils; import com.taobao.arthas.common.PidUtils; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Description; @@ -51,7 +51,7 @@ public void setDetails(boolean details) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { try { TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); if (this.details) { @@ -83,7 +83,7 @@ public StatusModel process(CommandProcess process) { process.end(); } - return StatusModel.IGNORED_STATUS; + return ExitStatus.IGNORED_STATUS; } private static List getPerfCounters() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java index eb9fd4e578a..f3c12f0ef14 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java @@ -16,7 +16,7 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.common.OSUtils; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.cli.CliToken; import com.taobao.arthas.core.shell.cli.Completion; @@ -270,14 +270,14 @@ private static String execute(AsyncProfiler asyncProfiler, String arg) } @Override - public StatusModel process(final CommandProcess process) { + public ExitStatus process(final CommandProcess process) { int status = 0; try { ProfilerAction profilerAction = ProfilerAction.valueOf(action); if (ProfilerAction.actions.equals(profilerAction)) { process.write("Supported Actions: " + actions() + "\n"); - return StatusModel.IGNORED_STATUS; + return ExitStatus.IGNORED_STATUS; } final AsyncProfiler asyncProfiler = this.profilerInstance(); @@ -286,7 +286,7 @@ public StatusModel process(final CommandProcess process) { if (actionArg == null) { process.write("actionArg can not be empty.\n"); status = 1; - return StatusModel.IGNORED_STATUS; + return ExitStatus.IGNORED_STATUS; } String result = execute(asyncProfiler, this.actionArg); process.write(result); @@ -370,7 +370,7 @@ public void run() { process.end(status); } - return StatusModel.IGNORED_STATUS; + return ExitStatus.IGNORED_STATUS; } private String outputFile() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java index 784d85b17fe..9233100a881 100755 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java @@ -1,7 +1,7 @@ package com.taobao.arthas.core.command.monitor200; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ArrayUtils; @@ -106,7 +106,7 @@ public void setLockedSynchronizers(boolean lockedSynchronizers) { } @Override - public StatusModel process(CommandProcess process) { + public ExitStatus process(CommandProcess process) { Affect affect = new RowAffect(); int status = 0; try { @@ -124,7 +124,7 @@ public StatusModel process(CommandProcess process) { process.end(status); } - return StatusModel.IGNORED_STATUS; + return ExitStatus.IGNORED_STATUS; } private int processAllThreads(CommandProcess process) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java index a0a3d991cbc..dbef8b23be2 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java @@ -8,7 +8,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.express.ExpressException; import com.taobao.arthas.core.command.express.ExpressFactory; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.handlers.command.CommandInterruptHandler; import com.taobao.arthas.core.shell.handlers.shell.QExitHandler; @@ -266,7 +266,7 @@ int putTimeTunnel(TimeFragment tt) { } @Override - public StatusModel process(final CommandProcess process) { + public ExitStatus process(final CommandProcess process) { // 检查参数 checkArguments(); @@ -295,7 +295,7 @@ public StatusModel process(final CommandProcess process) { } } - return StatusModel.IGNORED_STATUS; + return ExitStatus.IGNORED_STATUS; } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/shell/command/AnnotatedCommand.java b/core/src/main/java/com/taobao/arthas/core/shell/command/AnnotatedCommand.java index e6764b36618..56b535b03fd 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/command/AnnotatedCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/command/AnnotatedCommand.java @@ -1,6 +1,5 @@ package com.taobao.arthas.core.shell.command; -import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.middleware.cli.CLI; @@ -34,7 +33,7 @@ public CLI cli() { * @param process the command process * @return statusModel of command execute */ - public abstract StatusModel process(CommandProcess process); + public abstract ExitStatus process(CommandProcess process); /** * Perform command completion, when the command is done completing it should call {@link Completion#complete(List)} diff --git a/core/src/main/java/com/taobao/arthas/core/shell/command/ExitStatus.java b/core/src/main/java/com/taobao/arthas/core/shell/command/ExitStatus.java new file mode 100644 index 00000000000..b075165d0bb --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/shell/command/ExitStatus.java @@ -0,0 +1,89 @@ +package com.taobao.arthas.core.shell.command; + +/** + * 命令执行的结束状态 + */ +public class ExitStatus { + + /** + * 异步执行的命令返回此状态,注意避免状态码冲突 + */ + public static final ExitStatus PENDING_STATUS = new ExitStatus(0x300000); + + /** + * TODO 暂时兼容老代码使用,忽略检查此命令的status,命令改造完毕后需要移除此变量 + */ + public static final ExitStatus IGNORED_STATUS = new ExitStatus(0x100000); + + /** + * 命令执行成功的状态 + * @return + */ + public static ExitStatus success() { + return new ExitStatus(0); + } + + /** + * 命令执行失败 + * @param statusCode + * @param message + * @return + */ + public static ExitStatus failure(int statusCode, String message) { + if (statusCode == 0) { + throw new IllegalArgumentException("failure status code cannot be 0"); + } + if (statusCode == PENDING_STATUS.statusCode) { + throw new IllegalArgumentException("failure status cannot equals to PENDING_STATUS"); + } + return new ExitStatus(statusCode, message); + } + + /** + * 判断是否为失败状态 + * @param exitStatus + * @return + */ + public static boolean isFailed(ExitStatus exitStatus) { + return exitStatus != null && exitStatus.getStatusCode() != 0; + } + + /** + * 判断是否为异步执行等待状态 + * @param exitStatus + * @return + */ + public static boolean isPending(ExitStatus exitStatus) { + return exitStatus != null && exitStatus.getStatusCode() == PENDING_STATUS.getStatusCode(); + } + + /** + * TODO 判断是否为IGNORE状态,兼容老代码使用,改造完毕后需要移除 + * @param exitStatus + * @return + */ + public static boolean isIgnored(ExitStatus exitStatus) { + return exitStatus != null && exitStatus.getStatusCode() == IGNORED_STATUS.getStatusCode(); + } + + private int statusCode; + private String message; + + private ExitStatus(int statusCode) { + this.statusCode = statusCode; + } + + private ExitStatus(int statusCode, String message) { + this.statusCode = statusCode; + this.message = message; + } + + public int getStatusCode() { + return statusCode; + } + + public String getMessage() { + return message; + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/shell/command/impl/AnnotatedCommandImpl.java b/core/src/main/java/com/taobao/arthas/core/shell/command/impl/AnnotatedCommandImpl.java index 7343de347a2..8e3f8d324ca 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/command/impl/AnnotatedCommandImpl.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/command/impl/AnnotatedCommandImpl.java @@ -1,6 +1,6 @@ package com.taobao.arthas.core.shell.command.impl; -import com.taobao.arthas.core.command.model.StatusModel; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.Command; @@ -80,12 +80,12 @@ private void process(CommandProcess process) { return; } CLIConfigurator.inject(process.commandLine(), instance); - StatusModel status = instance.process(process); + ExitStatus status = instance.process(process); if (status != null) { - if (StatusModel.isIgnored(status)) { + if (ExitStatus.isIgnored(status)) { // TODO 暂时兼容老代码,改造完毕后不能返回IGNORED_STATUS状态 - } else if (!StatusModel.isPending(status)) { + } else if (!ExitStatus.isPending(status)) { process.end(status.getStatusCode(), status.getMessage()); } } else { From 727a883865a11c896c2b3507e6d9034e8366fdf1 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Tue, 7 Jul 2020 16:05:52 +0800 Subject: [PATCH 05/18] add SUCCESS_STATUS to ExitStatus --- .../com/taobao/arthas/core/shell/command/ExitStatus.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/taobao/arthas/core/shell/command/ExitStatus.java b/core/src/main/java/com/taobao/arthas/core/shell/command/ExitStatus.java index b075165d0bb..113c49dc067 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/command/ExitStatus.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/command/ExitStatus.java @@ -5,6 +5,11 @@ */ public class ExitStatus { + /** + * 命令执行成功的状态 + */ + public static final ExitStatus SUCCESS_STATUS = new ExitStatus(0); + /** * 异步执行的命令返回此状态,注意避免状态码冲突 */ @@ -20,7 +25,7 @@ public class ExitStatus { * @return */ public static ExitStatus success() { - return new ExitStatus(0); + return SUCCESS_STATUS; } /** From 0321478174fe1b6682b57fb3c5356bbe9dbf905d Mon Sep 17 00:00:00 2001 From: gongdewei Date: Thu, 9 Jul 2020 10:47:25 +0800 Subject: [PATCH 06/18] rollback commits of ExitStatus --- .../core/command/basic1000/CatCommand.java | 42 +++++--- .../core/command/basic1000/ClsCommand.java | 8 +- .../core/command/basic1000/EchoCommand.java | 6 +- .../core/command/basic1000/GrepCommand.java | 5 +- .../core/command/basic1000/HelpCommand.java | 5 +- .../command/basic1000/HistoryCommand.java | 5 +- .../core/command/basic1000/KeymapCommand.java | 12 +-- .../command/basic1000/OptionsCommand.java | 36 ++++--- .../core/command/basic1000/PwdCommand.java | 5 +- .../core/command/basic1000/ResetCommand.java | 9 +- .../command/basic1000/SessionCommand.java | 5 +- .../command/basic1000/ShutdownCommand.java | 4 +- .../core/command/basic1000/StopCommand.java | 4 +- .../command/basic1000/SystemEnvCommand.java | 8 +- .../basic1000/SystemPropertyCommand.java | 12 ++- .../core/command/basic1000/TeeCommand.java | 5 +- .../command/basic1000/VMOptionCommand.java | 14 +-- .../command/basic1000/VersionCommand.java | 5 +- .../core/command/hidden/JulyCommand.java | 6 +- .../core/command/hidden/ThanksCommand.java | 6 +- .../command/klass100/ClassLoaderCommand.java | 88 +++++++++-------- .../command/klass100/DumpClassCommand.java | 56 ++++++----- .../command/klass100/GetStaticCommand.java | 98 ++++++++++--------- .../core/command/klass100/JadCommand.java | 28 +++--- .../klass100/MemoryCompilerCommand.java | 14 ++- .../core/command/klass100/OgnlCommand.java | 19 ++-- .../command/klass100/RedefineCommand.java | 24 +++-- .../command/klass100/SearchClassCommand.java | 13 +-- .../command/klass100/SearchMethodCommand.java | 58 ++++++----- .../core/command/logger/LoggerCommand.java | 4 +- .../core/command/model/StatusModel.java | 21 ++++ .../command/monitor200/DashboardCommand.java | 5 +- .../command/monitor200/EnhancerCommand.java | 5 +- .../command/monitor200/HeapDumpCommand.java | 4 +- .../core/command/monitor200/JvmCommand.java | 5 +- .../core/command/monitor200/MBeanCommand.java | 5 +- .../monitor200/PerfCounterCommand.java | 5 +- .../command/monitor200/ProfilerCommand.java | 9 +- .../command/monitor200/ThreadCommand.java | 5 +- .../command/monitor200/TimeTunnelCommand.java | 5 +- .../core/shell/command/AnnotatedCommand.java | 3 +- .../command/impl/AnnotatedCommandImpl.java | 14 +-- 42 files changed, 347 insertions(+), 343 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java index dba163417bd..54149a60e0d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/CatCommand.java @@ -8,7 +8,6 @@ import com.taobao.arthas.core.command.model.CatModel; import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -48,31 +47,28 @@ public void setSizeLimit(Integer sizeLimit) { } @Override - public ExitStatus process(CommandProcess process) { - if (sizeLimit > maxSizeLimit) { - return ExitStatus.failure(-1, "sizeLimit cannot be large than: " + maxSizeLimit); - } - - //目前不支持过滤,限制http请求执行的文件大小 - int maxSizeLimitOfNonTty = 128 * 1024; - if (!process.session().isTty() && sizeLimit > maxSizeLimitOfNonTty) { - return ExitStatus.failure(-1, "When executing in non-tty session, sizeLimit cannot be large than: " + maxSizeLimitOfNonTty); + public void process(CommandProcess process) { + if (!verifyOptions(process)) { + return; } for (String file : files) { File f = new File(file); if (!f.exists()) { - return ExitStatus.failure(-1, "cat " + file + ": No such file or directory"); + process.end(-1, "cat " + file + ": No such file or directory"); + return; } if (f.isDirectory()) { - return ExitStatus.failure(-1, "cat " + file + ": Is a directory"); + process.end(-1, "cat " + file + ": Is a directory"); + return; } } for (String file : files) { File f = new File(file); if (f.length() > sizeLimit) { - return ExitStatus.failure(-1, "cat " + file + ": Is too large, size: " + f.length()); + process.end(-1, "cat " + file + ": Is too large, size: " + f.length()); + return; } try { String fileToString = FileUtils.readFileToString(f, @@ -80,11 +76,27 @@ public ExitStatus process(CommandProcess process) { process.appendResult(new CatModel(file, fileToString)); } catch (IOException e) { logger.error("cat read file error. name: " + file, e); - return ExitStatus.failure(1, "cat read file error: " + e.getMessage()); + process.end(1, "cat read file error: " + e.getMessage()); + return; } } - return ExitStatus.success(); + process.end(); + } + + private boolean verifyOptions(CommandProcess process) { + if (sizeLimit > maxSizeLimit) { + process.end(-1, "sizeLimit cannot be large than: " + maxSizeLimit); + return false; + } + + //目前不支持过滤,限制http请求执行的文件大小 + int maxSizeLimitOfNonTty = 128 * 1024; + if (!process.session().isTty() && sizeLimit > maxSizeLimitOfNonTty) { + process.end(-1, "When executing in non-tty session, sizeLimit cannot be large than: " + maxSizeLimitOfNonTty); + return false; + } + return true; } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java index ca01c4351a6..6ad72ed0814 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ClsCommand.java @@ -1,6 +1,5 @@ package com.taobao.arthas.core.command.basic1000; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Name; @@ -11,11 +10,12 @@ @Summary("Clear the screen") public class ClsCommand extends AnnotatedCommand { @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { if (!process.session().isTty()) { - return ExitStatus.failure(-1, "Command 'cls' is only support tty session."); + process.end(-1, "Command 'cls' is only support tty session."); + return; } process.write(RenderUtil.cls()).write("\n"); - return ExitStatus.success(); + process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/EchoCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/EchoCommand.java index 23ab2cf4adb..b1db3f084c7 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/EchoCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/EchoCommand.java @@ -2,7 +2,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.EchoModel; -import com.taobao.arthas.core.shell.command.ExitStatus; +import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Argument; @@ -30,12 +30,12 @@ public void setMessage(String message) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { if (message != null) { process.appendResult(new EchoModel(message)); } - return ExitStatus.success(); + process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java index cf8ecb955f7..d1db00b0ff4 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/GrepCommand.java @@ -1,7 +1,6 @@ package com.taobao.arthas.core.command.basic1000; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Argument; @@ -168,7 +167,7 @@ public int getMaxCount() { } @Override - public ExitStatus process(CommandProcess process) { - return ExitStatus.failure(-1, "The grep command only for pipes. See 'grep --help'\n"); + public void process(CommandProcess process) { + process.end(-1, "The grep command only for pipes. See 'grep --help'\n"); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HelpCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HelpCommand.java index 9546610e219..6e1d5f23ea0 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HelpCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HelpCommand.java @@ -4,7 +4,6 @@ import com.taobao.arthas.core.command.model.CommandOptionVO; import com.taobao.arthas.core.command.model.CommandVO; import com.taobao.arthas.core.command.model.HelpModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -40,7 +39,7 @@ public void setCmd(String cmd) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { List commands = allCommands(process.session()); Command targetCmd = findCommand(commands); if (targetCmd == null) { @@ -48,7 +47,7 @@ public ExitStatus process(CommandProcess process) { } else { process.appendResult(createHelpDetailModel(targetCmd)); } - return ExitStatus.success(); + process.end(); } public HelpModel createHelpDetailModel(Command targetCmd) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java index 64e8960a503..407970edcb3 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/HistoryCommand.java @@ -5,7 +5,6 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.HistoryModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; @@ -46,7 +45,7 @@ public void setNumber(int n) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { Session session = process.session(); //TODO 修改term history实现方式,统一使用HistoryManager Object termObject = session.get(Session.TTY); @@ -85,6 +84,6 @@ public ExitStatus process(CommandProcess process) { } } - return ExitStatus.success(); + process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java index c6aeb07ec5f..7bb044d6875 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/KeymapCommand.java @@ -4,7 +4,6 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.common.IOUtils; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.term.impl.Helper; @@ -18,6 +17,7 @@ import static com.taobao.text.ui.Element.label; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -34,9 +34,10 @@ public class KeymapCommand extends AnnotatedCommand { private static final Logger logger = LoggerFactory.getLogger(KeymapCommand.class); @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { if (!process.session().isTty()) { - return ExitStatus.failure(-1, "Command 'keymap' is only support tty session."); + process.end(-1, "Command 'keymap' is only support tty session."); + return; } InputStream inputrc = Helper.loadInputRcFile(); @@ -62,12 +63,11 @@ public ExitStatus process(CommandProcess process) { } process.write(RenderUtil.render(table, process.width())); - return ExitStatus.success(); - } catch (Throwable e) { + } catch (IOException e) { logger.error("read inputrc file error.", e); - return ExitStatus.failure(-1, "read inputrc file error."); } finally { IOUtils.close(inputrc); + process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java index 9b6ee28ca30..07960f71023 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java @@ -6,7 +6,7 @@ import com.taobao.arthas.core.command.model.ChangeResultVO; import com.taobao.arthas.core.command.model.OptionVO; import com.taobao.arthas.core.command.model.OptionsModel; -import com.taobao.arthas.core.shell.command.ExitStatus; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.CliToken; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -68,19 +68,25 @@ public void setOptionValue(String optionValue) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { try { + StatusModel statusModel = null; if (isShow()) { - return processShow(process); + statusModel = processShow(process); } else if (isShowName()) { - return processShowName(process); + statusModel = processShowName(process); } else { - return processChangeNameValue(process); + statusModel = processChangeNameValue(process); } + if (statusModel != null) { + process.end(statusModel.getStatusCode(), statusModel.getMessage()); + } else { + process.end(-1, "command was not processed"); + } } catch (Throwable t) { logger.error("process options command error", t); - return ExitStatus.failure(-1, "process options command error"); + process.end(-1, "process options command error"); } } @@ -104,24 +110,24 @@ public void complete(Completion completion) { } } - private ExitStatus processShow(CommandProcess process) throws IllegalAccessException { + private StatusModel processShow(CommandProcess process) throws IllegalAccessException { Collection fields = findOptionFields(new RegexMatcher(".*")); process.appendResult(new OptionsModel(convertToOptionVOs(fields))); - return ExitStatus.success(); + return StatusModel.success(); } - private ExitStatus processShowName(CommandProcess process) throws IllegalAccessException { + private StatusModel processShowName(CommandProcess process) throws IllegalAccessException { Collection fields = findOptionFields(new EqualsMatcher(optionName)); process.appendResult(new OptionsModel(convertToOptionVOs(fields))); - return ExitStatus.success(); + return StatusModel.success(); } - private ExitStatus processChangeNameValue(CommandProcess process) throws IllegalAccessException { + private StatusModel processChangeNameValue(CommandProcess process) throws IllegalAccessException { Collection fields = findOptionFields(new EqualsMatcher(optionName)); // name not exists if (fields.isEmpty()) { - return ExitStatus.failure(-1, format("options[%s] not found.", optionName)); + return StatusModel.failure(-1, format("options[%s] not found.", optionName)); } Field field = fields.iterator().next(); @@ -149,16 +155,16 @@ private ExitStatus processChangeNameValue(CommandProcess process) throws Illegal } else if (isIn(type, short.class, String.class)) { FieldUtils.writeStaticField(field, afterValue = optionValue); } else { - return ExitStatus.failure(-1, format("Options[%s] type[%s] was unsupported.", optionName, type.getSimpleName())); + return StatusModel.failure(-1, format("Options[%s] type[%s] was unsupported.", optionName, type.getSimpleName())); } } catch (Throwable t) { - return ExitStatus.failure(-1, format("Cannot cast option value[%s] to type[%s].", optionValue, type.getSimpleName())); + return StatusModel.failure(-1, format("Cannot cast option value[%s] to type[%s].", optionValue, type.getSimpleName())); } ChangeResultVO changeResultVO = new ChangeResultVO(optionAnnotation.name(), beforeValue, afterValue); process.appendResult(new OptionsModel(changeResultVO)); - return ExitStatus.success(); + return StatusModel.success(); } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java index 5dd1a16f0f7..718624c43dd 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/PwdCommand.java @@ -3,7 +3,6 @@ import java.io.File; import com.taobao.arthas.core.command.model.PwdModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Name; @@ -13,9 +12,9 @@ @Summary("Return working directory name") public class PwdCommand extends AnnotatedCommand { @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { String path = new File("").getAbsolutePath(); process.appendResult(new PwdModel(path)); - return ExitStatus.success(); + process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java index 2b454ea6ca7..834c2de6d99 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java @@ -3,7 +3,6 @@ import com.taobao.arthas.core.advisor.Enhancer; import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.ResetModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.matcher.Matcher; @@ -46,18 +45,16 @@ public void setRegEx(boolean regEx) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { Instrumentation inst = process.session().getInstrumentation(); Matcher matcher = SearchUtils.classNameMatcher(classPattern, isRegEx); try { EnhancerAffect enhancerAffect = Enhancer.reset(inst, matcher); process.appendResult(new ResetModel(enhancerAffect)); - return ExitStatus.success(); } catch (UnmodifiableClassException e) { // ignore - return ExitStatus.failure(1, "unmodifiable class exception"); - } catch (Throwable e) { - return ExitStatus.failure(-1, "process failure: "+e.toString()); + } finally { + process.end(); } } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java index 092e645db0f..e532d6c9b66 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SessionCommand.java @@ -1,7 +1,6 @@ package com.taobao.arthas.core.command.basic1000; import com.taobao.arthas.core.command.model.SessionModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; @@ -22,7 +21,7 @@ public class SessionCommand extends AnnotatedCommand { @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { SessionModel result = new SessionModel(); Session session = process.session(); result.setJavaPid(session.getPid()); @@ -43,7 +42,7 @@ public ExitStatus process(CommandProcess process) { result.setStatUrl(statUrl); process.appendResult(result); - return ExitStatus.success(); + process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java index 825f16da81a..e98067442b4 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ShutdownCommand.java @@ -6,7 +6,6 @@ import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.ResetModel; import com.taobao.arthas.core.command.model.ShutdownModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.ShellServer; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -34,9 +33,8 @@ public class ShutdownCommand extends AnnotatedCommand { private static final Logger logger = LoggerFactory.getLogger(ShutdownCommand.class); @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { shutdown(process); - return ExitStatus.success(); } public static void shutdown(CommandProcess process) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/StopCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/StopCommand.java index 30177e559ba..42a4260e85e 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/StopCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/StopCommand.java @@ -1,6 +1,5 @@ package com.taobao.arthas.core.command.basic1000; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Name; @@ -15,8 +14,7 @@ @Summary("Stop/Shutdown Arthas server and exit the console.") public class StopCommand extends AnnotatedCommand { @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { ShutdownCommand.shutdown(process); - return ExitStatus.success(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java index 3cd460a8f5d..c2191094c6c 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java @@ -1,7 +1,6 @@ package com.taobao.arthas.core.command.basic1000; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.command.model.SystemEnvModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -31,7 +30,7 @@ public void setOptionName(String envName) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { try { SystemEnvModel result = new SystemEnvModel(); if (StringUtils.isBlank(envName)) { @@ -43,9 +42,10 @@ public ExitStatus process(CommandProcess process) { result.put(envName, value); } process.appendResult(result); - return ExitStatus.success(); } catch (Throwable t) { - return ExitStatus.failure(-1, "Error during setting system env: " + t.getMessage()); + process.end(-1, "Error during setting system env: " + t.getMessage()); + } finally { + process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java index b9b1b740f14..cca75a2e896 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java @@ -2,7 +2,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.MessageModel; -import com.taobao.arthas.core.shell.command.ExitStatus; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.command.model.SystemPropertyModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -39,7 +39,7 @@ public void setOptionValue(String propertyValue) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { try { if (StringUtils.isBlank(propertyName) && StringUtils.isBlank(propertyValue)) { @@ -49,7 +49,8 @@ public ExitStatus process(CommandProcess process) { // view the specified system property String value = System.getProperty(propertyName); if (value == null) { - return ExitStatus.failure(1, "There is no property with the key " + propertyName); + process.end(1, "There is no property with the key " + propertyName); + return; } else { process.appendResult(new SystemPropertyModel(propertyName, value)); } @@ -59,9 +60,10 @@ public ExitStatus process(CommandProcess process) { process.appendResult(new MessageModel("Successfully changed the system property.")); process.appendResult(new SystemPropertyModel(propertyName, System.getProperty(propertyName))); } - return ExitStatus.success(); } catch (Throwable t) { - return ExitStatus.failure(-1, "Error during setting system property: " + t.getMessage()); + process.end(-1, "Error during setting system property: " + t.getMessage()); + } finally { + process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java index c263b27f64a..3c8868c5a97 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/TeeCommand.java @@ -2,7 +2,6 @@ import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.*; @@ -34,8 +33,8 @@ public void setRegEx(boolean append) { } @Override - public ExitStatus process(CommandProcess process) { - return ExitStatus.failure(-1, "The tee command only for pipes. See 'tee --help'"); + public void process(CommandProcess process) { + process.end(-1, "The tee command only for pipes. See 'tee --help'"); } public String getFilePath() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java index 34ad8843245..9ae903133a9 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java @@ -12,7 +12,6 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.ChangeResultVO; import com.taobao.arthas.core.command.model.MessageModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.command.model.VMOptionModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -53,11 +52,11 @@ public void setOptionValue(String value) { } @Override - public ExitStatus process(CommandProcess process) { - return run(process, name, value); + public void process(CommandProcess process) { + run(process, name, value); } - private static ExitStatus run(CommandProcess process, String name, String value) { + private static void run(CommandProcess process, String name, String value) { try { HotSpotDiagnosticMXBean hotSpotDiagnosticMXBean = ManagementFactory .getPlatformMXBean(HotSpotDiagnosticMXBean.class); @@ -69,7 +68,7 @@ private static ExitStatus run(CommandProcess process, String name, String value) // view the specified option VMOption option = hotSpotDiagnosticMXBean.getVMOption(name); if (option == null) { - return ExitStatus.failure(-1, "In order to change the system properties, you must specify the property value."); + process.end(-1, "In order to change the system properties, you must specify the property value."); } else { process.appendResult(new VMOptionModel(Arrays.asList(option))); } @@ -83,10 +82,11 @@ private static ExitStatus run(CommandProcess process, String name, String value) process.appendResult(new VMOptionModel(new ChangeResultVO(name, originValue, hotSpotDiagnosticMXBean.getVMOption(name).getValue()))); } - return ExitStatus.success(); } catch (Throwable t) { logger.error("Error during setting vm option", t); - return ExitStatus.failure(-1, "Error during setting vm option: " + t.getMessage()); + process.end(-1, "Error during setting vm option: " + t.getMessage()); + } finally { + process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VersionCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VersionCommand.java index da2ffc3a302..b46ed80b845 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VersionCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VersionCommand.java @@ -1,7 +1,6 @@ package com.taobao.arthas.core.command.basic1000; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.command.model.VersionModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; @@ -19,11 +18,11 @@ public class VersionCommand extends AnnotatedCommand { @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { VersionModel result = new VersionModel(); result.setVersion(ArthasBanner.version()); process.appendResult(result); - return ExitStatus.success(); + process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/hidden/JulyCommand.java b/core/src/main/java/com/taobao/arthas/core/command/hidden/JulyCommand.java index 59fea15bcf9..f67afbbd9bd 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/hidden/JulyCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/hidden/JulyCommand.java @@ -1,6 +1,5 @@ package com.taobao.arthas.core.command.hidden; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Hidden; @@ -15,9 +14,8 @@ @Hidden public class JulyCommand extends AnnotatedCommand { @Override - public ExitStatus process(CommandProcess process) { - process.write(new String($$())).write("\n"); - return ExitStatus.success(); + public void process(CommandProcess process) { + process.write(new String($$())).write("\n").end(); } private static byte[] $$() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/hidden/ThanksCommand.java b/core/src/main/java/com/taobao/arthas/core/command/hidden/ThanksCommand.java index 745ae86ad98..d7b4adb790d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/hidden/ThanksCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/hidden/ThanksCommand.java @@ -1,6 +1,5 @@ package com.taobao.arthas.core.command.hidden; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ArthasBanner; @@ -19,8 +18,7 @@ @Hidden public class ThanksCommand extends AnnotatedCommand { @Override - public ExitStatus process(CommandProcess process) { - process.write(ArthasBanner.credit()).write("\n"); - return ExitStatus.success(); + public void process(CommandProcess process) { + process.write(ArthasBanner.credit()).write("\n").end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java index fca642cef07..a9020d400c6 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java @@ -9,7 +9,6 @@ import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.handlers.Handler; @@ -110,23 +109,23 @@ public void setLoadClass(String className) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { // ctrl-C support process.interruptHandler(new ClassLoaderInterruptHandler(process, isInterrupted)); Instrumentation inst = process.session().getInstrumentation(); if (all) { - return processAllClasses(process, inst); + processAllClasses(process, inst); } else if (hashCode != null && resource != null) { - return processResources(process, inst); + processResources(process, inst); } else if (hashCode != null && this.loadClass != null) { - return processLoadClass(process, inst); + processLoadClass(process, inst); } else if (hashCode != null) { - return processClassLoader(process, inst); - } else if (listClassLoader || isTree) { - return processClassLoaders(process, inst); + processClassLoader(process, inst); + } else if (listClassLoader || isTree){ + processClassLoaders(process, inst); } else { - return processClassLoaderStats(process, inst); + processClassLoaderStats(process, inst); } } @@ -135,13 +134,12 @@ public ExitStatus process(CommandProcess process) { * e.g. In JVM, there are 100 GrooyClassLoader instances, which loaded 200 classes in total * @param process * @param inst - * @return */ - private ExitStatus processClassLoaderStats(CommandProcess process, Instrumentation inst) { + private void processClassLoaderStats(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); List classLoaderInfos = getAllClassLoaderInfo(inst); Map classLoaderStats = new HashMap(); - for (ClassLoaderInfo info : classLoaderInfos) { + for (ClassLoaderInfo info: classLoaderInfos) { String name = info.classLoader == null ? "BootstrapClassLoader" : info.classLoader.getClass().getName(); ClassLoaderStat stat = classLoaderStats.get(name); if (null == stat) { @@ -160,10 +158,10 @@ private ExitStatus processClassLoaderStats(CommandProcess process, Instrumentati affect.rCnt(sorted.keySet().size()); process.appendResult(new RowAffectModel(affect)); - return ExitStatus.success(); + process.end(); } - private ExitStatus processClassLoaders(CommandProcess process, Instrumentation inst) { + private void processClassLoaders(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); List classLoaderInfos = includeReflectionClassLoader ? getAllClassLoaderInfo(inst) : getAllClassLoaderInfo(inst, new SunReflectionClassLoaderFilter()); @@ -174,18 +172,18 @@ private ExitStatus processClassLoaders(CommandProcess process, Instrumentation i classLoaderVO.setLoadedCount(classLoaderInfo.loadedClassCount()); classLoaderVOs.add(classLoaderVO); } - if (isTree) { + if (isTree){ classLoaderVOs = processClassLoaderTree(classLoaderVOs); } process.appendResult(new ClassLoaderModel().setClassLoaders(classLoaderVOs).setTree(isTree)); affect.rCnt(classLoaderInfos.size()); process.appendResult(new RowAffectModel(affect)); - return ExitStatus.success(); + process.end(); } // 根据 hashCode 来打印URLClassLoader的urls - private ExitStatus processClassLoader(CommandProcess process, Instrumentation inst) { + private void processClassLoader(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); Set allClassLoader = getAllClassLoaders(inst); for (ClassLoader cl : allClassLoader) { @@ -193,7 +191,7 @@ private ExitStatus processClassLoader(CommandProcess process, Instrumentation in if (cl instanceof URLClassLoader) { List classLoaderUrls = getClassLoaderUrls(cl); affect.rCnt(classLoaderUrls.size()); - if (classLoaderUrls.isEmpty()) { + if (classLoaderUrls.isEmpty()){ process.appendResult(new MessageModel("urls is empty.")); } else { process.appendResult(new ClassLoaderModel().setUrls(classLoaderUrls)); @@ -201,16 +199,16 @@ private ExitStatus processClassLoader(CommandProcess process, Instrumentation in } } else { process.appendResult(new MessageModel("not a URLClassLoader.")); - } - break; } + break; + } } process.appendResult(new RowAffectModel(affect)); - return ExitStatus.success(); + process.end(); } // 使用ClassLoader去getResources - private ExitStatus processResources(CommandProcess process, Instrumentation inst) { + private void processResources(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); int rowCount = 0; Set allClassLoader = getAllClassLoaders(inst); @@ -233,11 +231,11 @@ private ExitStatus processResources(CommandProcess process, Instrumentation inst process.appendResult(new ClassLoaderModel().setResources(resources)); process.appendResult(new RowAffectModel(affect)); - return ExitStatus.success(); + process.end(); } // Use ClassLoader to loadClass - private ExitStatus processLoadClass(CommandProcess process, Instrumentation inst) { + private void processLoadClass(CommandProcess process, Instrumentation inst) { Set allClassLoader = getAllClassLoaders(inst); for (ClassLoader cl : allClassLoader) { if (Integer.toHexString(cl.hashCode()).equals(hashCode)) { @@ -249,33 +247,40 @@ private ExitStatus processLoadClass(CommandProcess process, Instrumentation inst } catch (Throwable e) { logger.warn("load class error, class: {}", this.loadClass, e); - return ExitStatus.failure(-1, "load class error, class:" + this.loadClass + ", error: " + e.toString()); + process.end(-1, "load class error, class:"+this.loadClass+", error: "+e.toString()); + break; } } } - return ExitStatus.success(); + process.end(); } - private ExitStatus processAllClasses(CommandProcess process, Instrumentation inst) { + private void processAllClasses(CommandProcess process, Instrumentation inst) { RowAffect affect = new RowAffect(); - ExitStatus exitStatus = getAllClasses(hashCode, inst, affect, process); - if (ExitStatus.isFailed(exitStatus)) { - return exitStatus; + getAllClasses(hashCode, inst, affect, process); + if (checkInterrupted(process)) { + return; } + process.appendResult(new RowAffectModel(affect)); + process.end(); + } + + private boolean checkInterrupted(CommandProcess process) { if (isInterrupted.get()) { - return ExitStatus.failure(1, "Interrupted by user"); + process.end(1, "Interrupted by user"); + return true; } - process.appendResult(new RowAffectModel(affect)); - return ExitStatus.success(); + return false; } /** * 获取到所有的class, 还有它们的classloader,按classloader归类好,统一输出每个classloader里有哪些class *

* 当hashCode是null,则把所有的classloader的都打印 + * */ @SuppressWarnings("rawtypes") - private ExitStatus getAllClasses(String hashCode, Instrumentation inst, RowAffect affect, CommandProcess process) { + private void getAllClasses(String hashCode, Instrumentation inst, RowAffect affect, CommandProcess process) { int hashCodeInt = -1; if (hashCode != null) { hashCodeInt = Integer.valueOf(hashCode, 16); @@ -323,16 +328,15 @@ public int compare(Class o1, Class o2) { affect.rCnt(bootstrapClassSet.size()); for (Entry> entry : classLoaderClassMap.entrySet()) { - if (isInterrupted.get()) { - return ExitStatus.failure(1, "Interrupted by user"); + if (checkInterrupted(process)) { + return; } ClassLoader classLoader = entry.getKey(); SortedSet classSet = entry.getValue(); processClassSet(process, ClassUtils.createClassLoaderVO(classLoader), classSet, pageSize); affect.rCnt(classSet.size()); } - return null; - } + } private void processClassSet(final CommandProcess process, final ClassLoaderVO classLoaderVO, Collection classes, int pageSize) { @@ -340,8 +344,8 @@ private void processClassSet(final CommandProcess process, final ClassLoaderVO c @Override public boolean handle(List classNames, int segment) { process.appendResult(new ClassLoaderModel().setClassSet(new ClassSetVO(classLoaderVO, classNames, segment))); - return !isInterrupted.get(); - } + return !checkInterrupted(process); + } }); } @@ -373,14 +377,14 @@ private static List processClassLoaderTree(List cl for (ClassLoaderVO classLoaderVO : rootClassLoaders) { buildTree(classLoaderVO, parentNotNullClassLoaders); - } + } return rootClassLoaders; } private static void buildTree(ClassLoaderVO parent, List parentNotNullClassLoaders) { for (ClassLoaderVO classLoaderVO : parentNotNullClassLoaders) { - if (parent.getName().equals(classLoaderVO.getParent())) { + if (parent.getName().equals(classLoaderVO.getParent())){ parent.addChild(classLoaderVO); buildTree(classLoaderVO, parentNotNullClassLoaders); } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java index 20a7030eb00..b1b1cb36f9b 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java @@ -7,7 +7,7 @@ import com.taobao.arthas.core.command.model.DumpClassModel; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.shell.command.ExitStatus; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -87,21 +87,29 @@ public void setLimit(int limit) { } @Override - public ExitStatus process(CommandProcess process) { - if (directory != null) { - File dir = new File(directory); - if (dir.isFile()) { - return ExitStatus.failure(-1, directory + " :is not a directory, please check it"); + public void process(CommandProcess process) { + RowAffect effect = new RowAffect(); + StatusModel statusModel = new StatusModel(-1, "unknown error"); + try { + if (directory != null) { + File dir = new File(directory); + if (dir.isFile()) { + process.end(-1, directory + " :is not a directory, please check it"); + return; + } } - } - Instrumentation inst = process.session().getInstrumentation(); - Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, code); - if (matchedClasses == null || matchedClasses.isEmpty()) { - return processNoMatch(process); - } else if (matchedClasses.size() > limit) { - return processMatches(process, matchedClasses); - } else { - return processMatch(process, inst, matchedClasses); + Instrumentation inst = process.session().getInstrumentation(); + Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, code); + if (matchedClasses == null || matchedClasses.isEmpty()) { + processNoMatch(process, statusModel); + } else if (matchedClasses.size() > limit) { + processMatches(process, matchedClasses, statusModel); + } else { + processMatch(process, effect, inst, matchedClasses, statusModel); + } + } finally { + process.appendResult(new RowAffectModel(effect)); + process.end(statusModel.getStatusCode(), statusModel.getMessage()); } } @@ -112,8 +120,7 @@ public void complete(Completion completion) { } } - private ExitStatus processMatch(CommandProcess process, Instrumentation inst, Set> matchedClasses) { - RowAffect effect = new RowAffect(); + private void processMatch(CommandProcess process, RowAffect effect, Instrumentation inst, Set> matchedClasses, StatusModel statusModel) { try { Map, File> classFiles = dump(inst, matchedClasses); List dumpedClasses = new ArrayList(classFiles.size()); @@ -123,20 +130,17 @@ private ExitStatus processMatch(CommandProcess process, Instrumentation inst, Se ClassVO classVO = ClassUtils.createSimpleClassInfo(clazz); classVO.setLocation(file.getCanonicalPath()); dumpedClasses.add(classVO); - effect.rCnt(1); } process.appendResult(new DumpClassModel().setDumpedClassFiles(dumpedClasses)); - return ExitStatus.success(); + effect.rCnt(classFiles.keySet().size()); + statusModel.setStatus(0); } catch (Throwable t) { logger.error("dump: fail to dump classes: " + matchedClasses, t); - return ExitStatus.failure(-1, "dump: fail to dump classes: " + matchedClasses); - } finally { - process.appendResult(new RowAffectModel(effect)); } } - private ExitStatus processMatches(CommandProcess process, Set> matchedClasses) { + private void processMatches(CommandProcess process, Set> matchedClasses, StatusModel statusModel) { String msg = String.format( "Found more than %d class for: %s, Please Try to specify the classloader with the -c option, or try to use --limit option.", limit, classPattern); @@ -144,11 +148,11 @@ private ExitStatus processMatches(CommandProcess process, Set> matchedC List classVOs = ClassUtils.createClassVOList(matchedClasses); process.appendResult(new DumpClassModel().setMatchedClasses(classVOs)); - return ExitStatus.failure(-1, msg); + statusModel.setStatus(-1, msg); } - private ExitStatus processNoMatch(CommandProcess process) { - return ExitStatus.failure(-1, "No class found for: " + classPattern); + private void processNoMatch(CommandProcess process, StatusModel statusModel) { + statusModel.setStatus(-1, "No class found for: " + classPattern); } private Map, File> dump(Instrumentation inst, Set> classes) throws UnmodifiableClassException { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java index 5d5b0750896..1035d10dab5 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java @@ -9,7 +9,7 @@ import com.taobao.arthas.core.command.model.GetStaticModel; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.shell.command.ExitStatus; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ClassUtils; @@ -89,69 +89,71 @@ public void setExpand(Integer expand) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { + RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); Set> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, hashCode); - if (matchedClasses == null || matchedClasses.isEmpty()) { - return ExitStatus.failure(-1, "No class found for: " + classPattern); - } else if (matchedClasses.size() > 1) { - return processMatches(process, matchedClasses); - } else { - return processExactMatch(process, inst, matchedClasses); + StatusModel statusModel = new StatusModel(-1, "unknown error"); + try { + if (matchedClasses == null || matchedClasses.isEmpty()) { + statusModel.setStatus(-1, "No class found for: " + classPattern); + } else if (matchedClasses.size() > 1) { + processMatches(process, matchedClasses, statusModel); + } else { + processExactMatch(process, affect, inst, matchedClasses, statusModel); + } + } finally { + process.appendResult(new RowAffectModel(affect)); + process.end(statusModel.getStatusCode(), statusModel.getMessage()); } } - private ExitStatus processExactMatch(CommandProcess process, Instrumentation inst, - Set> matchedClasses) { - RowAffect affect = new RowAffect(); + private void processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, + Set> matchedClasses, StatusModel statusModel) { Matcher fieldNameMatcher = fieldNameMatcher(); Class clazz = matchedClasses.iterator().next(); boolean found = false; - try { - for (Field field : clazz.getDeclaredFields()) { - if (!Modifier.isStatic(field.getModifiers()) || !fieldNameMatcher.matching(field.getName())) { - continue; - } - if (!field.isAccessible()) { - field.setAccessible(true); - } - try { - Object value = field.get(null); - - if (!StringUtils.isEmpty(express)) { - value = ExpressFactory.threadLocalExpress(value).get(express); - } - - process.appendResult(new GetStaticModel(field.getName(), value, expand)); - - affect.rCnt(1); - } catch (IllegalAccessException e) { - logger.warn("getstatic: failed to get static value, class: {}, field: {} ", clazz, field.getName(), e); - process.appendResult(new MessageModel("Failed to get static, exception message: " + e.getMessage() - + ", please check $HOME/logs/arthas/arthas.log for more details. ")); - } catch (ExpressException e) { - logger.warn("getstatic: failed to get express value, class: {}, field: {}, express: {}", clazz, field.getName(), express, e); - process.appendResult(new MessageModel("Failed to get static, exception message: " + e.getMessage() - + ", please check $HOME/logs/arthas/arthas.log for more details. ")); - } finally { - found = true; - } + for (Field field : clazz.getDeclaredFields()) { + if (!Modifier.isStatic(field.getModifiers()) || !fieldNameMatcher.matching(field.getName())) { + continue; + } + if (!field.isAccessible()) { + field.setAccessible(true); } + try { + Object value = field.get(null); - if (!found) { - return ExitStatus.failure(-1, "getstatic: no matched static field was found"); - } else { - return ExitStatus.success(); + if (!StringUtils.isEmpty(express)) { + value = ExpressFactory.threadLocalExpress(value).get(express); + } + + process.appendResult(new GetStaticModel(field.getName(), value, expand)); + + affect.rCnt(1); + } catch (IllegalAccessException e) { + logger.warn("getstatic: failed to get static value, class: {}, field: {} ", clazz, field.getName(), e); + process.appendResult(new MessageModel("Failed to get static, exception message: " + e.getMessage() + + ", please check $HOME/logs/arthas/arthas.log for more details. ")); + } catch (ExpressException e) { + logger.warn("getstatic: failed to get express value, class: {}, field: {}, express: {}", clazz, field.getName(), express, e); + process.appendResult(new MessageModel("Failed to get static, exception message: " + e.getMessage() + + ", please check $HOME/logs/arthas/arthas.log for more details. ")); + } finally { + found = true; } - } finally { - process.appendResult(new RowAffectModel(affect)); + } + + if (!found) { + statusModel.setStatus(-1, "getstatic: no matched static field was found"); + } else { + statusModel.setStatus(0, null); } } - private ExitStatus processMatches(CommandProcess process, Set> matchedClasses) { + private void processMatches(CommandProcess process, Set> matchedClasses, StatusModel statusModel) { // Element usage = new LabelElement("getstatic -c " + classPattern + " " + fieldPattern).style( // Decoration.bold.fg(Color.blue)); @@ -162,7 +164,7 @@ private ExitStatus processMatches(CommandProcess process, Set> matchedC List matchedClassVOs = ClassUtils.createClassVOList(matchedClasses); process.appendResult(new GetStaticModel(matchedClassVOs)); - return ExitStatus.failure(-1, "Found more than one class for: " + classPattern + ", Please use: "+usage); + statusModel.setStatus(-1, "Found more than one class for: " + classPattern + ", Please use: "+usage); } private Matcher fieldNameMatcher() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java index cf2ebc5f534..8b7a60a5062 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java @@ -7,7 +7,7 @@ import com.taobao.arthas.core.command.model.JadModel; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.shell.command.ExitStatus; +import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -97,32 +97,35 @@ public void setSourceOnly(boolean sourceOnly) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); Set> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, code); + StatusModel statusModel = new StatusModel(-1, "unknown error"); try { if (matchedClasses == null || matchedClasses.isEmpty()) { - return processNoMatch(process); + statusModel = processNoMatch(process); } else if (matchedClasses.size() > 1) { - return processMatches(process, matchedClasses); + statusModel = processMatches(process, matchedClasses); } else { // matchedClasses size is 1 // find inner classes. Set> withInnerClasses = SearchUtils.searchClassOnly(inst, matchedClasses.iterator().next().getName() + "$*", false, code); if(withInnerClasses.isEmpty()) { withInnerClasses = matchedClasses; } - return processExactMatch(process, affect, inst, matchedClasses, withInnerClasses); + statusModel = processExactMatch(process, affect, inst, matchedClasses, withInnerClasses); } } finally { if (!this.sourceOnly) { process.appendResult(new RowAffectModel(affect)); } + process.end(statusModel.getStatusCode(), statusModel.getMessage()); } } - private ExitStatus processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, Set> matchedClasses, Set> withInnerClasses) { + private StatusModel processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, Set> matchedClasses, Set> withInnerClasses) { + StatusModel statusModel = new StatusModel(); Class c = matchedClasses.iterator().next(); Set> allClasses = new HashSet>(withInnerClasses); allClasses.add(c); @@ -150,14 +153,15 @@ private ExitStatus processExactMatch(CommandProcess process, RowAffect affect, I process.appendResult(jadModel); affect.rCnt(classFiles.keySet().size()); - return ExitStatus.success(); + statusModel.setStatus(0); } catch (Throwable t) { logger.error("jad: fail to decompile class: " + c.getName(), t); - return ExitStatus.failure(-1, "jad: fail to decompile class: " + c.getName()); + statusModel.setStatus(-1, "jad: fail to decompile class: " + c.getName()); } + return statusModel; } - private ExitStatus processMatches(CommandProcess process, Set> matchedClasses) { + private StatusModel processMatches(CommandProcess process, Set> matchedClasses) { //Element usage = new LabelElement("jad -c " + classPattern).style(Decoration.bold.fg(Color.blue)); //process.write("\n Found more than one class for: " + classPattern + ", Please use " // + RenderUtil.render(usage, process.width())); @@ -171,11 +175,11 @@ private ExitStatus processMatches(CommandProcess process, Set> matchedC jadModel.setMatchedClasses(classVOs); process.appendResult(jadModel); - return ExitStatus.failure(-1, msg); + return new StatusModel(-1, msg); } - private ExitStatus processNoMatch(CommandProcess process) { - return ExitStatus.failure(-1, "No class found for: " + classPattern); + private StatusModel processNoMatch(CommandProcess process) { + return new StatusModel().setStatus(-1, "No class found for: " + classPattern); } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java index 834613ed0af..e0f6e68c71b 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java @@ -14,7 +14,6 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.MemoryCompilerModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -73,7 +72,8 @@ public void setDirectory(String directory) { } @Override - public ExitStatus process(final CommandProcess process) { + public void process(final CommandProcess process) { + int exitCode = -1; RowAffect affect = new RowAffect(); try { @@ -84,7 +84,9 @@ public ExitStatus process(final CommandProcess process) { } else { classloader = ClassLoaderUtils.getClassLoader(inst, hashCode); if (classloader == null) { - return ExitStatus.failure(-1, "Can not find classloader with hashCode: " + hashCode + "."); + exitCode = -1; + process.end(-1, "Can not find classloader with hashCode: " + hashCode + "."); + return; } } @@ -121,13 +123,15 @@ public ExitStatus process(final CommandProcess process) { affect.rCnt(1); } process.appendResult(new MemoryCompilerModel(files)); - return ExitStatus.success(); + exitCode = 0; } catch (Throwable e) { logger.warn("Memory compiler error", e); - return ExitStatus.failure(-1, "Memory compiler error, exception message: " + e.getMessage() + process.end(-1, "Memory compiler error, exception message: " + e.getMessage() + ", please check $HOME/logs/arthas/arthas.log for more details."); + exitCode = -1; } finally { process.appendResult(new RowAffectModel(affect)); + process.end(exitCode); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java index dba62eedaa5..33f65ad7407 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java @@ -9,7 +9,6 @@ import com.taobao.arthas.core.command.express.ExpressException; import com.taobao.arthas.core.command.express.ExpressFactory; import com.taobao.arthas.core.command.model.OgnlModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ClassLoaderUtils; @@ -61,7 +60,8 @@ public void setExpand(Integer expand) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { + int exitCode = 0; try { Instrumentation inst = process.session().getInstrumentation(); ClassLoader classLoader = null; @@ -72,7 +72,9 @@ public ExitStatus process(CommandProcess process) { } if (classLoader == null) { - return ExitStatus.failure(-1, "Can not find classloader with hashCode: " + hashCode + "."); + process.end(-1, "Can not find classloader with hashCode: " + hashCode + "."); + exitCode = -1; + return; } Express unpooledExpress = ExpressFactory.unpooledExpress(classLoader); @@ -84,13 +86,12 @@ public ExitStatus process(CommandProcess process) { process.appendResult(ognlModel); } catch (ExpressException e) { logger.warn("ognl: failed execute express: " + express, e); - return ExitStatus.failure(-1, "Failed to execute ognl, exception message: " + e.getMessage() - + ", please check $HOME/logs/arthas/arthas.log for more details. "); + process.end(-1, "Failed to execute ognl, exception message: " + e.getMessage() + + ", please check $HOME/logs/arthas/arthas.log for more details. "); + exitCode = -1; } - return ExitStatus.success(); - } catch(Throwable e){ - logger.error("process failure", e); - return ExitStatus.failure(-1, "process failure: "+e.toString()); + } finally { + process.end(exitCode); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java index 4c8b5202f32..33f320a0eb4 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java @@ -15,7 +15,6 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.RedefineModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -59,19 +58,22 @@ public void setPaths(List paths) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { RedefineModel redefineModel = new RedefineModel(); Instrumentation inst = process.session().getInstrumentation(); for (String path : paths) { File file = new File(path); if (!file.exists()) { - return ExitStatus.failure(-1, "file does not exist, path:" + path); + process.end(-1, "file does not exist, path:" + path); + return; } if (!file.isFile()) { - return ExitStatus.failure(-1, "not a normal file, path:" + path); + process.end(-1, "not a normal file, path:" + path); + return; } if (file.length() >= MAX_FILE_SIZE) { - return ExitStatus.failure(-1, "file size: " + file.length() + " >= " + MAX_FILE_SIZE + ", path: " + path); + process.end(-1, "file size: " + file.length() + " >= " + MAX_FILE_SIZE + ", path: " + path); + return; } } @@ -89,7 +91,7 @@ public ExitStatus process(CommandProcess process) { } catch (Exception e) { logger.warn("load class file failed: "+path, e); - return ExitStatus.failure(-1, "load class file failed: " +path+", error: " + e); + process.end(-1, "load class file failed: " +path+", error: " + e); } finally { if (f != null) { try { @@ -102,7 +104,8 @@ public ExitStatus process(CommandProcess process) { } if (bytesMap.size() != paths.size()) { - return ExitStatus.failure(-1, "paths may contains same class name!"); + process.end(-1, "paths may contains same class name!"); + return; } List definitions = new ArrayList(); @@ -120,15 +123,16 @@ public ExitStatus process(CommandProcess process) { try { if (definitions.isEmpty()) { - return ExitStatus.failure(-1, "These classes are not found in the JVM and may not be loaded: " + bytesMap.keySet()); + process.end(-1, "These classes are not found in the JVM and may not be loaded: " + bytesMap.keySet()); + return; } inst.redefineClasses(definitions.toArray(new ClassDefinition[0])); process.appendResult(redefineModel); } catch (Exception e) { - return ExitStatus.failure(-1, "redefine error! " + e); + process.end(-1, "redefine error! " + e); } - return ExitStatus.success(); + process.end(); } private static String readClassName(final byte[] bytes) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java index d3a3c62b50d..1953f1fb04e 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java @@ -11,7 +11,6 @@ import com.taobao.arthas.core.command.model.SearchClassModel; import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -93,7 +92,7 @@ public void setNumberOfLimit(int numberOfLimit) { } @Override - public ExitStatus process(final CommandProcess process) { + public void process(final CommandProcess process) { // TODO: null check RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); @@ -107,9 +106,10 @@ public int compare(Class c1, Class c2) { if (isDetail) { if (matchedClasses.size() > numberOfLimit) { - return ExitStatus.failure(-1, "Matching classes are too many: " + matchedClasses.size()); + process.end(-1, "Matching classes are too many: "+matchedClasses.size()); + return; } - for (Class clazz : matchedClasses) { + for (Class clazz : matchedClasses) { ClassVO classInfo = ClassUtils.createClassInfo(clazz, isDetail, isField); process.appendResult(new SearchClassModel(classInfo, isDetail, isField, expand)); } @@ -120,13 +120,14 @@ public int compare(Class c1, Class c2) { public boolean handle(List classNames, int segment) { process.appendResult(new SearchClassModel(classNames, segment)); return true; - } + } }); } + affect.rCnt(matchedClasses.size()); process.appendResult(new RowAffectModel(affect)); - return ExitStatus.success(); + process.end(); } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java index 145a6798411..d9add0132d8 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java @@ -12,7 +12,6 @@ import com.taobao.arthas.core.command.model.SearchMethodModel; import com.taobao.arthas.core.command.model.MethodVO; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -92,7 +91,7 @@ public void setNumberOfLimit(int numberOfLimit) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); @@ -100,41 +99,40 @@ public ExitStatus process(CommandProcess process) { Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode); if (matchedClasses.size() > numberOfLimit) { - return ExitStatus.failure(-1, "Matching classes are too many: "+matchedClasses.size()); + process.end(-1, "Matching classes are too many: "+matchedClasses.size()); + return; } - try { - for (Class clazz : matchedClasses) { - try { - for (Constructor constructor : clazz.getDeclaredConstructors()) { - if (!methodNameMatcher.matching("")) { - continue; - } - - MethodVO methodInfo = ClassUtils.createMethodInfo(constructor, clazz, isDetail); - process.appendResult(new SearchMethodModel(methodInfo, isDetail)); - affect.rCnt(1); + for (Class clazz : matchedClasses) { + try { + for (Constructor constructor : clazz.getDeclaredConstructors()) { + if (!methodNameMatcher.matching("")) { + continue; } - for (Method method : clazz.getDeclaredMethods()) { - if (!methodNameMatcher.matching(method.getName())) { - continue; - } - MethodVO methodInfo = ClassUtils.createMethodInfo(method, clazz, isDetail); - process.appendResult(new SearchMethodModel(methodInfo, isDetail)); - affect.rCnt(1); + MethodVO methodInfo = ClassUtils.createMethodInfo(constructor, clazz, isDetail); + process.appendResult(new SearchMethodModel(methodInfo, isDetail)); + affect.rCnt(1); + } + + for (Method method : clazz.getDeclaredMethods()) { + if (!methodNameMatcher.matching(method.getName())) { + continue; } - } catch (Error e) { - //print failed className - String msg = String.format("process class failed: %s, error: %s", clazz.getName(), e.toString()); - logger.error(msg, e); - return ExitStatus.failure(1, msg); + MethodVO methodInfo = ClassUtils.createMethodInfo(method, clazz, isDetail); + process.appendResult(new SearchMethodModel(methodInfo, isDetail)); + affect.rCnt(1); } + } catch (Error e) { + //print failed className + String msg = String.format("process class failed: %s, error: %s", clazz.getName(), e.toString()); + logger.error(msg, e); + process.end(1, msg); + return; } - - return ExitStatus.success(); - } finally { - process.appendResult(new RowAffectModel(affect)); } + + process.appendResult(new RowAffectModel(affect)); + process.end(); } private Matcher methodNameMatcher() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/logger/LoggerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/logger/LoggerCommand.java index 3e8c164670a..a2a1d45d95d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/logger/LoggerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/logger/LoggerCommand.java @@ -21,7 +21,6 @@ import com.taobao.arthas.common.IOUtils; import com.taobao.arthas.common.ReflectUtils; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ClassLoaderUtils; @@ -111,7 +110,7 @@ public void setHaveAppender(boolean includeNoAppender) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { int status = 0; try { if (this.name != null && this.level != null) { @@ -122,7 +121,6 @@ public ExitStatus process(CommandProcess process) { } finally { process.end(status); } - return ExitStatus.IGNORED_STATUS; } public void level(CommandProcess process) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java index 6c10e36172b..4b43baf7c81 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java @@ -1,6 +1,17 @@ package com.taobao.arthas.core.command.model; public class StatusModel extends ResultModel { + public static StatusModel success() { + return new StatusModel(0); + } + + public static StatusModel failure(int statusCode, String message) { + if (statusCode == 0) { + throw new IllegalArgumentException("failure status code cannot be 0"); + } + return new StatusModel(statusCode, message); + } + private int statusCode; private String message; @@ -20,10 +31,20 @@ public int getStatusCode() { return statusCode; } + public StatusModel setStatusCode(int statusCode) { + this.statusCode = statusCode; + return this; + } + public String getMessage() { return message; } + public StatusModel setMessage(String message) { + this.message = message; + return this; + } + public StatusModel setStatus(int statusCode, String message) { this.statusCode = statusCode; this.message = message; diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java index 6eafb3c0282..a6f3313976e 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/DashboardCommand.java @@ -5,7 +5,6 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.handlers.Handler; @@ -78,7 +77,7 @@ public void setInterval(long interval) { @Override - public ExitStatus process(final CommandProcess process) { + public void process(final CommandProcess process) { Session session = process.session(); timer = new Timer("Timer-for-arthas-dashboard-" + session.getSessionId(), true); @@ -111,8 +110,6 @@ public void handle(Void event) { // start the timer timer.scheduleAtFixedRate(new DashboardTimerTask(process), 0, getInterval()); - - return ExitStatus.IGNORED_STATUS; } public synchronized void stop() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java index 1d13138411c..6fb9bace28c 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/EnhancerCommand.java @@ -11,7 +11,6 @@ import com.taobao.arthas.core.advisor.AdviceWeaver; import com.taobao.arthas.core.advisor.Enhancer; import com.taobao.arthas.core.advisor.InvokeTraceable; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -78,7 +77,7 @@ AdviceListener getAdviceListenerWithId(CommandProcess process) { return getAdviceListener(process); } @Override - public ExitStatus process(final CommandProcess process) { + public void process(final CommandProcess process) { // ctrl-C support process.interruptHandler(new CommandInterruptHandler(process)); // q exit support @@ -86,8 +85,6 @@ public ExitStatus process(final CommandProcess process) { // start to enhance enhance(process); - - return ExitStatus.IGNORED_STATUS; } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/HeapDumpCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/HeapDumpCommand.java index 85dd1a5d345..d1acf4a4142 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/HeapDumpCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/HeapDumpCommand.java @@ -10,7 +10,6 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.sun.management.HotSpotDiagnosticMXBean; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Argument; @@ -48,7 +47,7 @@ public void setLive(boolean live) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { int status = 0; try { String dumpFile = file; @@ -73,7 +72,6 @@ public ExitStatus process(CommandProcess process) { process.end(status); } - return ExitStatus.IGNORED_STATUS; } private static void run(CommandProcess process, String file, boolean live) throws IOException { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/JvmCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/JvmCommand.java index 21923bc5721..7f3f295c224 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/JvmCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/JvmCommand.java @@ -1,7 +1,6 @@ package com.taobao.arthas.core.command.monitor200; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.StringUtils; @@ -43,7 +42,7 @@ public class JvmCommand extends AnnotatedCommand { private final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { RowAffect affect = new RowAffect(); TableElement table = new TableElement(2, 5).leftCellPadding(1).rightCellPadding(1); table.row(true, label("RUNTIME").style(Decoration.bold.bold())); @@ -82,8 +81,6 @@ public ExitStatus process(CommandProcess process) { process.write(RenderUtil.render(table, process.width())); process.write(affect.toString()).write("\n"); process.end(); - - return ExitStatus.IGNORED_STATUS; } private void drawFileDescriptorTable(TableElement table) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/MBeanCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/MBeanCommand.java index df453584c5d..12f7d157543 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/MBeanCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/MBeanCommand.java @@ -3,7 +3,6 @@ import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.CliToken; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -141,7 +140,7 @@ public int getNumOfExecutions() { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { if (StringUtils.isEmpty(getName())) { listMBean(process); } else if (isMetaData()) { @@ -149,8 +148,6 @@ public ExitStatus process(CommandProcess process) { } else { listAttribute(process); } - - return ExitStatus.IGNORED_STATUS; } private void listMBean(CommandProcess process) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/PerfCounterCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/PerfCounterCommand.java index 1a05621d1ab..a388a7dba2c 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/PerfCounterCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/PerfCounterCommand.java @@ -12,7 +12,6 @@ import com.taobao.arthas.common.JavaVersionUtils; import com.taobao.arthas.common.PidUtils; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.middleware.cli.annotations.Description; @@ -51,7 +50,7 @@ public void setDetails(boolean details) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { try { TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); if (this.details) { @@ -82,8 +81,6 @@ public ExitStatus process(CommandProcess process) { } finally { process.end(); } - - return ExitStatus.IGNORED_STATUS; } private static List getPerfCounters() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java index f3c12f0ef14..96c6a3bb052 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java @@ -16,7 +16,6 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.common.OSUtils; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.server.ArthasBootstrap; import com.taobao.arthas.core.shell.cli.CliToken; import com.taobao.arthas.core.shell.cli.Completion; @@ -270,14 +269,14 @@ private static String execute(AsyncProfiler asyncProfiler, String arg) } @Override - public ExitStatus process(final CommandProcess process) { + public void process(final CommandProcess process) { int status = 0; try { ProfilerAction profilerAction = ProfilerAction.valueOf(action); if (ProfilerAction.actions.equals(profilerAction)) { process.write("Supported Actions: " + actions() + "\n"); - return ExitStatus.IGNORED_STATUS; + return; } final AsyncProfiler asyncProfiler = this.profilerInstance(); @@ -286,7 +285,7 @@ public ExitStatus process(final CommandProcess process) { if (actionArg == null) { process.write("actionArg can not be empty.\n"); status = 1; - return ExitStatus.IGNORED_STATUS; + return; } String result = execute(asyncProfiler, this.actionArg); process.write(result); @@ -369,8 +368,6 @@ public void run() { } finally { process.end(status); } - - return ExitStatus.IGNORED_STATUS; } private String outputFile() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java index 9233100a881..eb8a5f44beb 100755 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/ThreadCommand.java @@ -1,7 +1,6 @@ package com.taobao.arthas.core.command.monitor200; import com.taobao.arthas.core.command.Constants; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ArrayUtils; @@ -106,7 +105,7 @@ public void setLockedSynchronizers(boolean lockedSynchronizers) { } @Override - public ExitStatus process(CommandProcess process) { + public void process(CommandProcess process) { Affect affect = new RowAffect(); int status = 0; try { @@ -123,8 +122,6 @@ public ExitStatus process(CommandProcess process) { process.write(affect + "\n"); process.end(status); } - - return ExitStatus.IGNORED_STATUS; } private int processAllThreads(CommandProcess process) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java index dbef8b23be2..707d44114a7 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java @@ -8,7 +8,6 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.express.ExpressException; import com.taobao.arthas.core.command.express.ExpressFactory; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.handlers.command.CommandInterruptHandler; import com.taobao.arthas.core.shell.handlers.shell.QExitHandler; @@ -266,7 +265,7 @@ int putTimeTunnel(TimeFragment tt) { } @Override - public ExitStatus process(final CommandProcess process) { + public void process(final CommandProcess process) { // 检查参数 checkArguments(); @@ -294,8 +293,6 @@ public ExitStatus process(final CommandProcess process) { processShow(process); } } - - return ExitStatus.IGNORED_STATUS; } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/shell/command/AnnotatedCommand.java b/core/src/main/java/com/taobao/arthas/core/shell/command/AnnotatedCommand.java index 56b535b03fd..fc88c654754 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/command/AnnotatedCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/command/AnnotatedCommand.java @@ -31,9 +31,8 @@ public CLI cli() { * Process the command, when the command is done processing it should call the {@link CommandProcess#end()} method. * * @param process the command process - * @return statusModel of command execute */ - public abstract ExitStatus process(CommandProcess process); + public abstract void process(CommandProcess process); /** * Perform command completion, when the command is done completing it should call {@link Completion#complete(List)} diff --git a/core/src/main/java/com/taobao/arthas/core/shell/command/impl/AnnotatedCommandImpl.java b/core/src/main/java/com/taobao/arthas/core/shell/command/impl/AnnotatedCommandImpl.java index 8e3f8d324ca..2310f6b3e7d 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/command/impl/AnnotatedCommandImpl.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/command/impl/AnnotatedCommandImpl.java @@ -1,6 +1,5 @@ package com.taobao.arthas.core.shell.command.impl; -import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.Command; @@ -80,18 +79,7 @@ private void process(CommandProcess process) { return; } CLIConfigurator.inject(process.commandLine(), instance); - ExitStatus status = instance.process(process); - if (status != null) { - if (ExitStatus.isIgnored(status)) { - // TODO 暂时兼容老代码,改造完毕后不能返回IGNORED_STATUS状态 - - } else if (!ExitStatus.isPending(status)) { - process.end(status.getStatusCode(), status.getMessage()); - } - } else { - //代码处理不正确,不应该返回null状态 - throw new IllegalStateException("Command exit status is null"); - } + instance.process(process); UserStatUtil.arthasUsageSuccess(name(), process.args()); } From f16e8079c852ff3d4f7b88214cbe0fbcb4120168 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Thu, 9 Jul 2020 10:48:56 +0800 Subject: [PATCH 07/18] remove unused code --- .../arthas/core/shell/command/ExitStatus.java | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/shell/command/ExitStatus.java b/core/src/main/java/com/taobao/arthas/core/shell/command/ExitStatus.java index 113c49dc067..ce2b4181012 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/command/ExitStatus.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/command/ExitStatus.java @@ -10,16 +10,6 @@ public class ExitStatus { */ public static final ExitStatus SUCCESS_STATUS = new ExitStatus(0); - /** - * 异步执行的命令返回此状态,注意避免状态码冲突 - */ - public static final ExitStatus PENDING_STATUS = new ExitStatus(0x300000); - - /** - * TODO 暂时兼容老代码使用,忽略检查此命令的status,命令改造完毕后需要移除此变量 - */ - public static final ExitStatus IGNORED_STATUS = new ExitStatus(0x100000); - /** * 命令执行成功的状态 * @return @@ -38,9 +28,6 @@ public static ExitStatus failure(int statusCode, String message) { if (statusCode == 0) { throw new IllegalArgumentException("failure status code cannot be 0"); } - if (statusCode == PENDING_STATUS.statusCode) { - throw new IllegalArgumentException("failure status cannot equals to PENDING_STATUS"); - } return new ExitStatus(statusCode, message); } @@ -53,23 +40,6 @@ public static boolean isFailed(ExitStatus exitStatus) { return exitStatus != null && exitStatus.getStatusCode() != 0; } - /** - * 判断是否为异步执行等待状态 - * @param exitStatus - * @return - */ - public static boolean isPending(ExitStatus exitStatus) { - return exitStatus != null && exitStatus.getStatusCode() == PENDING_STATUS.getStatusCode(); - } - - /** - * TODO 判断是否为IGNORE状态,兼容老代码使用,改造完毕后需要移除 - * @param exitStatus - * @return - */ - public static boolean isIgnored(ExitStatus exitStatus) { - return exitStatus != null && exitStatus.getStatusCode() == IGNORED_STATUS.getStatusCode(); - } private int statusCode; private String message; From 1ca5a9bbfab02470fe1d9f07eecf16ff1e275ec9 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Thu, 9 Jul 2020 15:59:11 +0800 Subject: [PATCH 08/18] change isInterrupted to volatile boolean --- .../command/klass100/ClassLoaderCommand.java | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java index a9020d400c6..f53fb77e837 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java @@ -64,7 +64,7 @@ public class ClassLoaderCommand extends AnnotatedCommand { private String loadClass = null; - private AtomicBoolean isInterrupted = new AtomicBoolean(false); + private volatile boolean isInterrupted = false; @Option(shortName = "t", longName = "tree", flag = true) @Description("Display ClassLoader tree") @@ -111,7 +111,7 @@ public void setLoadClass(String className) { @Override public void process(CommandProcess process) { // ctrl-C support - process.interruptHandler(new ClassLoaderInterruptHandler(process, isInterrupted)); + process.interruptHandler(new ClassLoaderInterruptHandler(this)); Instrumentation inst = process.session().getInstrumentation(); if (all) { @@ -247,8 +247,8 @@ private void processLoadClass(CommandProcess process, Instrumentation inst) { } catch (Throwable e) { logger.warn("load class error, class: {}", this.loadClass, e); - process.end(-1, "load class error, class:"+this.loadClass+", error: "+e.toString()); - break; + process.end(-1, "load class error, class: "+this.loadClass+", error: "+e.toString()); + return; } } } @@ -265,14 +265,6 @@ private void processAllClasses(CommandProcess process, Instrumentation inst) { process.end(); } - private boolean checkInterrupted(CommandProcess process) { - if (isInterrupted.get()) { - process.end(1, "Interrupted by user"); - return true; - } - return false; - } - /** * 获取到所有的class, 还有它们的classloader,按classloader归类好,统一输出每个classloader里有哪些class *

@@ -322,33 +314,45 @@ public int compare(Class o1, Class o2) { classSet.add(clazz); } - //convert to vo + // output bootstrapClassSet int pageSize = 256; - processClassSet(process, ClassUtils.createClassLoaderVO(null), bootstrapClassSet, pageSize); - affect.rCnt(bootstrapClassSet.size()); + processClassSet(process, ClassUtils.createClassLoaderVO(null), bootstrapClassSet, pageSize, affect); + // output other classSet for (Entry> entry : classLoaderClassMap.entrySet()) { if (checkInterrupted(process)) { return; } ClassLoader classLoader = entry.getKey(); SortedSet classSet = entry.getValue(); - processClassSet(process, ClassUtils.createClassLoaderVO(classLoader), classSet, pageSize); - affect.rCnt(classSet.size()); + processClassSet(process, ClassUtils.createClassLoaderVO(classLoader), classSet, pageSize, affect); } - } - - private void processClassSet(final CommandProcess process, final ClassLoaderVO classLoaderVO, Collection classes, int pageSize) { + } + private void processClassSet(final CommandProcess process, final ClassLoaderVO classLoaderVO, Collection classes, int pageSize, final RowAffect affect) { + //分批输出classNames, Ctrl+C可以中断执行 ResultUtils.processClassNames(classes, pageSize, new ResultUtils.PaginationHandler>() { @Override public boolean handle(List classNames, int segment) { process.appendResult(new ClassLoaderModel().setClassSet(new ClassSetVO(classLoaderVO, classNames, segment))); + affect.rCnt(classNames.size()); return !checkInterrupted(process); - } + } }); } + private boolean checkInterrupted(CommandProcess process) { + if (!process.isRunning()) { + return true; + } + if(isInterrupted){ + process.end(-1, "Processing has been interrupted"); + return true; + } else { + return false; + } + } + private static List getClassLoaderUrls(ClassLoader classLoader) { List urlStrs = new ArrayList(); if (classLoader instanceof URLClassLoader) { @@ -377,8 +381,7 @@ private static List processClassLoaderTree(List cl for (ClassLoaderVO classLoaderVO : rootClassLoaders) { buildTree(classLoaderVO, parentNotNullClassLoaders); - } - + } return rootClassLoaders; } @@ -595,17 +598,16 @@ public int compare(String o1, String o2) { } private class ClassLoaderInterruptHandler implements Handler { - private final CommandProcess process; - private final AtomicBoolean isInterrupted; - public ClassLoaderInterruptHandler(CommandProcess process, AtomicBoolean isInterrupted) { - this.process = process; - this.isInterrupted = isInterrupted; + private ClassLoaderCommand command; + + public ClassLoaderInterruptHandler(ClassLoaderCommand command) { + this.command = command; } @Override public void handle(Void event) { - isInterrupted.set(true); + command.isInterrupted = true; } } } From aabebed205b3a9f698f42cf0e967b0390b929e30 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Thu, 9 Jul 2020 16:06:13 +0800 Subject: [PATCH 09/18] Improve process end logic --- .../command/basic1000/OptionsCommand.java | 39 +++++++------- .../core/command/basic1000/ResetCommand.java | 2 +- .../command/basic1000/SystemEnvCommand.java | 3 +- .../basic1000/SystemPropertyCommand.java | 4 +- .../command/basic1000/VMOptionCommand.java | 4 +- .../command/klass100/DumpClassCommand.java | 31 ++++++----- .../command/klass100/GetStaticCommand.java | 34 +++++++----- .../core/command/klass100/JadCommand.java | 33 ++++++------ .../klass100/MemoryCompilerCommand.java | 9 +--- .../core/command/klass100/OgnlCommand.java | 53 ++++++++----------- .../command/klass100/RedefineCommand.java | 3 +- .../command/klass100/SearchClassCommand.java | 7 ++- .../taobao/arthas/core/util/CommandUtil.java | 24 +++++++++ 13 files changed, 132 insertions(+), 114 deletions(-) create mode 100644 core/src/main/java/com/taobao/arthas/core/util/CommandUtil.java diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java index 07960f71023..4a92d32256e 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java @@ -6,12 +6,13 @@ import com.taobao.arthas.core.command.model.ChangeResultVO; import com.taobao.arthas.core.command.model.OptionVO; import com.taobao.arthas.core.command.model.OptionsModel; -import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.CliToken; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.shell.command.ExitStatus; +import com.taobao.arthas.core.util.CommandUtil; import com.taobao.arthas.core.util.StringUtils; import com.taobao.arthas.core.util.TokenUtils; import com.taobao.arthas.core.util.matcher.EqualsMatcher; @@ -70,23 +71,19 @@ public void setOptionValue(String optionValue) { @Override public void process(CommandProcess process) { try { - StatusModel statusModel = null; + ExitStatus status = null; if (isShow()) { - statusModel = processShow(process); + status = processShow(process); } else if (isShowName()) { - statusModel = processShowName(process); + status = processShowName(process); } else { - statusModel = processChangeNameValue(process); + status = processChangeNameValue(process); } - if (statusModel != null) { - process.end(statusModel.getStatusCode(), statusModel.getMessage()); - } else { - process.end(-1, "command was not processed"); - } + CommandUtil.end(process, status); } catch (Throwable t) { - logger.error("process options command error", t); - process.end(-1, "process options command error"); + logger.error("processing error", t); + process.end(-1, "processing error"); } } @@ -110,24 +107,24 @@ public void complete(Completion completion) { } } - private StatusModel processShow(CommandProcess process) throws IllegalAccessException { + private ExitStatus processShow(CommandProcess process) throws IllegalAccessException { Collection fields = findOptionFields(new RegexMatcher(".*")); process.appendResult(new OptionsModel(convertToOptionVOs(fields))); - return StatusModel.success(); + return ExitStatus.success(); } - private StatusModel processShowName(CommandProcess process) throws IllegalAccessException { + private ExitStatus processShowName(CommandProcess process) throws IllegalAccessException { Collection fields = findOptionFields(new EqualsMatcher(optionName)); process.appendResult(new OptionsModel(convertToOptionVOs(fields))); - return StatusModel.success(); + return ExitStatus.success(); } - private StatusModel processChangeNameValue(CommandProcess process) throws IllegalAccessException { + private ExitStatus processChangeNameValue(CommandProcess process) throws IllegalAccessException { Collection fields = findOptionFields(new EqualsMatcher(optionName)); // name not exists if (fields.isEmpty()) { - return StatusModel.failure(-1, format("options[%s] not found.", optionName)); + return ExitStatus.failure(-1, format("options[%s] not found.", optionName)); } Field field = fields.iterator().next(); @@ -155,16 +152,16 @@ private StatusModel processChangeNameValue(CommandProcess process) throws Illega } else if (isIn(type, short.class, String.class)) { FieldUtils.writeStaticField(field, afterValue = optionValue); } else { - return StatusModel.failure(-1, format("Options[%s] type[%s] was unsupported.", optionName, type.getSimpleName())); + return ExitStatus.failure(-1, format("Options[%s] type[%s] was unsupported.", optionName, type.getSimpleName())); } } catch (Throwable t) { - return StatusModel.failure(-1, format("Cannot cast option value[%s] to type[%s].", optionValue, type.getSimpleName())); + return ExitStatus.failure(-1, format("Cannot cast option value[%s] to type[%s].", optionValue, type.getSimpleName())); } ChangeResultVO changeResultVO = new ChangeResultVO(optionAnnotation.name(), beforeValue, afterValue); process.appendResult(new OptionsModel(changeResultVO)); - return StatusModel.success(); + return ExitStatus.success(); } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java index 834c2de6d99..60e744adfe2 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/ResetCommand.java @@ -51,9 +51,9 @@ public void process(CommandProcess process) { try { EnhancerAffect enhancerAffect = Enhancer.reset(inst, matcher); process.appendResult(new ResetModel(enhancerAffect)); + process.end(); } catch (UnmodifiableClassException e) { // ignore - } finally { process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java index c2191094c6c..6a6dc7e8d04 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemEnvCommand.java @@ -42,10 +42,9 @@ public void process(CommandProcess process) { result.put(envName, value); } process.appendResult(result); + process.end(); } catch (Throwable t) { process.end(-1, "Error during setting system env: " + t.getMessage()); - } finally { - process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java index cca75a2e896..1d2093c5928 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/SystemPropertyCommand.java @@ -2,7 +2,6 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.MessageModel; -import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.command.model.SystemPropertyModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -60,10 +59,9 @@ public void process(CommandProcess process) { process.appendResult(new MessageModel("Successfully changed the system property.")); process.appendResult(new SystemPropertyModel(propertyName, System.getProperty(propertyName))); } + process.end(); } catch (Throwable t) { process.end(-1, "Error during setting system property: " + t.getMessage()); - } finally { - process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java index 9ae903133a9..49d5b4f2ed3 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/VMOptionCommand.java @@ -69,6 +69,7 @@ private static void run(CommandProcess process, String name, String value) { VMOption option = hotSpotDiagnosticMXBean.getVMOption(name); if (option == null) { process.end(-1, "In order to change the system properties, you must specify the property value."); + return; } else { process.appendResult(new VMOptionModel(Arrays.asList(option))); } @@ -82,11 +83,10 @@ private static void run(CommandProcess process, String name, String value) { process.appendResult(new VMOptionModel(new ChangeResultVO(name, originValue, hotSpotDiagnosticMXBean.getVMOption(name).getValue()))); } + process.end(); } catch (Throwable t) { logger.error("Error during setting vm option", t); process.end(-1, "Error during setting vm option: " + t.getMessage()); - } finally { - process.end(); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java index b1b1cb36f9b..b85fb0bd21d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java @@ -7,12 +7,13 @@ import com.taobao.arthas.core.command.model.DumpClassModel; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.util.ClassUtils; +import com.taobao.arthas.core.util.CommandUtil; import com.taobao.arthas.core.util.InstrumentationUtils; import com.taobao.arthas.core.util.SearchUtils; import com.taobao.arthas.core.util.affect.RowAffect; @@ -89,7 +90,6 @@ public void setLimit(int limit) { @Override public void process(CommandProcess process) { RowAffect effect = new RowAffect(); - StatusModel statusModel = new StatusModel(-1, "unknown error"); try { if (directory != null) { File dir = new File(directory); @@ -98,18 +98,22 @@ public void process(CommandProcess process) { return; } } + + ExitStatus status = null; Instrumentation inst = process.session().getInstrumentation(); Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, code); if (matchedClasses == null || matchedClasses.isEmpty()) { - processNoMatch(process, statusModel); + status = processNoMatch(process); } else if (matchedClasses.size() > limit) { - processMatches(process, matchedClasses, statusModel); + status = processMatches(process, matchedClasses); } else { - processMatch(process, effect, inst, matchedClasses, statusModel); + status = processMatch(process, effect, inst, matchedClasses); } - } finally { process.appendResult(new RowAffectModel(effect)); - process.end(statusModel.getStatusCode(), statusModel.getMessage()); + CommandUtil.end(process, status); + } catch (Throwable e){ + logger.error("processing error", e); + process.end(-1, "processing error"); } } @@ -120,7 +124,7 @@ public void complete(Completion completion) { } } - private void processMatch(CommandProcess process, RowAffect effect, Instrumentation inst, Set> matchedClasses, StatusModel statusModel) { + private ExitStatus processMatch(CommandProcess process, RowAffect effect, Instrumentation inst, Set> matchedClasses) { try { Map, File> classFiles = dump(inst, matchedClasses); List dumpedClasses = new ArrayList(classFiles.size()); @@ -134,13 +138,14 @@ private void processMatch(CommandProcess process, RowAffect effect, Instrumentat process.appendResult(new DumpClassModel().setDumpedClassFiles(dumpedClasses)); effect.rCnt(classFiles.keySet().size()); - statusModel.setStatus(0); + return ExitStatus.success(); } catch (Throwable t) { logger.error("dump: fail to dump classes: " + matchedClasses, t); + return ExitStatus.failure(-1, "dump: fail to dump classes: " + matchedClasses); } } - private void processMatches(CommandProcess process, Set> matchedClasses, StatusModel statusModel) { + private ExitStatus processMatches(CommandProcess process, Set> matchedClasses) { String msg = String.format( "Found more than %d class for: %s, Please Try to specify the classloader with the -c option, or try to use --limit option.", limit, classPattern); @@ -148,11 +153,11 @@ private void processMatches(CommandProcess process, Set> matchedClasses List classVOs = ClassUtils.createClassVOList(matchedClasses); process.appendResult(new DumpClassModel().setMatchedClasses(classVOs)); - statusModel.setStatus(-1, msg); + return ExitStatus.failure(-1, msg); } - private void processNoMatch(CommandProcess process, StatusModel statusModel) { - statusModel.setStatus(-1, "No class found for: " + classPattern); + private ExitStatus processNoMatch(CommandProcess process) { + return ExitStatus.failure(-1, "No class found for: " + classPattern); } private Map, File> dump(Instrumentation inst, Set> classes) throws UnmodifiableClassException { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java index 1035d10dab5..8905160f3f6 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java @@ -9,10 +9,11 @@ import com.taobao.arthas.core.command.model.GetStaticModel; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.util.ClassUtils; +import com.taobao.arthas.core.util.CommandUtil; import com.taobao.arthas.core.util.SearchUtils; import com.taobao.arthas.core.util.StringUtils; import com.taobao.arthas.core.util.affect.RowAffect; @@ -93,23 +94,28 @@ public void process(CommandProcess process) { RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); Set> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, hashCode); - StatusModel statusModel = new StatusModel(-1, "unknown error"); try { if (matchedClasses == null || matchedClasses.isEmpty()) { - statusModel.setStatus(-1, "No class found for: " + classPattern); - } else if (matchedClasses.size() > 1) { - processMatches(process, matchedClasses, statusModel); + process.end(-1, "No class found for: " + classPattern); + return; + } + ExitStatus status = null; + if (matchedClasses.size() > 1) { + status = processMatches(process, matchedClasses); } else { - processExactMatch(process, affect, inst, matchedClasses, statusModel); + status = processExactMatch(process, affect, inst, matchedClasses); } - } finally { process.appendResult(new RowAffectModel(affect)); - process.end(statusModel.getStatusCode(), statusModel.getMessage()); + CommandUtil.end(process, status); + } catch (Throwable e){ + logger.error("processing error", e); + process.appendResult(new RowAffectModel(affect)); + process.end(-1, "processing error"); } } - private void processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, - Set> matchedClasses, StatusModel statusModel) { + private ExitStatus processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, + Set> matchedClasses) { Matcher fieldNameMatcher = fieldNameMatcher(); Class clazz = matchedClasses.iterator().next(); @@ -147,13 +153,13 @@ private void processExactMatch(CommandProcess process, RowAffect affect, Instrum } if (!found) { - statusModel.setStatus(-1, "getstatic: no matched static field was found"); + return ExitStatus.failure(-1, "getstatic: no matched static field was found"); } else { - statusModel.setStatus(0, null); + return ExitStatus.success(); } } - private void processMatches(CommandProcess process, Set> matchedClasses, StatusModel statusModel) { + private ExitStatus processMatches(CommandProcess process, Set> matchedClasses) { // Element usage = new LabelElement("getstatic -c " + classPattern + " " + fieldPattern).style( // Decoration.bold.fg(Color.blue)); @@ -164,7 +170,7 @@ private void processMatches(CommandProcess process, Set> matchedClasses List matchedClassVOs = ClassUtils.createClassVOList(matchedClasses); process.appendResult(new GetStaticModel(matchedClassVOs)); - statusModel.setStatus(-1, "Found more than one class for: " + classPattern + ", Please use: "+usage); + return ExitStatus.failure(-1, "Found more than one class for: " + classPattern + ", Please use: "+usage); } private Matcher fieldNameMatcher() { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java index 8b7a60a5062..3afbd39e55e 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java @@ -7,12 +7,13 @@ import com.taobao.arthas.core.command.model.JadModel; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; -import com.taobao.arthas.core.command.model.StatusModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.util.ClassUtils; +import com.taobao.arthas.core.util.CommandUtil; import com.taobao.arthas.core.util.Decompiler; import com.taobao.arthas.core.util.InstrumentationUtils; import com.taobao.arthas.core.util.SearchUtils; @@ -102,30 +103,31 @@ public void process(CommandProcess process) { Instrumentation inst = process.session().getInstrumentation(); Set> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, code); - StatusModel statusModel = new StatusModel(-1, "unknown error"); try { + ExitStatus status = null; if (matchedClasses == null || matchedClasses.isEmpty()) { - statusModel = processNoMatch(process); + status = processNoMatch(process); } else if (matchedClasses.size() > 1) { - statusModel = processMatches(process, matchedClasses); + status = processMatches(process, matchedClasses); } else { // matchedClasses size is 1 // find inner classes. Set> withInnerClasses = SearchUtils.searchClassOnly(inst, matchedClasses.iterator().next().getName() + "$*", false, code); if(withInnerClasses.isEmpty()) { withInnerClasses = matchedClasses; } - statusModel = processExactMatch(process, affect, inst, matchedClasses, withInnerClasses); + status = processExactMatch(process, affect, inst, matchedClasses, withInnerClasses); } - } finally { if (!this.sourceOnly) { process.appendResult(new RowAffectModel(affect)); } - process.end(statusModel.getStatusCode(), statusModel.getMessage()); + CommandUtil.end(process, status); + } catch (Throwable e){ + logger.error("processing error", e); + process.end(-1, "processing error"); } } - private StatusModel processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, Set> matchedClasses, Set> withInnerClasses) { - StatusModel statusModel = new StatusModel(); + private ExitStatus processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, Set> matchedClasses, Set> withInnerClasses) { Class c = matchedClasses.iterator().next(); Set> allClasses = new HashSet>(withInnerClasses); allClasses.add(c); @@ -153,15 +155,14 @@ private StatusModel processExactMatch(CommandProcess process, RowAffect affect, process.appendResult(jadModel); affect.rCnt(classFiles.keySet().size()); - statusModel.setStatus(0); + return ExitStatus.success(); } catch (Throwable t) { logger.error("jad: fail to decompile class: " + c.getName(), t); - statusModel.setStatus(-1, "jad: fail to decompile class: " + c.getName()); + return ExitStatus.failure(-1, "jad: fail to decompile class: " + c.getName()); } - return statusModel; } - private StatusModel processMatches(CommandProcess process, Set> matchedClasses) { + private ExitStatus processMatches(CommandProcess process, Set> matchedClasses) { //Element usage = new LabelElement("jad -c " + classPattern).style(Decoration.bold.fg(Color.blue)); //process.write("\n Found more than one class for: " + classPattern + ", Please use " // + RenderUtil.render(usage, process.width())); @@ -175,11 +176,11 @@ private StatusModel processMatches(CommandProcess process, Set> matched jadModel.setMatchedClasses(classVOs); process.appendResult(jadModel); - return new StatusModel(-1, msg); + return ExitStatus.failure(-1, msg); } - private StatusModel processNoMatch(CommandProcess process) { - return new StatusModel().setStatus(-1, "No class found for: " + classPattern); + private ExitStatus processNoMatch(CommandProcess process) { + return ExitStatus.failure(-1, "No class found for: " + classPattern); } @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java index e0f6e68c71b..c252f939f36 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/MemoryCompilerCommand.java @@ -73,7 +73,6 @@ public void setDirectory(String directory) { @Override public void process(final CommandProcess process) { - int exitCode = -1; RowAffect affect = new RowAffect(); try { @@ -84,7 +83,6 @@ public void process(final CommandProcess process) { } else { classloader = ClassLoaderUtils.getClassLoader(inst, hashCode); if (classloader == null) { - exitCode = -1; process.end(-1, "Can not find classloader with hashCode: " + hashCode + "."); return; } @@ -123,15 +121,12 @@ public void process(final CommandProcess process) { affect.rCnt(1); } process.appendResult(new MemoryCompilerModel(files)); - exitCode = 0; + process.appendResult(new RowAffectModel(affect)); + process.end(); } catch (Throwable e) { logger.warn("Memory compiler error", e); process.end(-1, "Memory compiler error, exception message: " + e.getMessage() + ", please check $HOME/logs/arthas/arthas.log for more details."); - exitCode = -1; - } finally { - process.appendResult(new RowAffectModel(affect)); - process.end(exitCode); } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java index 33f65ad7407..c1cbaa14cef 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/OgnlCommand.java @@ -61,38 +61,31 @@ public void setExpand(Integer expand) { @Override public void process(CommandProcess process) { - int exitCode = 0; - try { - Instrumentation inst = process.session().getInstrumentation(); - ClassLoader classLoader = null; - if (hashCode == null) { - classLoader = ClassLoader.getSystemClassLoader(); - } else { - classLoader = ClassLoaderUtils.getClassLoader(inst, hashCode); - } + Instrumentation inst = process.session().getInstrumentation(); + ClassLoader classLoader = null; + if (hashCode == null) { + classLoader = ClassLoader.getSystemClassLoader(); + } else { + classLoader = ClassLoaderUtils.getClassLoader(inst, hashCode); + } - if (classLoader == null) { - process.end(-1, "Can not find classloader with hashCode: " + hashCode + "."); - exitCode = -1; - return; - } + if (classLoader == null) { + process.end(-1, "Can not find classloader with hashCode: " + hashCode + "."); + return; + } - Express unpooledExpress = ExpressFactory.unpooledExpress(classLoader); - try { - Object value = unpooledExpress.get(express); - OgnlModel ognlModel = new OgnlModel() - .setValue(value) - .setExpand(expand); - process.appendResult(ognlModel); - } catch (ExpressException e) { - logger.warn("ognl: failed execute express: " + express, e); - process.end(-1, "Failed to execute ognl, exception message: " + e.getMessage() - + ", please check $HOME/logs/arthas/arthas.log for more details. "); - exitCode = -1; - } - } finally { - process.end(exitCode); + Express unpooledExpress = ExpressFactory.unpooledExpress(classLoader); + try { + Object value = unpooledExpress.get(express); + OgnlModel ognlModel = new OgnlModel() + .setValue(value) + .setExpand(expand); + process.appendResult(ognlModel); + process.end(); + } catch (ExpressException e) { + logger.warn("ognl: failed execute express: " + express, e); + process.end(-1, "Failed to execute ognl, exception message: " + e.getMessage() + + ", please check $HOME/logs/arthas/arthas.log for more details. "); } } - } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java index 33f320a0eb4..accdd4488d1 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java @@ -92,6 +92,7 @@ public void process(CommandProcess process) { } catch (Exception e) { logger.warn("load class file failed: "+path, e); process.end(-1, "load class file failed: " +path+", error: " + e); + return; } finally { if (f != null) { try { @@ -128,11 +129,11 @@ public void process(CommandProcess process) { } inst.redefineClasses(definitions.toArray(new ClassDefinition[0])); process.appendResult(redefineModel); + process.end(); } catch (Exception e) { process.end(-1, "redefine error! " + e); } - process.end(); } private static String readClassName(final byte[] bytes) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java index 1953f1fb04e..42efa0b36c8 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java @@ -106,10 +106,10 @@ public int compare(Class c1, Class c2) { if (isDetail) { if (matchedClasses.size() > numberOfLimit) { - process.end(-1, "Matching classes are too many: "+matchedClasses.size()); + process.end(-1, "Matching classes are too many: " + matchedClasses.size()); return; } - for (Class clazz : matchedClasses) { + for (Class clazz : matchedClasses) { ClassVO classInfo = ClassUtils.createClassInfo(clazz, isDetail, isField); process.appendResult(new SearchClassModel(classInfo, isDetail, isField, expand)); } @@ -120,11 +120,10 @@ public int compare(Class c1, Class c2) { public boolean handle(List classNames, int segment) { process.appendResult(new SearchClassModel(classNames, segment)); return true; - } + } }); } - affect.rCnt(matchedClasses.size()); process.appendResult(new RowAffectModel(affect)); process.end(); diff --git a/core/src/main/java/com/taobao/arthas/core/util/CommandUtil.java b/core/src/main/java/com/taobao/arthas/core/util/CommandUtil.java new file mode 100644 index 00000000000..8faad307b01 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/util/CommandUtil.java @@ -0,0 +1,24 @@ +package com.taobao.arthas.core.util; + +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.shell.command.ExitStatus; + +/** + * Command Process util + */ +public class CommandUtil { + + /** + * check exit status and end command processing + * @param process CommandProcess instance + * @param status ExitStatus of command + */ + public static void end(CommandProcess process, ExitStatus status) { + if (status != null) { + process.end(status.getStatusCode(), status.getMessage()); + } else { + process.end(-1, "process error, exit status is null"); + } + } + +} From dd5e3822c5ff30a4a72c18f822ac84633d30a184 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Thu, 9 Jul 2020 16:07:06 +0800 Subject: [PATCH 10/18] register RowAffectView and remove redundant code --- .../core/command/model/StatusModel.java | 32 ------------------- .../core/command/view/ResultViewResolver.java | 2 ++ 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java index 4b43baf7c81..dcb023553a9 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/StatusModel.java @@ -1,23 +1,10 @@ package com.taobao.arthas.core.command.model; public class StatusModel extends ResultModel { - public static StatusModel success() { - return new StatusModel(0); - } - - public static StatusModel failure(int statusCode, String message) { - if (statusCode == 0) { - throw new IllegalArgumentException("failure status code cannot be 0"); - } - return new StatusModel(statusCode, message); - } private int statusCode; private String message; - public StatusModel() { - } - public StatusModel(int statusCode) { this.statusCode = statusCode; } @@ -31,30 +18,11 @@ public int getStatusCode() { return statusCode; } - public StatusModel setStatusCode(int statusCode) { - this.statusCode = statusCode; - return this; - } public String getMessage() { return message; } - public StatusModel setMessage(String message) { - this.message = message; - return this; - } - - public StatusModel setStatus(int statusCode, String message) { - this.statusCode = statusCode; - this.message = message; - return this; - } - - public StatusModel setStatus(int statusCode) { - return this.setStatus(statusCode, null); - } - @Override public String getType() { return "status"; diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/ResultViewResolver.java b/core/src/main/java/com/taobao/arthas/core/command/view/ResultViewResolver.java index 2eab88e8094..9891883c2b9 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/view/ResultViewResolver.java +++ b/core/src/main/java/com/taobao/arthas/core/command/view/ResultViewResolver.java @@ -29,6 +29,8 @@ public ResultViewResolver() { */ private void initResultViews() { try { + registerView(RowAffectView.class); + //basic1000 registerView(StatusView.class); registerView(VersionView.class); From 53ba564ad8ad7703443cd6acc3d2bfd635667c66 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Thu, 9 Jul 2020 16:47:19 +0800 Subject: [PATCH 11/18] add class generic type --- .../command/klass100/ClassLoaderCommand.java | 16 ++++++++-------- .../command/klass100/SearchClassCommand.java | 6 +++--- .../com/taobao/arthas/core/util/ResultUtils.java | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java index f53fb77e837..d6ea1ea834e 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java @@ -278,7 +278,7 @@ private void getAllClasses(String hashCode, Instrumentation inst, RowAffect affe hashCodeInt = Integer.valueOf(hashCode, 16); } - SortedSet bootstrapClassSet = new TreeSet(new Comparator() { + SortedSet> bootstrapClassSet = new TreeSet>(new Comparator() { @Override public int compare(Class o1, Class o2) { return o1.getName().compareTo(o2.getName()); @@ -286,7 +286,7 @@ public int compare(Class o1, Class o2) { }); Class[] allLoadedClasses = inst.getAllLoadedClasses(); - Map> classLoaderClassMap = new HashMap>(); + Map>> classLoaderClassMap = new HashMap>>(); for (Class clazz : allLoadedClasses) { ClassLoader classLoader = clazz.getClassLoader(); // Class loaded by BootstrapClassLoader @@ -301,11 +301,11 @@ public int compare(Class o1, Class o2) { continue; } - SortedSet classSet = classLoaderClassMap.get(classLoader); + SortedSet> classSet = classLoaderClassMap.get(classLoader); if (classSet == null) { - classSet = new TreeSet(new Comparator() { + classSet = new TreeSet>(new Comparator>() { @Override - public int compare(Class o1, Class o2) { + public int compare(Class o1, Class o2) { return o1.getName().compareTo(o2.getName()); } }); @@ -319,17 +319,17 @@ public int compare(Class o1, Class o2) { processClassSet(process, ClassUtils.createClassLoaderVO(null), bootstrapClassSet, pageSize, affect); // output other classSet - for (Entry> entry : classLoaderClassMap.entrySet()) { + for (Entry>> entry : classLoaderClassMap.entrySet()) { if (checkInterrupted(process)) { return; } ClassLoader classLoader = entry.getKey(); - SortedSet classSet = entry.getValue(); + SortedSet> classSet = entry.getValue(); processClassSet(process, ClassUtils.createClassLoaderVO(classLoader), classSet, pageSize, affect); } } - private void processClassSet(final CommandProcess process, final ClassLoaderVO classLoaderVO, Collection classes, int pageSize, final RowAffect affect) { + private void processClassSet(final CommandProcess process, final ClassLoaderVO classLoaderVO, Collection> classes, int pageSize, final RowAffect affect) { //分批输出classNames, Ctrl+C可以中断执行 ResultUtils.processClassNames(classes, pageSize, new ResultUtils.PaginationHandler>() { @Override diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java index 42efa0b36c8..53971ac295a 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java @@ -96,10 +96,10 @@ public void process(final CommandProcess process) { // TODO: null check RowAffect affect = new RowAffect(); Instrumentation inst = process.session().getInstrumentation(); - List matchedClasses = new ArrayList(SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode)); - Collections.sort(matchedClasses, new Comparator() { + List> matchedClasses = new ArrayList>(SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode)); + Collections.sort(matchedClasses, new Comparator>() { @Override - public int compare(Class c1, Class c2) { + public int compare(Class c1, Class c2) { return StringUtils.classname(c1).compareTo(StringUtils.classname(c2)); } }); diff --git a/core/src/main/java/com/taobao/arthas/core/util/ResultUtils.java b/core/src/main/java/com/taobao/arthas/core/util/ResultUtils.java index 9974990f66a..f770993636f 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/ResultUtils.java +++ b/core/src/main/java/com/taobao/arthas/core/util/ResultUtils.java @@ -16,7 +16,7 @@ public class ResultUtils { * @param pageSize * @param handler */ - public static void processClassNames(Collection classes, int pageSize, PaginationHandler> handler) { + public static void processClassNames(Collection> classes, int pageSize, PaginationHandler> handler) { List classNames = new ArrayList(pageSize); int segment = 0; for (Class aClass : classes) { From 0e2221e1a513b2b4805d9856fa93ddfbca3213f8 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Thu, 9 Jul 2020 17:04:08 +0800 Subject: [PATCH 12/18] Check the negative value of numberOfLimit --- .../taobao/arthas/core/command/klass100/SearchClassCommand.java | 2 +- .../arthas/core/command/klass100/SearchMethodCommand.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java index 53971ac295a..69ba2ec4e6a 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java @@ -105,7 +105,7 @@ public int compare(Class c1, Class c2) { }); if (isDetail) { - if (matchedClasses.size() > numberOfLimit) { + if (numberOfLimit > 0 && matchedClasses.size() > numberOfLimit) { process.end(-1, "Matching classes are too many: " + matchedClasses.size()); return; } diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java index d9add0132d8..93ecab9af0c 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java @@ -98,7 +98,7 @@ public void process(CommandProcess process) { Matcher methodNameMatcher = methodNameMatcher(); Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode); - if (matchedClasses.size() > numberOfLimit) { + if (numberOfLimit > 0 && matchedClasses.size() > numberOfLimit) { process.end(-1, "Matching classes are too many: "+matchedClasses.size()); return; } From cd0add7dd9db13dfdfa2a9e2b7707d60ffe27967 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Thu, 9 Jul 2020 17:06:06 +0800 Subject: [PATCH 13/18] remove redundant code --- .../com/taobao/arthas/core/command/klass100/JadCommand.java | 3 --- .../com/taobao/arthas/core/command/model/ClassLoaderVO.java | 6 +----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java index 3afbd39e55e..c94d7eef6af 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java @@ -163,9 +163,6 @@ private ExitStatus processExactMatch(CommandProcess process, RowAffect affect, I } private ExitStatus processMatches(CommandProcess process, Set> matchedClasses) { - //Element usage = new LabelElement("jad -c " + classPattern).style(Decoration.bold.fg(Color.blue)); - //process.write("\n Found more than one class for: " + classPattern + ", Please use " - // + RenderUtil.render(usage, process.width())); String usage = "jad -c " + classPattern; String msg = " Found more than one class for: " + classPattern + ", Please use " + usage; diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderVO.java index 7f9ebf9096c..802bfbec137 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderVO.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderVO.java @@ -19,11 +19,7 @@ public ClassLoaderVO() { public void addChild(ClassLoaderVO child){ if (this.children == null){ - synchronized (this){ - if (this.children == null) { - this.children = new ArrayList(); - } - } + this.children = new ArrayList(); } this.children.add(child); } From e28e6ef69f068b091054792d58886aeec4b9bf37 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Thu, 9 Jul 2020 21:18:49 +0800 Subject: [PATCH 14/18] Extract ClassDetailVO and DumpClassVO --- .../command/klass100/ClassLoaderCommand.java | 5 +- .../command/klass100/DumpClassCommand.java | 12 +- .../command/klass100/SearchClassCommand.java | 4 +- .../core/command/model/ClassDetailVO.java | 163 ++++++++++++++++++ .../core/command/model/ClassLoaderModel.java | 6 +- .../arthas/core/command/model/ClassVO.java | 162 ----------------- .../core/command/model/DumpClassModel.java | 10 +- .../core/command/model/DumpClassVO.java | 17 ++ .../core/command/model/SearchClassModel.java | 8 +- .../core/command/view/ClassLoaderView.java | 4 +- .../core/command/view/DumpClassView.java | 10 +- .../taobao/arthas/core/util/ClassUtils.java | 71 ++++---- .../arthas/core/util/TypeRenderUtils.java | 7 +- 13 files changed, 250 insertions(+), 229 deletions(-) create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/ClassDetailVO.java create mode 100644 core/src/main/java/com/taobao/arthas/core/command/model/DumpClassVO.java diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java index d6ea1ea834e..ce0cd1cf73e 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/ClassLoaderCommand.java @@ -3,10 +3,10 @@ import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.ClassDetailVO; import com.taobao.arthas.core.command.model.ClassLoaderModel; import com.taobao.arthas.core.command.model.ClassLoaderVO; import com.taobao.arthas.core.command.model.ClassSetVO; -import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; import com.taobao.arthas.core.shell.command.AnnotatedCommand; @@ -38,7 +38,6 @@ import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicBoolean; @Name("classloader") @Summary("Show classloader info") @@ -242,7 +241,7 @@ private void processLoadClass(CommandProcess process, Instrumentation inst) { try { Class clazz = cl.loadClass(this.loadClass); process.appendResult(new MessageModel("load class success.")); - ClassVO classInfo = ClassUtils.createClassInfo(clazz, true, false); + ClassDetailVO classInfo = ClassUtils.createClassInfo(clazz, false); process.appendResult(new ClassLoaderModel().setLoadClass(classInfo)); } catch (Throwable e) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java index b85fb0bd21d..aaec668300c 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java @@ -5,6 +5,7 @@ import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.DumpClassModel; +import com.taobao.arthas.core.command.model.DumpClassVO; import com.taobao.arthas.core.command.model.MessageModel; import com.taobao.arthas.core.command.model.RowAffectModel; import com.taobao.arthas.core.shell.cli.Completion; @@ -127,15 +128,16 @@ public void complete(Completion completion) { private ExitStatus processMatch(CommandProcess process, RowAffect effect, Instrumentation inst, Set> matchedClasses) { try { Map, File> classFiles = dump(inst, matchedClasses); - List dumpedClasses = new ArrayList(classFiles.size()); + List dumpedClasses = new ArrayList(classFiles.size()); for (Map.Entry, File> entry : classFiles.entrySet()) { Class clazz = entry.getKey(); File file = entry.getValue(); - ClassVO classVO = ClassUtils.createSimpleClassInfo(clazz); - classVO.setLocation(file.getCanonicalPath()); - dumpedClasses.add(classVO); + DumpClassVO dumpClassVO = new DumpClassVO(); + dumpClassVO.setLocation(file.getCanonicalPath()); + ClassUtils.fillSimpleClassVO(clazz, dumpClassVO); + dumpedClasses.add(dumpClassVO); } - process.appendResult(new DumpClassModel().setDumpedClassFiles(dumpedClasses)); + process.appendResult(new DumpClassModel().setDumpedClasses(dumpedClasses)); effect.rCnt(classFiles.keySet().size()); return ExitStatus.success(); diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java index 69ba2ec4e6a..a74aeb05d38 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java @@ -8,8 +8,8 @@ import java.util.List; import com.taobao.arthas.core.command.Constants; +import com.taobao.arthas.core.command.model.ClassDetailVO; import com.taobao.arthas.core.command.model.SearchClassModel; -import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.RowAffectModel; import com.taobao.arthas.core.shell.cli.Completion; import com.taobao.arthas.core.shell.cli.CompletionUtils; @@ -110,7 +110,7 @@ public int compare(Class c1, Class c2) { return; } for (Class clazz : matchedClasses) { - ClassVO classInfo = ClassUtils.createClassInfo(clazz, isDetail, isField); + ClassDetailVO classInfo = ClassUtils.createClassInfo(clazz, isField); process.appendResult(new SearchClassModel(classInfo, isDetail, isField, expand)); } } else { diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/ClassDetailVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/ClassDetailVO.java new file mode 100644 index 00000000000..a66a11ee822 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/ClassDetailVO.java @@ -0,0 +1,163 @@ +package com.taobao.arthas.core.command.model; + +/** + * Class detail VO + * @author gongdewei 2020/4/8 + */ +public class ClassDetailVO extends ClassVO { + + private String classInfo; + private String codeSource; + private boolean isInterface; + private boolean isAnnotation; + private boolean isEnum; + private boolean isAnonymousClass; + private boolean isArray; + private boolean isLocalClass; + private boolean isMemberClass; + private boolean isPrimitive; + private boolean isSynthetic; + private String simpleName; + private String modifier; + private String[] annotations; + private String[] interfaces; + private String[] superClass; + private FieldVO[] fields; + + public String getClassInfo() { + return classInfo; + } + + public void setClassInfo(String classInfo) { + this.classInfo = classInfo; + } + + public String getCodeSource() { + return codeSource; + } + + public void setCodeSource(String codeSource) { + this.codeSource = codeSource; + } + + public boolean isInterface() { + return isInterface; + } + + public void setInterface(boolean anInterface) { + isInterface = anInterface; + } + + public boolean isAnnotation() { + return isAnnotation; + } + + public void setAnnotation(boolean annotation) { + isAnnotation = annotation; + } + + public boolean isEnum() { + return isEnum; + } + + public void setEnum(boolean anEnum) { + isEnum = anEnum; + } + + public boolean isAnonymousClass() { + return isAnonymousClass; + } + + public void setAnonymousClass(boolean anonymousClass) { + isAnonymousClass = anonymousClass; + } + + public boolean isArray() { + return isArray; + } + + public void setArray(boolean array) { + isArray = array; + } + + public boolean isLocalClass() { + return isLocalClass; + } + + public void setLocalClass(boolean localClass) { + isLocalClass = localClass; + } + + public boolean isMemberClass() { + return isMemberClass; + } + + public void setMemberClass(boolean memberClass) { + isMemberClass = memberClass; + } + + public boolean isPrimitive() { + return isPrimitive; + } + + public void setPrimitive(boolean primitive) { + isPrimitive = primitive; + } + + public boolean isSynthetic() { + return isSynthetic; + } + + public void setSynthetic(boolean synthetic) { + isSynthetic = synthetic; + } + + public String getSimpleName() { + return simpleName; + } + + public void setSimpleName(String simpleName) { + this.simpleName = simpleName; + } + + public String getModifier() { + return modifier; + } + + public void setModifier(String modifier) { + this.modifier = modifier; + } + + public String[] getAnnotations() { + return annotations; + } + + public void setAnnotations(String[] annotations) { + this.annotations = annotations; + } + + public String[] getInterfaces() { + return interfaces; + } + + public void setInterfaces(String[] interfaces) { + this.interfaces = interfaces; + } + + public String[] getSuperClass() { + return superClass; + } + + public void setSuperClass(String[] superClass) { + this.superClass = superClass; + } + + public FieldVO[] getFields() { + return fields; + } + + public void setFields(FieldVO[] fields) { + this.fields = fields; + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderModel.java index 607a1b4136b..36afd347960 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/ClassLoaderModel.java @@ -12,7 +12,7 @@ public class ClassLoaderModel extends ResultModel { private ClassSetVO classSet; private List resources; - private ClassVO loadClass; + private ClassDetailVO loadClass; private List urls; //classloader -l -t private List classLoaders; @@ -46,11 +46,11 @@ public ClassLoaderModel setResources(List resources) { return this; } - public ClassVO getLoadClass() { + public ClassDetailVO getLoadClass() { return loadClass; } - public ClassLoaderModel setLoadClass(ClassVO loadClass) { + public ClassLoaderModel setLoadClass(ClassDetailVO loadClass) { this.loadClass = loadClass; return this; } diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/ClassVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/ClassVO.java index e8ef107211d..fea8a6d405f 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/ClassVO.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/ClassVO.java @@ -6,26 +6,8 @@ public class ClassVO { private String name; - private String classInfo; - private String codeSource; - private Boolean isInterface; - private Boolean isAnnotation; - private Boolean isEnum; - private Boolean isAnonymousClass; - private Boolean isArray; - private Boolean isLocalClass; - private Boolean isMemberClass; - private Boolean isPrimitive; - private Boolean isSynthetic; - private String simpleName; - private String modifier; - private String[] annotations; - private String[] interfaces; - private String[] superClass; private String[] classloader; private String classLoaderHash; - private FieldVO[] fields; - private String location; public String getName() { return name; @@ -35,134 +17,6 @@ public void setName(String name) { this.name = name; } - public String getClassInfo() { - return classInfo; - } - - public void setClassInfo(String classInfo) { - this.classInfo = classInfo; - } - - public String getCodeSource() { - return codeSource; - } - - public void setCodeSource(String codeSource) { - this.codeSource = codeSource; - } - - public Boolean getInterface() { - return isInterface; - } - - public void setInterface(Boolean anInterface) { - isInterface = anInterface; - } - - public Boolean getAnnotation() { - return isAnnotation; - } - - public void setAnnotation(Boolean annotation) { - isAnnotation = annotation; - } - - public Boolean getEnum() { - return isEnum; - } - - public void setEnum(Boolean anEnum) { - isEnum = anEnum; - } - - public Boolean getAnonymousClass() { - return isAnonymousClass; - } - - public void setAnonymousClass(Boolean anonymousClass) { - isAnonymousClass = anonymousClass; - } - - public Boolean getArray() { - return isArray; - } - - public void setArray(Boolean array) { - isArray = array; - } - - public Boolean getLocalClass() { - return isLocalClass; - } - - public void setLocalClass(Boolean localClass) { - isLocalClass = localClass; - } - - public Boolean getMemberClass() { - return isMemberClass; - } - - public void setMemberClass(Boolean memberClass) { - isMemberClass = memberClass; - } - - public Boolean getPrimitive() { - return isPrimitive; - } - - public void setPrimitive(Boolean primitive) { - isPrimitive = primitive; - } - - public Boolean getSynthetic() { - return isSynthetic; - } - - public void setSynthetic(Boolean synthetic) { - isSynthetic = synthetic; - } - - public String getSimpleName() { - return simpleName; - } - - public void setSimpleName(String simpleName) { - this.simpleName = simpleName; - } - - public String getModifier() { - return modifier; - } - - public void setModifier(String modifier) { - this.modifier = modifier; - } - - public String[] getAnnotations() { - return annotations; - } - - public void setAnnotations(String[] annotations) { - this.annotations = annotations; - } - - public String[] getInterfaces() { - return interfaces; - } - - public void setInterfaces(String[] interfaces) { - this.interfaces = interfaces; - } - - public String[] getSuperClass() { - return superClass; - } - - public void setSuperClass(String[] superClass) { - this.superClass = superClass; - } - public String[] getClassloader() { return classloader; } @@ -178,20 +32,4 @@ public String getClassLoaderHash() { public void setClassLoaderHash(String classLoaderHash) { this.classLoaderHash = classLoaderHash; } - - public FieldVO[] getFields() { - return fields; - } - - public void setFields(FieldVO[] fields) { - this.fields = fields; - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassModel.java index 4c393660958..e7b8bd684c3 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassModel.java @@ -8,7 +8,7 @@ */ public class DumpClassModel extends ResultModel { - private List dumpedClassFiles; + private List dumpedClasses; private Collection matchedClasses; @@ -20,12 +20,12 @@ public String getType() { return "dump"; } - public List getDumpedClassFiles() { - return dumpedClassFiles; + public List getDumpedClasses() { + return dumpedClasses; } - public DumpClassModel setDumpedClassFiles(List dumpedClassFiles) { - this.dumpedClassFiles = dumpedClassFiles; + public DumpClassModel setDumpedClasses(List dumpedClasses) { + this.dumpedClasses = dumpedClasses; return this; } diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassVO.java b/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassVO.java new file mode 100644 index 00000000000..9605299ab75 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/command/model/DumpClassVO.java @@ -0,0 +1,17 @@ +package com.taobao.arthas.core.command.model; + +/** + * Dumped class VO + * @author gongdewei 2020/7/9 + */ +public class DumpClassVO extends ClassVO { + private String location; + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/SearchClassModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/SearchClassModel.java index 7541ab14ab8..63b4b025f51 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/SearchClassModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/SearchClassModel.java @@ -8,7 +8,7 @@ * @author gongdewei 2020/04/08 */ public class SearchClassModel extends ResultModel { - private ClassVO classInfo; + private ClassDetailVO classInfo; private boolean withField; private boolean detail; private Integer expand; @@ -18,7 +18,7 @@ public class SearchClassModel extends ResultModel { public SearchClassModel() { } - public SearchClassModel(ClassVO classInfo, boolean detail, boolean withField, Integer expand) { + public SearchClassModel(ClassDetailVO classInfo, boolean detail, boolean withField, Integer expand) { this.classInfo = classInfo; this.detail = detail; this.withField = withField; @@ -35,11 +35,11 @@ public String getType() { return "sc"; } - public ClassVO getClassInfo() { + public ClassDetailVO getClassInfo() { return classInfo; } - public void setClassInfo(ClassVO classInfo) { + public void setClassInfo(ClassDetailVO classInfo) { this.classInfo = classInfo; } diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/ClassLoaderView.java b/core/src/main/java/com/taobao/arthas/core/command/view/ClassLoaderView.java index 1cf5caeef60..8a14a252fbc 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/view/ClassLoaderView.java +++ b/core/src/main/java/com/taobao/arthas/core/command/view/ClassLoaderView.java @@ -1,10 +1,10 @@ package com.taobao.arthas.core.command.view; import com.taobao.arthas.core.command.klass100.ClassLoaderCommand.ClassLoaderStat; +import com.taobao.arthas.core.command.model.ClassDetailVO; import com.taobao.arthas.core.command.model.ClassLoaderModel; import com.taobao.arthas.core.command.model.ClassLoaderVO; import com.taobao.arthas.core.command.model.ClassSetVO; -import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ClassUtils; import com.taobao.text.Decoration; @@ -68,7 +68,7 @@ private void drawClassLoaderUrls(CommandProcess process, List urls) { process.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING); } - private void drawLoadClass(CommandProcess process, ClassVO loadClass) { + private void drawLoadClass(CommandProcess process, ClassDetailVO loadClass) { process.write(RenderUtil.render(ClassUtils.renderClassInfo(loadClass), process.width()) + "\n"); } diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/DumpClassView.java b/core/src/main/java/com/taobao/arthas/core/command/view/DumpClassView.java index 9467261758f..273728c6747 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/view/DumpClassView.java +++ b/core/src/main/java/com/taobao/arthas/core/command/view/DumpClassView.java @@ -1,7 +1,7 @@ package com.taobao.arthas.core.command.view; -import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.DumpClassModel; +import com.taobao.arthas.core.command.model.DumpClassVO; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.util.ClassUtils; import com.taobao.arthas.core.util.TypeRenderUtils; @@ -23,8 +23,8 @@ public class DumpClassView extends ResultView { @Override public void draw(CommandProcess process, DumpClassModel result) { - if (result.getDumpedClassFiles() != null) { - drawDumpedClassFiles(process, result.getDumpedClassFiles()); + if (result.getDumpedClasses() != null) { + drawDumpedClasses(process, result.getDumpedClasses()); } else if (result.getMatchedClasses() != null) { Element table = ClassUtils.renderMatchedClasses(result.getMatchedClasses()); @@ -32,13 +32,13 @@ public void draw(CommandProcess process, DumpClassModel result) { } } - private void drawDumpedClassFiles(CommandProcess process, List classFiles) { + private void drawDumpedClasses(CommandProcess process, List classVOs) { TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); table.row(new LabelElement("HASHCODE").style(Decoration.bold.bold()), new LabelElement("CLASSLOADER").style(Decoration.bold.bold()), new LabelElement("LOCATION").style(Decoration.bold.bold())); - for (ClassVO clazz : classFiles) { + for (DumpClassVO clazz : classVOs) { table.row(label(clazz.getClassLoaderHash()).style(Decoration.bold.fg(Color.red)), TypeRenderUtils.drawClassLoader(clazz), label(clazz.getLocation()).style(Decoration.bold.fg(Color.red))); diff --git a/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java b/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java index 48dbf2a6256..b31ee56c09e 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java +++ b/core/src/main/java/com/taobao/arthas/core/util/ClassUtils.java @@ -11,6 +11,7 @@ import java.util.Set; import com.alibaba.arthas.deps.org.objectweb.asm.Type; +import com.taobao.arthas.core.command.model.ClassDetailVO; import com.taobao.arthas.core.command.model.ClassLoaderVO; import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.MethodVO; @@ -41,25 +42,25 @@ public static boolean isLambdaClass(Class clazz) { return clazz.getName().contains("$$Lambda$"); } - public static Element renderClassInfo(ClassVO clazz) { + public static Element renderClassInfo(ClassDetailVO clazz) { return renderClassInfo(clazz, false, null); } - public static Element renderClassInfo(ClassVO clazz, boolean isPrintField, Integer expand) { + public static Element renderClassInfo(ClassDetailVO clazz, boolean isPrintField, Integer expand) { TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1); table.row(label("class-info").style(Decoration.bold.bold()), label(clazz.getClassInfo())) .row(label("code-source").style(Decoration.bold.bold()), label(clazz.getCodeSource())) .row(label("name").style(Decoration.bold.bold()), label(clazz.getName())) - .row(label("isInterface").style(Decoration.bold.bold()), label("" + clazz.getInterface())) - .row(label("isAnnotation").style(Decoration.bold.bold()), label("" + clazz.getAnnotation())) - .row(label("isEnum").style(Decoration.bold.bold()), label("" + clazz.getEnum())) - .row(label("isAnonymousClass").style(Decoration.bold.bold()), label("" + clazz.getAnonymousClass())) - .row(label("isArray").style(Decoration.bold.bold()), label("" + clazz.getArray())) - .row(label("isLocalClass").style(Decoration.bold.bold()), label("" + clazz.getLocalClass())) - .row(label("isMemberClass").style(Decoration.bold.bold()), label("" + clazz.getMemberClass())) - .row(label("isPrimitive").style(Decoration.bold.bold()), label("" + clazz.getPrimitive())) - .row(label("isSynthetic").style(Decoration.bold.bold()), label("" + clazz.getSynthetic())) + .row(label("isInterface").style(Decoration.bold.bold()), label("" + clazz.isInterface())) + .row(label("isAnnotation").style(Decoration.bold.bold()), label("" + clazz.isAnnotation())) + .row(label("isEnum").style(Decoration.bold.bold()), label("" + clazz.isEnum())) + .row(label("isAnonymousClass").style(Decoration.bold.bold()), label("" + clazz.isAnonymousClass())) + .row(label("isArray").style(Decoration.bold.bold()), label("" + clazz.isArray())) + .row(label("isLocalClass").style(Decoration.bold.bold()), label("" + clazz.isLocalClass())) + .row(label("isMemberClass").style(Decoration.bold.bold()), label("" + clazz.isMemberClass())) + .row(label("isPrimitive").style(Decoration.bold.bold()), label("" + clazz.isPrimitive())) + .row(label("isSynthetic").style(Decoration.bold.bold()), label("" + clazz.isSynthetic())) .row(label("simple-name").style(Decoration.bold.bold()), label(clazz.getSimpleName())) .row(label("modifier").style(Decoration.bold.bold()), label(clazz.getModifier())) .row(label("annotation").style(Decoration.bold.bold()), label(StringUtils.join(clazz.getAnnotations(), ","))) @@ -74,30 +75,28 @@ public static Element renderClassInfo(ClassVO clazz, boolean isPrintField, Integ return table; } - public static ClassVO createClassInfo(Class clazz, boolean detail, boolean withFields) { + public static ClassDetailVO createClassInfo(Class clazz, boolean withFields) { CodeSource cs = clazz.getProtectionDomain().getCodeSource(); - ClassVO classInfo = new ClassVO(); + ClassDetailVO classInfo = new ClassDetailVO(); classInfo.setName(StringUtils.classname(clazz)); - if (detail) { - classInfo.setClassInfo(StringUtils.classname(clazz)); - classInfo.setCodeSource(ClassUtils.getCodeSource(cs)); - classInfo.setInterface(clazz.isInterface()); - classInfo.setAnnotation(clazz.isAnnotation()); - classInfo.setEnum(clazz.isEnum()); - classInfo.setAnonymousClass(clazz.isAnonymousClass()); - classInfo.setArray(clazz.isArray()); - classInfo.setLocalClass(clazz.isLocalClass()); - classInfo.setMemberClass(clazz.isMemberClass()); - classInfo.setPrimitive(clazz.isPrimitive()); - classInfo.setSynthetic(clazz.isSynthetic()); - classInfo.setSimpleName(clazz.getSimpleName()); - classInfo.setModifier(StringUtils.modifier(clazz.getModifiers(), ',')); - classInfo.setAnnotations(TypeRenderUtils.getAnnotations(clazz)); - classInfo.setInterfaces(TypeRenderUtils.getInterfaces(clazz)); - classInfo.setSuperClass(TypeRenderUtils.getSuperClass(clazz)); - classInfo.setClassloader(TypeRenderUtils.getClassloader(clazz)); - classInfo.setClassLoaderHash(StringUtils.classLoaderHash(clazz)); - } + classInfo.setClassInfo(StringUtils.classname(clazz)); + classInfo.setCodeSource(ClassUtils.getCodeSource(cs)); + classInfo.setInterface(clazz.isInterface()); + classInfo.setAnnotation(clazz.isAnnotation()); + classInfo.setEnum(clazz.isEnum()); + classInfo.setAnonymousClass(clazz.isAnonymousClass()); + classInfo.setArray(clazz.isArray()); + classInfo.setLocalClass(clazz.isLocalClass()); + classInfo.setMemberClass(clazz.isMemberClass()); + classInfo.setPrimitive(clazz.isPrimitive()); + classInfo.setSynthetic(clazz.isSynthetic()); + classInfo.setSimpleName(clazz.getSimpleName()); + classInfo.setModifier(StringUtils.modifier(clazz.getModifiers(), ',')); + classInfo.setAnnotations(TypeRenderUtils.getAnnotations(clazz)); + classInfo.setInterfaces(TypeRenderUtils.getInterfaces(clazz)); + classInfo.setSuperClass(TypeRenderUtils.getSuperClass(clazz)); + classInfo.setClassloader(TypeRenderUtils.getClassloader(clazz)); + classInfo.setClassLoaderHash(StringUtils.classLoaderHash(clazz)); if (withFields) { classInfo.setFields(TypeRenderUtils.getFields(clazz)); } @@ -106,10 +105,14 @@ public static ClassVO createClassInfo(Class clazz, boolean detail, boolean withF public static ClassVO createSimpleClassInfo(Class clazz) { ClassVO classInfo = new ClassVO(); + fillSimpleClassVO(clazz, classInfo); + return classInfo; + } + + public static void fillSimpleClassVO(Class clazz, ClassVO classInfo) { classInfo.setName(StringUtils.classname(clazz)); classInfo.setClassloader(TypeRenderUtils.getClassloader(clazz)); classInfo.setClassLoaderHash(StringUtils.classLoaderHash(clazz)); - return classInfo; } public static MethodVO createMethodInfo(Method method, Class clazz, boolean detail) { diff --git a/core/src/main/java/com/taobao/arthas/core/util/TypeRenderUtils.java b/core/src/main/java/com/taobao/arthas/core/util/TypeRenderUtils.java index 72475e5bfba..c6493dea0e5 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/TypeRenderUtils.java +++ b/core/src/main/java/com/taobao/arthas/core/util/TypeRenderUtils.java @@ -1,5 +1,6 @@ package com.taobao.arthas.core.util; +import com.taobao.arthas.core.command.model.ClassDetailVO; import com.taobao.arthas.core.command.model.ClassVO; import com.taobao.arthas.core.command.model.FieldVO; import com.taobao.arthas.core.view.ObjectView; @@ -13,8 +14,6 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedList; import java.util.List; import static com.taobao.text.ui.Element.label; @@ -56,7 +55,7 @@ public static String drawExceptions(String[] exceptionTypes) { return StringUtils.concat("\n", exceptionTypes); } - public static Element drawSuperClass(ClassVO clazz) { + public static Element drawSuperClass(ClassDetailVO clazz) { return drawTree(clazz.getSuperClass()); } @@ -76,7 +75,7 @@ public static Element drawTree(String[] nodes) { return root; } - public static Element drawField(ClassVO clazz, Integer expand) { + public static Element drawField(ClassDetailVO clazz, Integer expand) { TableElement fieldsTable = new TableElement(1).leftCellPadding(0).rightCellPadding(0); FieldVO[] fields = clazz.getFields(); if (fields == null || fields.length == 0) { From a728f096f027026fc5d013b5b3157c370ae68c7d Mon Sep 17 00:00:00 2001 From: gongdewei Date: Fri, 10 Jul 2020 10:37:26 +0800 Subject: [PATCH 15/18] add error log --- .../arthas/core/command/klass100/RedefineCommand.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java index accdd4488d1..8a7595b43c8 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/RedefineCommand.java @@ -130,8 +130,10 @@ public void process(CommandProcess process) { inst.redefineClasses(definitions.toArray(new ClassDefinition[0])); process.appendResult(redefineModel); process.end(); - } catch (Exception e) { - process.end(-1, "redefine error! " + e); + } catch (Throwable e) { + String message = "redefine error! " + e.toString(); + logger.error(message, e); + process.end(-1, message); } } From e4f8235515876e51ba4f70120dc75fe9d7a1b426 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Fri, 10 Jul 2020 17:57:49 +0800 Subject: [PATCH 16/18] expose fields: expand, withField --- .../core/command/model/SearchClassModel.java | 15 +++++++-------- .../arthas/core/command/view/SearchClassView.java | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/model/SearchClassModel.java b/core/src/main/java/com/taobao/arthas/core/command/model/SearchClassModel.java index 63b4b025f51..b4e6ee00cb6 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/model/SearchClassModel.java +++ b/core/src/main/java/com/taobao/arthas/core/command/model/SearchClassModel.java @@ -10,7 +10,7 @@ public class SearchClassModel extends ResultModel { private ClassDetailVO classInfo; private boolean withField; - private boolean detail; + private boolean detailed; private Integer expand; private List classNames; private int segment; @@ -18,9 +18,9 @@ public class SearchClassModel extends ResultModel { public SearchClassModel() { } - public SearchClassModel(ClassDetailVO classInfo, boolean detail, boolean withField, Integer expand) { + public SearchClassModel(ClassDetailVO classInfo, boolean detailed, boolean withField, Integer expand) { this.classInfo = classInfo; - this.detail = detail; + this.detailed = detailed; this.withField = withField; this.expand = expand; } @@ -59,16 +59,15 @@ public void setSegment(int segment) { this.segment = segment; } - public boolean isDetail() { - return detail; + public boolean isDetailed() { + return detailed; } - public boolean withField() { + public boolean isWithField() { return withField; } - public Integer expand() { + public Integer getExpand() { return expand; } - } diff --git a/core/src/main/java/com/taobao/arthas/core/command/view/SearchClassView.java b/core/src/main/java/com/taobao/arthas/core/command/view/SearchClassView.java index ecd22c60534..fc17576f576 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/view/SearchClassView.java +++ b/core/src/main/java/com/taobao/arthas/core/command/view/SearchClassView.java @@ -12,9 +12,9 @@ public class SearchClassView extends ResultView { @Override public void draw(CommandProcess process, SearchClassModel result) { - if (result.isDetail()) { + if (result.isDetailed()) { process.write(RenderUtil.render(ClassUtils.renderClassInfo(result.getClassInfo(), - result.withField(), result.expand()), process.width())); + result.isWithField(), result.getExpand()), process.width())); process.write("\n"); } else if (result.getClassNames() != null) { for (String className : result.getClassNames()) { From 71cee74c5d20351b9586078d7c1358cee2834e47 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Fri, 10 Jul 2020 17:58:20 +0800 Subject: [PATCH 17/18] rename to CommandUtils --- .../taobao/arthas/core/command/basic1000/OptionsCommand.java | 4 ++-- .../taobao/arthas/core/command/klass100/DumpClassCommand.java | 4 ++-- .../taobao/arthas/core/command/klass100/GetStaticCommand.java | 4 ++-- .../com/taobao/arthas/core/command/klass100/JadCommand.java | 4 ++-- .../arthas/core/util/{CommandUtil.java => CommandUtils.java} | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) rename core/src/main/java/com/taobao/arthas/core/util/{CommandUtil.java => CommandUtils.java} (95%) diff --git a/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java b/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java index 4a92d32256e..14a0a6174ad 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/basic1000/OptionsCommand.java @@ -12,7 +12,7 @@ import com.taobao.arthas.core.shell.command.AnnotatedCommand; import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.command.ExitStatus; -import com.taobao.arthas.core.util.CommandUtil; +import com.taobao.arthas.core.util.CommandUtils; import com.taobao.arthas.core.util.StringUtils; import com.taobao.arthas.core.util.TokenUtils; import com.taobao.arthas.core.util.matcher.EqualsMatcher; @@ -80,7 +80,7 @@ public void process(CommandProcess process) { status = processChangeNameValue(process); } - CommandUtil.end(process, status); + CommandUtils.end(process, status); } catch (Throwable t) { logger.error("processing error", t); process.end(-1, "processing error"); diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java index aaec668300c..2e9f2931d5f 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/DumpClassCommand.java @@ -14,7 +14,7 @@ import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.util.ClassUtils; -import com.taobao.arthas.core.util.CommandUtil; +import com.taobao.arthas.core.util.CommandUtils; import com.taobao.arthas.core.util.InstrumentationUtils; import com.taobao.arthas.core.util.SearchUtils; import com.taobao.arthas.core.util.affect.RowAffect; @@ -111,7 +111,7 @@ public void process(CommandProcess process) { status = processMatch(process, effect, inst, matchedClasses); } process.appendResult(new RowAffectModel(effect)); - CommandUtil.end(process, status); + CommandUtils.end(process, status); } catch (Throwable e){ logger.error("processing error", e); process.end(-1, "processing error"); diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java index 8905160f3f6..e008fd468d6 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/GetStaticCommand.java @@ -13,7 +13,7 @@ import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.util.ClassUtils; -import com.taobao.arthas.core.util.CommandUtil; +import com.taobao.arthas.core.util.CommandUtils; import com.taobao.arthas.core.util.SearchUtils; import com.taobao.arthas.core.util.StringUtils; import com.taobao.arthas.core.util.affect.RowAffect; @@ -106,7 +106,7 @@ public void process(CommandProcess process) { status = processExactMatch(process, affect, inst, matchedClasses); } process.appendResult(new RowAffectModel(affect)); - CommandUtil.end(process, status); + CommandUtils.end(process, status); } catch (Throwable e){ logger.error("processing error", e); process.appendResult(new RowAffectModel(affect)); diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java index c94d7eef6af..cbb6ef9554f 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/JadCommand.java @@ -13,7 +13,7 @@ import com.taobao.arthas.core.shell.command.CommandProcess; import com.taobao.arthas.core.shell.command.ExitStatus; import com.taobao.arthas.core.util.ClassUtils; -import com.taobao.arthas.core.util.CommandUtil; +import com.taobao.arthas.core.util.CommandUtils; import com.taobao.arthas.core.util.Decompiler; import com.taobao.arthas.core.util.InstrumentationUtils; import com.taobao.arthas.core.util.SearchUtils; @@ -120,7 +120,7 @@ public void process(CommandProcess process) { if (!this.sourceOnly) { process.appendResult(new RowAffectModel(affect)); } - CommandUtil.end(process, status); + CommandUtils.end(process, status); } catch (Throwable e){ logger.error("processing error", e); process.end(-1, "processing error"); diff --git a/core/src/main/java/com/taobao/arthas/core/util/CommandUtil.java b/core/src/main/java/com/taobao/arthas/core/util/CommandUtils.java similarity index 95% rename from core/src/main/java/com/taobao/arthas/core/util/CommandUtil.java rename to core/src/main/java/com/taobao/arthas/core/util/CommandUtils.java index 8faad307b01..21c0c936d70 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/CommandUtil.java +++ b/core/src/main/java/com/taobao/arthas/core/util/CommandUtils.java @@ -6,7 +6,7 @@ /** * Command Process util */ -public class CommandUtil { +public class CommandUtils { /** * check exit status and end command processing From 76e3b4349f0824ae1a1380875270e6b35a23219c Mon Sep 17 00:00:00 2001 From: gongdewei Date: Fri, 10 Jul 2020 19:30:57 +0800 Subject: [PATCH 18/18] Improved error message for the number of matching classes --- .../arthas/core/command/klass100/SearchClassCommand.java | 3 ++- .../arthas/core/command/klass100/SearchMethodCommand.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java index a74aeb05d38..daacfbb9a6a 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchClassCommand.java @@ -106,7 +106,8 @@ public int compare(Class c1, Class c2) { if (isDetail) { if (numberOfLimit > 0 && matchedClasses.size() > numberOfLimit) { - process.end(-1, "Matching classes are too many: " + matchedClasses.size()); + process.end(-1, "The number of matching classes is greater than : " + numberOfLimit+". \n" + + "Please specify a more accurate 'class-patten' or use the parameter '-n' to change the maximum number of matching classes."); return; } for (Class clazz : matchedClasses) { diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java index 93ecab9af0c..2986e8c560d 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java @@ -99,7 +99,8 @@ public void process(CommandProcess process) { Set> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode); if (numberOfLimit > 0 && matchedClasses.size() > numberOfLimit) { - process.end(-1, "Matching classes are too many: "+matchedClasses.size()); + process.end(-1, "The number of matching classes is greater than : " + numberOfLimit+". \n" + + "Please specify a more accurate 'class-patten' or use the parameter '-n' to change the maximum number of matching classes."); return; } for (Class clazz : matchedClasses) {