Transform commands of pkg klass100 (#1285)

pull/920/merge
gongdewei 5 years ago committed by GitHub
parent afc5183321
commit 4a48a7b073
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,12 +6,13 @@ import com.taobao.arthas.core.command.Constants;
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.CommandUtils;
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 class OptionsCommand extends AnnotatedCommand {
@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");
}
CommandUtils.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 class OptionsCommand extends AnnotatedCommand {
}
}
private StatusModel processShow(CommandProcess process) throws IllegalAccessException {
private ExitStatus processShow(CommandProcess process) throws IllegalAccessException {
Collection<Field> 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<Field> fields = findOptionFields(new EqualsMatcher<String>(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<Field> fields = findOptionFields(new EqualsMatcher<String>(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 @@ public class OptionsCommand extends AnnotatedCommand {
} 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();
}

@ -51,9 +51,9 @@ public class ResetCommand extends AnnotatedCommand {
try {
EnhancerAffect enhancerAffect = Enhancer.reset(inst, matcher);
process.appendResult(new ResetModel(enhancerAffect));
process.end();
} catch (UnmodifiableClassException e) {
// ignore
} finally {
process.end();
}
}

@ -42,10 +42,9 @@ public class SystemEnvCommand extends AnnotatedCommand {
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();
}
}

@ -2,7 +2,6 @@ package com.taobao.arthas.core.command.basic1000;
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 class SystemPropertyCommand extends AnnotatedCommand {
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();
}
}

@ -69,6 +69,7 @@ public class VMOptionCommand extends AnnotatedCommand {
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 @@ public class VMOptionCommand extends AnnotatedCommand {
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();
}
}

@ -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.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.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;
@ -49,6 +52,8 @@ import java.util.TreeSet;
" 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 +63,8 @@ public class ClassLoaderCommand extends AnnotatedCommand {
private String loadClass = null;
private volatile boolean isInterrupted = false;
@Option(shortName = "t", longName = "tree", flag = true)
@Description("Display ClassLoader tree")
public void setTree(boolean tree) {
@ -102,6 +109,9 @@ public class ClassLoaderCommand extends AnnotatedCommand {
@Override
public void process(CommandProcess process) {
// ctrl-C support
process.interruptHandler(new ClassLoaderInterruptHandler(this));
Instrumentation inst = process.session().getInstrumentation();
if (all) {
processAllClasses(process, inst);
@ -143,12 +153,10 @@ public class ClassLoaderCommand extends AnnotatedCommand {
TreeMap<String, ClassLoaderStat> sorted =
new TreeMap<String, ClassLoaderStat>(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 +164,45 @@ public class ClassLoaderCommand extends AnnotatedCommand {
RowAffect affect = new RowAffect();
List<ClassLoaderInfo> 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<ClassLoaderVO> classLoaderVOs = new ArrayList<ClassLoaderVO>(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<ClassLoader> 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<String> 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 +211,25 @@ public class ClassLoaderCommand extends AnnotatedCommand {
RowAffect affect = new RowAffect();
int rowCount = 0;
Set<ClassLoader> allClassLoader = getAllClassLoaders(inst);
List<String> resources = new ArrayList<String>();
for (ClassLoader cl : allClassLoader) {
if (Integer.toHexString(cl.hashCode()).equals(hashCode)) {
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
try {
Enumeration<URL> 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,23 +240,27 @@ public class ClassLoaderCommand extends AnnotatedCommand {
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."));
ClassDetailVO classInfo = ClassUtils.createClassInfo(clazz, 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());
return;
}
}
}
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();
}
@ -239,17 +269,15 @@ public class ClassLoaderCommand extends AnnotatedCommand {
* <p>
* hashCodenullclassloader
*
* @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);
}
SortedSet<Class> bootstrapClassSet = new TreeSet<Class>(new Comparator<Class>() {
SortedSet<Class<?>> bootstrapClassSet = new TreeSet<Class<?>>(new Comparator<Class>() {
@Override
public int compare(Class o1, Class o2) {
return o1.getName().compareTo(o2.getName());
@ -257,7 +285,7 @@ public class ClassLoaderCommand extends AnnotatedCommand {
});
Class[] allLoadedClasses = inst.getAllLoadedClasses();
Map<ClassLoader, SortedSet<Class>> classLoaderClassMap = new HashMap<ClassLoader, SortedSet<Class>>();
Map<ClassLoader, SortedSet<Class<?>>> classLoaderClassMap = new HashMap<ClassLoader, SortedSet<Class<?>>>();
for (Class clazz : allLoadedClasses) {
ClassLoader classLoader = clazz.getClassLoader();
// Class loaded by BootstrapClassLoader
@ -272,11 +300,11 @@ public class ClassLoaderCommand extends AnnotatedCommand {
continue;
}
SortedSet<Class> classSet = classLoaderClassMap.get(classLoader);
SortedSet<Class<?>> classSet = classLoaderClassMap.get(classLoader);
if (classSet == null) {
classSet = new TreeSet<Class>(new Comparator<Class>() {
classSet = new TreeSet<Class<?>>(new Comparator<Class<?>>() {
@Override
public int compare(Class o1, Class o2) {
public int compare(Class<?> o1, Class<?> o2) {
return o1.getName().compareTo(o2.getName());
}
});
@ -285,99 +313,82 @@ public class ClassLoaderCommand extends AnnotatedCommand {
classSet.add(clazz);
}
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
// output bootstrapClassSet
int pageSize = 256;
processClassSet(process, ClassUtils.createClassLoaderVO(null), bootstrapClassSet, pageSize, affect);
if (!bootstrapClassSet.isEmpty()) {
table.row(new LabelElement("hash:null, BootstrapClassLoader").style(Decoration.bold.bold()));
for (Class clazz : bootstrapClassSet) {
table.row(new LabelElement(clazz.getName()));
// output other classSet
for (Entry<ClassLoader, SortedSet<Class<?>>> entry : classLoaderClassMap.entrySet()) {
if (checkInterrupted(process)) {
return;
}
table.row(new LabelElement(" "));
}
for (Entry<ClassLoader, SortedSet<Class>> entry : classLoaderClassMap.entrySet()) {
ClassLoader classLoader = entry.getKey();
SortedSet<Class> classSet = entry.getValue();
SortedSet<Class<?>> classSet = entry.getValue();
processClassSet(process, ClassUtils.createClassLoaderVO(classLoader), classSet, pageSize, affect);
}
}
table.row(new LabelElement("hash:" + classLoader.hashCode() + ", " + classLoader.toString())
.style(Decoration.bold.bold()));
for (Class clazz : classSet) {
table.row(new LabelElement(clazz.getName()));
private void processClassSet(final CommandProcess process, final ClassLoaderVO classLoaderVO, Collection<Class<?>> classes, int pageSize, final RowAffect affect) {
//分批输出classNames, Ctrl+C可以中断执行
ResultUtils.processClassNames(classes, pageSize, new ResultUtils.PaginationHandler<List<String>>() {
@Override
public boolean handle(List<String> classNames, int segment) {
process.appendResult(new ClassLoaderModel().setClassSet(new ClassSetVO(classLoaderVO, classNames, segment)));
affect.rCnt(classNames.size());
return !checkInterrupted(process);
}
});
}
table.row(new LabelElement(" "));
private boolean checkInterrupted(CommandProcess process) {
if (!process.isRunning()) {
return true;
}
if(isInterrupted){
process.end(-1, "Processing has been interrupted");
return true;
} else {
return false;
}
return table;
}
private static Element renderClassLoaderUrls(ClassLoader classLoader) {
StringBuilder sb = new StringBuilder();
private static List<String> getClassLoaderUrls(ClassLoader classLoader) {
List<String> urlStrs = new ArrayList<String>();
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<ClassLoaderInfo> classLoaderInfos) {
TreeElement root = new TreeElement();
List<ClassLoaderInfo> parentNullClassLoaders = new ArrayList<ClassLoaderInfo>();
List<ClassLoaderInfo> parentNotNullClassLoaders = new ArrayList<ClassLoaderInfo>();
for (ClassLoaderInfo info : classLoaderInfos) {
if (info.parent() == null) {
parentNullClassLoaders.add(info);
private static List<ClassLoaderVO> processClassLoaderTree(List<ClassLoaderVO> classLoaders) {
List<ClassLoaderVO> rootClassLoaders = new ArrayList<ClassLoaderVO>();
List<ClassLoaderVO> parentNotNullClassLoaders = new ArrayList<ClassLoaderVO>();
for (ClassLoaderVO classLoaderVO : classLoaders) {
if (classLoaderVO.getParent() == null) {
rootClassLoaders.add(classLoaderVO);
} else {
parentNotNullClassLoaders.add(info);
}
}
for (ClassLoaderInfo info : parentNullClassLoaders) {
if (info.parent() == null) {
TreeElement parent = new TreeElement(info.getName());
renderParent(parent, info, parentNotNullClassLoaders);
root.addChild(parent);
parentNotNullClassLoaders.add(classLoaderVO);
}
}
return root;
}
// 统计所有的ClassLoader的信息
private static TableElement renderTable(List<ClassLoaderInfo> 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;
}
private static TableElement renderStat(Map<String, ClassLoaderStat> classLoaderStats) {
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
table.add(new RowElement().style(Decoration.bold.bold()).add("name", "numberOfInstances", "loadedCountTotal"));
for (Map.Entry<String, ClassLoaderStat> entry : classLoaderStats.entrySet()) {
table.row(entry.getKey(), "" + entry.getValue().getNumberOfInstance(), "" + entry.getValue().getLoadedCount());
for (ClassLoaderVO classLoaderVO : rootClassLoaders) {
buildTree(classLoaderVO, parentNotNullClassLoaders);
}
return table;
return rootClassLoaders;
}
private static void renderParent(TreeElement node, ClassLoaderInfo parent, List<ClassLoaderInfo> 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<ClassLoaderVO> parentNotNullClassLoaders) {
for (ClassLoaderVO classLoaderVO : parentNotNullClassLoaders) {
if (parent.getName().equals(classLoaderVO.getParent())){
parent.addChild(classLoaderVO);
buildTree(classLoaderVO, parentNotNullClassLoaders);
}
}
}
@ -532,15 +543,16 @@ public class ClassLoaderCommand extends AnnotatedCommand {
}
private static class SunReflectionClassLoaderFilter implements Filter {
private static final String REFLECTION_CLASSLOADER = "sun.reflect.DelegatingClassLoader";
private static final List<String> 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 +564,11 @@ public class ClassLoaderCommand extends AnnotatedCommand {
this.numberOfInstance += count;
}
int getLoadedCount() {
public int getLoadedCount() {
return loadedCount;
}
int getNumberOfInstance() {
public int getNumberOfInstance() {
return numberOfInstance;
}
}
@ -583,4 +595,18 @@ public class ClassLoaderCommand extends AnnotatedCommand {
return unsortedStats.get(o2).getLoadedCount() - unsortedStats.get(o1).getLoadedCount();
}
}
private class ClassLoaderInterruptHandler implements Handler<Void> {
private ClassLoaderCommand command;
public ClassLoaderInterruptHandler(ClassLoaderCommand command) {
this.command = command;
}
@Override
public void handle(Void event) {
command.isInterrupted = true;
}
}
}

@ -3,14 +3,20 @@ 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.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;
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.CommandUtils;
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 +24,15 @@ 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.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 +91,30 @@ public class DumpClassCommand extends AnnotatedCommand {
@Override
public void process(CommandProcess process) {
RowAffect effect = new RowAffect();
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;
}
}
ExitStatus status = null;
Instrumentation inst = process.session().getInstrumentation();
Set<Class<?>> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, code);
if (matchedClasses == null || matchedClasses.isEmpty()) {
processNoMatch(process);
status = processNoMatch(process);
} else if (matchedClasses.size() > limit) {
processMatches(process, matchedClasses);
status = processMatches(process, matchedClasses);
} else {
processMatch(process, effect, inst, matchedClasses);
status = processMatch(process, effect, inst, matchedClasses);
}
} finally {
process.write(effect + "\n");
process.end();
process.appendResult(new RowAffectModel(effect));
CommandUtils.end(process, status);
} catch (Throwable e){
logger.error("processing error", e);
process.end(-1, "processing error");
}
}
@ -121,50 +125,41 @@ public class DumpClassCommand extends AnnotatedCommand {
}
}
private void processMatch(CommandProcess process, RowAffect effect, Instrumentation inst, Set<Class<?>> matchedClasses) {
private ExitStatus processMatch(CommandProcess process, RowAffect effect, Instrumentation inst, Set<Class<?>> matchedClasses) {
try {
Map<Class<?>, 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<DumpClassVO> dumpedClasses = new ArrayList<DumpClassVO>(classFiles.size());
for (Map.Entry<Class<?>, 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)));
DumpClassVO dumpClassVO = new DumpClassVO();
dumpClassVO.setLocation(file.getCanonicalPath());
ClassUtils.fillSimpleClassVO(clazz, dumpClassVO);
dumpedClasses.add(dumpClassVO);
}
process.appendResult(new DumpClassModel().setDumpedClasses(dumpedClasses));
process.write(RenderUtil.render(table, process.width()))
.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING);
effect.rCnt(classFiles.keySet().size());
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<Class<?>> 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 ExitStatus processMatches(CommandProcess process, Set<Class<?>> 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);
process.appendResult(new MessageModel(msg));
process.write(RenderUtil.render(table, process.width()) + "\n");
List<ClassVO> classVOs = ClassUtils.createClassVOList(matchedClasses);
process.appendResult(new DumpClassModel().setMatchedClasses(classVOs));
return ExitStatus.failure(-1, msg);
}
private void processNoMatch(CommandProcess process) {
process.write("No class found for: " + classPattern + "\n");
private ExitStatus processNoMatch(CommandProcess process) {
return ExitStatus.failure(-1, "No class found for: " + classPattern);
}
private Map<Class<?>, File> dump(Instrumentation inst, Set<Class<?>> classes) throws UnmodifiableClassException {

@ -5,35 +5,33 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
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.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.CommandUtils;
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,22 +94,27 @@ public class GetStaticCommand extends AnnotatedCommand {
RowAffect affect = new RowAffect();
Instrumentation inst = process.session().getInstrumentation();
Set<Class<?>> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, hashCode);
try {
if (matchedClasses == null || matchedClasses.isEmpty()) {
process.write("No class found for: " + classPattern + "\n");
} else if (matchedClasses.size() > 1) {
processMatches(process, matchedClasses);
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);
status = processExactMatch(process, affect, inst, matchedClasses);
}
} finally {
process.write(affect + "\n");
process.end();
process.appendResult(new RowAffectModel(affect));
CommandUtils.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,
private ExitStatus processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst,
Set<Class<?>> matchedClasses) {
Matcher<String> fieldNameMatcher = fieldNameMatcher();
@ -133,45 +136,41 @@ public class GetStaticCommand extends AnnotatedCommand {
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");
return ExitStatus.failure(-1, "getstatic: no matched static field was found");
} else {
return ExitStatus.success();
}
}
private void processMatches(CommandProcess process, Set<Class<?>> matchedClasses) {
Element usage = new LabelElement("getstatic -c <hashcode> " + 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 ExitStatus processMatches(CommandProcess process, Set<Class<?>> 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()));
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 <hashcode> " + 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 <hashcode> " + 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<ClassVO> matchedClassVOs = ClassUtils.createClassVOList(matchedClasses);
process.appendResult(new GetStaticModel(matchedClassVOs));
return ExitStatus.failure(-1, "Found more than one class for: " + classPattern + ", Please use: "+usage);
}
private Matcher<String> fieldNameMatcher() {

@ -3,38 +3,35 @@ 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.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.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.CommandUtils;
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
@ -107,27 +104,30 @@ public class JadCommand extends AnnotatedCommand {
Set<Class<?>> matchedClasses = SearchUtils.searchClassOnly(inst, classPattern, isRegEx, code);
try {
ExitStatus status = null;
if (matchedClasses == null || matchedClasses.isEmpty()) {
processNoMatch(process);
status = processNoMatch(process);
} else if (matchedClasses.size() > 1) {
processMatches(process, matchedClasses);
status = processMatches(process, matchedClasses);
} else { // matchedClasses size is 1
// find inner classes.
Set<Class<?>> withInnerClasses = SearchUtils.searchClassOnly(inst, matchedClasses.iterator().next().getName() + "$*", false, code);
if(withInnerClasses.isEmpty()) {
withInnerClasses = matchedClasses;
}
processExactMatch(process, affect, inst, matchedClasses, withInnerClasses);
status = processExactMatch(process, affect, inst, matchedClasses, withInnerClasses);
}
} finally {
if (!this.sourceOnly) {
process.write(affect + "\n");
process.appendResult(new RowAffectModel(affect));
}
process.end();
CommandUtils.end(process, status);
} catch (Throwable e){
logger.error("processing error", e);
process.end(-1, "processing error");
}
}
private void processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, Set<Class<?>> matchedClasses, Set<Class<?>> withInnerClasses) {
private ExitStatus processExactMatch(CommandProcess process, RowAffect affect, Instrumentation inst, Set<Class<?>> matchedClasses, Set<Class<?>> withInnerClasses) {
Class<?> c = matchedClasses.iterator().next();
Set<Class<?>> allClasses = new HashSet<Class<?>>(withInnerClasses);
allClasses.add(c);
@ -146,46 +146,38 @@ public class JadCommand extends AnnotatedCommand {
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());
return ExitStatus.success();
} catch (Throwable t) {
logger.error("jad: fail to decompile class: " + c.getName(), t);
return ExitStatus.failure(-1, "jad: fail to decompile class: " + c.getName());
}
}
private void processMatches(CommandProcess process, Set<Class<?>> matchedClasses) {
Element usage = new LabelElement("jad -c <hashcode> " + 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 ExitStatus processMatches(CommandProcess process, Set<Class<?>> 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()));
String usage = "jad -c <hashcode> " + 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<ClassVO> classVOs = ClassUtils.createClassVOList(matchedClasses);
JadModel jadModel = new JadModel();
jadModel.setMatchedClasses(classVOs);
process.appendResult(jadModel);
process.write(RenderUtil.render(table, process.width()) + "\n");
return ExitStatus.failure(-1, msg);
}
private void processNoMatch(CommandProcess process) {
process.write("No class found for: " + classPattern + "\n");
private ExitStatus processNoMatch(CommandProcess process) {
return ExitStatus.failure(-1, "No class found for: " + classPattern);
}
@Override

@ -3,6 +3,7 @@ package com.taobao.arthas.core.command.klass100;
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.Logger;
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,6 @@ public class MemoryCompilerCommand extends AnnotatedCommand {
@Override
public void process(final CommandProcess process) {
int exitCode = 0;
RowAffect affect = new RowAffect();
try {
@ -81,8 +83,7 @@ public class MemoryCompilerCommand extends AnnotatedCommand {
} 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,22 +113,20 @@ public class MemoryCompilerCommand extends AnnotatedCommand {
outputDir = new File("").getAbsoluteFile();
}
process.write("Memory compiler output:\n");
List<String> files = new ArrayList<String>();
for (Entry<String, byte[]> 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));
process.appendResult(new RowAffectModel(affect));
process.end();
} 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");
exitCode = -1;
} finally {
process.write(affect + "\n");
process.end(exitCode);
process.end(-1, "Memory compiler error, exception message: " + e.getMessage()
+ ", please check $HOME/logs/arthas/arthas.log for more details.");
}
}

@ -8,11 +8,10 @@ import com.taobao.arthas.core.command.Constants;
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;
@ -62,36 +61,31 @@ public class OgnlCommand extends AnnotatedCommand {
@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.write("Can not find classloader with hashCode: " + hashCode + ".\n");
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);
String result = StringUtils.objectToString(expand >= 0 ? new ObjectView(value, expand).draw() : value);
process.write(result + "\n");
} 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");
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. ");
}
}
}

@ -14,6 +14,7 @@ import com.alibaba.arthas.deps.org.objectweb.asm.ClassReader;
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 class RedefineCommand extends AnnotatedCommand {
@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,9 @@ public class RedefineCommand extends AnnotatedCommand {
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);
return;
} finally {
if (f != null) {
try {
@ -105,8 +105,7 @@ public class RedefineCommand extends AnnotatedCommand {
}
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,24 +117,25 @@ public class RedefineCommand extends AnnotatedCommand {
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");
} catch (Exception e) {
process.write("redefine error! " + e + "\n");
process.appendResult(redefineModel);
process.end();
} catch (Throwable e) {
String message = "redefine error! " + e.toString();
logger.error(message, e);
process.end(-1, message);
}
process.end();
}
private static String readClassName(final byte[] bytes) {

@ -8,11 +8,15 @@ import java.util.Comparator;
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.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.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.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,8 +85,14 @@ public class SearchClassCommand extends AnnotatedCommand {
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();
@ -94,23 +104,32 @@ public class SearchClassCommand extends AnnotatedCommand {
}
});
for (Class<?> clazz : matchedClasses) {
processClass(process, clazz);
if (isDetail) {
if (numberOfLimit > 0 && matchedClasses.size() > numberOfLimit) {
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) {
ClassDetailVO classInfo = ClassUtils.createClassInfo(clazz, isField);
process.appendResult(new SearchClassModel(classInfo, isDetail, isField, expand));
}
} else {
int pageSize = 256;
ResultUtils.processClassNames(matchedClasses, pageSize, new ResultUtils.PaginationHandler<List<String>>() {
@Override
public boolean handle(List<String> 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)) {

@ -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 java.util.Set;
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.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.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 class SearchMethodCommand extends AnnotatedCommand {
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,41 @@ public class SearchMethodCommand extends AnnotatedCommand {
Matcher<String> methodNameMatcher = methodNameMatcher();
Set<Class<?>> matchedClasses = SearchUtils.searchClass(inst, classPattern, isRegEx, hashCode);
if (numberOfLimit > 0 && matchedClasses.size() > numberOfLimit) {
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) {
try {
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
String methodNameWithDescriptor = com.alibaba.arthas.deps.org.objectweb.asm.commons.Method.getMethod(constructor).toString();
if (!methodNameMatcher.matching("<init>")) {
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 +144,6 @@ public class SearchMethodCommand extends AnnotatedCommand {
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("<init>").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);

@ -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;
}
}

@ -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<String> resources;
private ClassDetailVO loadClass;
private List<String> urls;
//classloader -l -t
private List<ClassLoaderVO> classLoaders;
private Boolean tree;
private Map<String, ClassLoaderStat> 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<String> getResources() {
return resources;
}
public ClassLoaderModel setResources(List<String> resources) {
this.resources = resources;
return this;
}
public ClassDetailVO getLoadClass() {
return loadClass;
}
public ClassLoaderModel setLoadClass(ClassDetailVO loadClass) {
this.loadClass = loadClass;
return this;
}
public List<String> getUrls() {
return urls;
}
public ClassLoaderModel setUrls(List<String> urls) {
this.urls = urls;
return this;
}
public List<ClassLoaderVO> getClassLoaders() {
return classLoaders;
}
public ClassLoaderModel setClassLoaders(List<ClassLoaderVO> classLoaders) {
this.classLoaders = classLoaders;
return this;
}
public Boolean getTree() {
return tree;
}
public ClassLoaderModel setTree(Boolean tree) {
this.tree = tree;
return this;
}
public Map<String, ClassLoaderStat> getClassLoaderStats() {
return classLoaderStats;
}
public ClassLoaderModel setClassLoaderStats(Map<String, ClassLoaderStat> classLoaderStats) {
this.classLoaderStats = classLoaderStats;
return this;
}
}

@ -0,0 +1,74 @@
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<ClassLoaderVO> children;
public ClassLoaderVO() {
}
public void addChild(ClassLoaderVO child){
if (this.children == null){
this.children = new ArrayList<ClassLoaderVO>();
}
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<ClassLoaderVO> getChildren() {
return children;
}
public void setChildren(List<ClassLoaderVO> children) {
this.children = children;
}
}

@ -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<String> classes;
private int segment;
public ClassSetVO(ClassLoaderVO classloader, Collection<String> classes) {
this(classloader, classes, 0);
}
public ClassSetVO(ClassLoaderVO classloader, Collection<String> 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<String> getClasses() {
return classes;
}
public void setClasses(Collection<String> 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;
}
}

@ -0,0 +1,35 @@
package com.taobao.arthas.core.command.model;
/**
* @author gongdewei 2020/4/8
*/
public class ClassVO {
private String name;
private String[] classloader;
private String classLoaderHash;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
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;
}
}

@ -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<DumpClassVO> dumpedClasses;
private Collection<ClassVO> matchedClasses;
public DumpClassModel() {
}
@Override
public String getType() {
return "dump";
}
public List<DumpClassVO> getDumpedClasses() {
return dumpedClasses;
}
public DumpClassModel setDumpedClasses(List<DumpClassVO> dumpedClasses) {
this.dumpedClasses = dumpedClasses;
return this;
}
public Collection<ClassVO> getMatchedClasses() {
return matchedClasses;
}
public DumpClassModel setMatchedClasses(Collection<ClassVO> matchedClasses) {
this.matchedClasses = matchedClasses;
return this;
}
}

@ -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;
}
}

@ -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;
}
}

@ -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<ClassVO> 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<ClassVO> matchedClasses) {
this.matchedClasses = matchedClasses;
}
public ObjectVO getField() {
return field;
}
public void setField(ObjectVO field) {
this.field = field;
}
public Collection<ClassVO> getMatchedClasses() {
return matchedClasses;
}
public void setMatchedClasses(Collection<ClassVO> matchedClasses) {
this.matchedClasses = matchedClasses;
}
public int expand() {
return expand;
}
public void setExpand(int expand) {
this.expand = expand;
}
@Override
public String getType() {
return "getstatic";
}
}

@ -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<ClassVO> 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<ClassVO> getMatchedClasses() {
return matchedClasses;
}
public void setMatchedClasses(Collection<ClassVO> matchedClasses) {
this.matchedClasses = matchedClasses;
}
}

@ -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<String> files;
public MemoryCompilerModel() {
}
public MemoryCompilerModel(List<String> files) {
this.files = files;
}
public void setFiles(List<String> files) {
this.files = files;
}
public List<String> getFiles() {
return files;
}
@Override
public String getType() {
return "mc";
}
}

@ -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;
}
}

@ -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;
}
}

@ -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;
}
}

@ -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<String> redefinedClasses;
public RedefineModel() {
redefinedClasses = new ArrayList<String>();
}
public void addRedefineClass(String className) {
redefinedClasses.add(className);
redefinitionCount++;
}
public int getRedefinitionCount() {
return redefinitionCount;
}
public void setRedefinitionCount(int redefinitionCount) {
this.redefinitionCount = redefinitionCount;
}
public List<String> getRedefinedClasses() {
return redefinedClasses;
}
public void setRedefinedClasses(List<String> redefinedClasses) {
this.redefinedClasses = redefinedClasses;
}
@Override
public String getType() {
return "redefine";
}
}

@ -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;
}
}

@ -0,0 +1,73 @@
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 ClassDetailVO classInfo;
private boolean withField;
private boolean detailed;
private Integer expand;
private List<String> classNames;
private int segment;
public SearchClassModel() {
}
public SearchClassModel(ClassDetailVO classInfo, boolean detailed, boolean withField, Integer expand) {
this.classInfo = classInfo;
this.detailed = detailed;
this.withField = withField;
this.expand = expand;
}
public SearchClassModel(List<String> classNames, int segment) {
this.classNames = classNames;
this.segment = segment;
}
@Override
public String getType() {
return "sc";
}
public ClassDetailVO getClassInfo() {
return classInfo;
}
public void setClassInfo(ClassDetailVO classInfo) {
this.classInfo = classInfo;
}
public List<String> getClassNames() {
return classNames;
}
public void setClassNames(List<String> classNames) {
this.classNames = classNames;
}
public int getSegment() {
return segment;
}
public void setSegment(int segment) {
this.segment = segment;
}
public boolean isDetailed() {
return detailed;
}
public boolean isWithField() {
return withField;
}
public Integer getExpand() {
return expand;
}
}

@ -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";
}
}

@ -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 class StatusModel extends ResultModel {
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";

@ -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.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.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<ClassLoaderModel> {
@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<String, ClassLoaderStat> 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<String, ClassLoaderStat> classLoaderStats) {
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
table.add(new RowElement().style(Decoration.bold.bold()).add("name", "numberOfInstances", "loadedCountTotal"));
for (Map.Entry<String, ClassLoaderStat> entry : classLoaderStats.entrySet()) {
table.row(entry.getKey(), "" + entry.getValue().getNumberOfInstance(), "" + entry.getValue().getLoadedCount());
}
return table;
}
private void drawClassLoaders(CommandProcess process, List<ClassLoaderVO> 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<String> urls) {
process.write(RenderUtil.render(renderClassLoaderUrls(urls), process.width()));
process.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING);
}
private void drawLoadClass(CommandProcess process, ClassDetailVO 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<String> 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<String> 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<ClassLoaderVO> 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<ClassLoaderVO> 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);
}
}
}

@ -0,0 +1,51 @@
package com.taobao.arthas.core.command.view;
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;
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<DumpClassModel> {
@Override
public void draw(CommandProcess process, DumpClassModel result) {
if (result.getDumpedClasses() != null) {
drawDumpedClasses(process, result.getDumpedClasses());
} else if (result.getMatchedClasses() != null) {
Element table = ClassUtils.renderMatchedClasses(result.getMatchedClasses());
process.write(RenderUtil.render(table)).write("\n");
}
}
private void drawDumpedClasses(CommandProcess process, List<DumpClassVO> 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 (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)));
}
process.write(RenderUtil.render(table, process.width()))
.write(com.taobao.arthas.core.util.Constants.EMPTY_STRING);
}
}

@ -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<GetStaticModel> {
@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");
}
}
}

@ -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<JadModel> {
@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);
}
}
}

@ -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<MemoryCompilerModel> {
@Override
public void draw(CommandProcess process, MemoryCompilerModel result) {
process.write("Memory compiler output:\n");
for (String file : result.getFiles()) {
process.write(file + '\n');
}
}
}

@ -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<OgnlModel> {
@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");
}
}

@ -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<RedefineModel> {
@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());
}
}

@ -29,6 +29,8 @@ public class ResultViewResolver {
*/
private void initResultViews() {
try {
registerView(RowAffectView.class);
//basic1000
registerView(StatusView.class);
registerView(VersionView.class);
@ -47,6 +49,15 @@ public class ResultViewResolver {
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

@ -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<RowAffectModel> {
@Override
public void draw(CommandProcess process, RowAffectModel result) {
process.write(result.affect() + "\n");
}
}

@ -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<SearchClassModel> {
@Override
public void draw(CommandProcess process, SearchClassModel result) {
if (result.isDetailed()) {
process.write(RenderUtil.render(ClassUtils.renderClassInfo(result.getClassInfo(),
result.isWithField(), result.getExpand()), process.width()));
process.write("\n");
} else if (result.getClassNames() != null) {
for (String className : result.getClassNames()) {
process.write(className).write("\n");
}
}
}
}

@ -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<SearchMethodModel> {
@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");
}
}
}

@ -0,0 +1,64 @@
package com.taobao.arthas.core.shell.command;
/**
*
*/
public class ExitStatus {
/**
*
*/
public static final ExitStatus SUCCESS_STATUS = new ExitStatus(0);
/**
*
* @return
*/
public static ExitStatus success() {
return SUCCESS_STATUS;
}
/**
*
* @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");
}
return new ExitStatus(statusCode, message);
}
/**
*
* @param exitStatus
* @return
*/
public static boolean isFailed(ExitStatus exitStatus) {
return exitStatus != null && exitStatus.getStatusCode() != 0;
}
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;
}
}

@ -2,12 +2,27 @@ package com.taobao.arthas.core.util;
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.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;
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
@ -27,17 +42,16 @@ public class ClassUtils {
return clazz.getName().contains("$$Lambda$");
}
public static Element renderClassInfo(Class<?> clazz) {
public static Element renderClassInfo(ClassDetailVO clazz) {
return renderClassInfo(clazz, false, null);
}
public static Element renderClassInfo(Class<?> clazz, boolean isPrintField, Integer expand) {
public static Element renderClassInfo(ClassDetailVO 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)))
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.isInterface()))
.row(label("isAnnotation").style(Decoration.bold.bold()), label("" + clazz.isAnnotation()))
.row(label("isEnum").style(Decoration.bold.bold()), label("" + clazz.isEnum()))
@ -48,12 +62,12 @@ public class ClassUtils {
.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("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(StringUtils.classLoaderHash(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));
@ -61,4 +75,156 @@ public class ClassUtils {
return table;
}
public static ClassDetailVO createClassInfo(Class clazz, boolean withFields) {
CodeSource cs = clazz.getProtectionDomain().getCodeSource();
ClassDetailVO classInfo = new ClassDetailVO();
classInfo.setName(StringUtils.classname(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));
}
return classInfo;
}
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));
}
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("<init>");
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(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(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("<init>").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<String> list = new ArrayList<String>();
for (Class anInterface : classes) {
list.add(StringUtils.classname(anInterface));
}
return list.toArray(new String[0]);
}
public static List<ClassVO> createClassVOList(Set<Class<?>> matchedClasses) {
List<ClassVO> classVOs = new ArrayList<ClassVO>(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<ClassVO> 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;
}
}

@ -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 CommandUtils {
/**
* 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");
}
}
}

@ -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 {
/**
* classclassName
* @param classes
* @param pageSize
* @param handler
*/
public static void processClassNames(Collection<Class<?>> classes, int pageSize, PaginationHandler<List<String>> handler) {
List<String> classNames = new ArrayList<String>(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<String>(pageSize);
}
}
//last segment
if (classNames.size() > 0) {
handler.handle(classNames, segment++);
}
}
/**
*
* @param <T>
*/
public interface PaginationHandler<T> {
/**
*
* @param list
* @param segment
* @return true false
*/
boolean handle(T list, int segment);
}
}

@ -71,7 +71,7 @@ public abstract class StringUtils {
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 abstract class StringUtils {
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);
}
}

@ -1,5 +1,8 @@
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;
import com.taobao.text.ui.Element;
import com.taobao.text.ui.TableElement;
@ -10,8 +13,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.List;
import static com.taobao.text.ui.Element.label;
@ -21,14 +23,6 @@ import static com.taobao.text.ui.Element.label;
*/
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());
}
@ -41,6 +35,10 @@ public class TypeRenderUtils {
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,70 +51,51 @@ public class TypeRenderUtils {
return StringUtils.concat("\n", constructor.getExceptionTypes());
}
public static Element drawSuperClass(Class<?> clazz) {
TreeElement root = new TreeElement();
TreeElement parent = root;
public static String drawExceptions(String[] exceptionTypes) {
return StringUtils.concat("\n", exceptionTypes);
}
Class<?> superClass = clazz.getSuperclass();
if (null != superClass) {
TreeElement child = new TreeElement(label(StringUtils.classname(superClass)));
parent.addChild(child);
parent = child;
public static Element drawSuperClass(ClassDetailVO clazz) {
return drawTree(clazz.getSuperClass());
}
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 drawClassLoader(ClassVO clazz) {
String[] classloaders = clazz.getClassloader();
return drawTree(classloaders);
}
public static Element drawClassLoader(Class<?> clazz) {
public static Element drawTree(String[] nodes) {
TreeElement root = new TreeElement();
TreeElement parent = root;
ClassLoader loader = clazz.getClassLoader();
if (null != loader) {
TreeElement child = new TreeElement(label(loader.toString()));
for (String node : nodes) {
TreeElement child = new TreeElement(label(node));
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 drawField(Class<?> clazz, Integer expand) {
public static Element drawField(ClassDetailVO clazz, Integer expand) {
TableElement fieldsTable = new TableElement(1).leftCellPadding(0).rightCellPadding(0);
Field[] fields = clazz.getDeclaredFields();
FieldVO[] fields = clazz.getFields();
if (fields == null || fields.length == 0) {
return fieldsTable;
}
for (Field field : fields) {
for (FieldVO 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(), ','));
.row("type", field.getType())
.row("modifier", field.getModifier());
Annotation[] annotations = field.getAnnotations();
String[] 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));
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(""));
@ -126,40 +105,97 @@ public class TypeRenderUtils {
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();
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<String> list = new ArrayList<String>();
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<String> list = new ArrayList<String>();
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<String> list = new ArrayList<String>();
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<FieldVO> list = new ArrayList<FieldVO>(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 String drawFieldValue(Field field, Integer expand) {
private static Object getFieldValue(Field field) {
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);
return value;
} catch (IllegalAccessException e) {
// no op
} finally {
field.setAccessible(isAccessible);
}
return Constants.EMPTY_STRING;
return null;
}
public static String drawAnnotation(Annotation... annotations) {
List<Class<?>> types = Collections.emptyList();
if (annotations != null && annotations.length > 0) {
types = new LinkedList<Class<?>>();
for (Annotation annotation : annotations) {
types.add(annotation.annotationType());
}
}
return StringUtils.concat(",", types.toArray(new Class<?>[0]));
}
}

Loading…
Cancel
Save