// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package net.sourceforge.eclipsejetty.starter.console.command;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import net.sourceforge.eclipsejetty.starter.console.AbstractCommand;
import net.sourceforge.eclipsejetty.starter.console.ArgumentException;
import net.sourceforge.eclipsejetty.starter.console.ConsoleAdapter;
import net.sourceforge.eclipsejetty.starter.console.Process;
import net.sourceforge.eclipsejetty.starter.console.util.WildcardUtils;
import net.sourceforge.eclipsejetty.starter.util.Utils;
/**
* Prints thread information
*
* @author Manfred Hantschel
*/
public class ThreadCommand extends AbstractCommand
{
public ThreadCommand(ConsoleAdapter consoleAdapter)
{
super(consoleAdapter, "thread", "t");
}
/**
* {@inheritDoc}
*
* @see net.sourceforge.eclipsejetty.starter.console.Command#getFormat()
*/
public String getFormat()
{
return "{<ID>}";
}
/**
* {@inheritDoc}
*
* @see net.sourceforge.eclipsejetty.starter.console.Command#getDescription()
*/
public String getDescription()
{
return "Thread information.";
}
/**
* {@inheritDoc}
*
* @see net.sourceforge.eclipsejetty.starter.console.AbstractCommand#getHelpDescription()
*/
@Override
protected String getHelpDescription()
{
return "Displays information gathered form threads. If the command is invoked without an <ID>, "
+ "a summary of all threads will be displayed. If the command is invoked with an <ID> (as thread id), "
+ "detail information of the thread will be displayed. You can use * as <ID> to display detail information "
+ "of all threads.";
}
/**
* {@inheritDoc}
*
* @see net.sourceforge.eclipsejetty.starter.console.Command#getOrdinal()
*/
public int getOrdinal()
{
return 520;
}
/**
* {@inheritDoc}
*
* @see net.sourceforge.eclipsejetty.starter.console.Command#execute(java.lang.String,
* net.sourceforge.eclipsejetty.starter.console.Process)
*/
public int execute(String commandName, Process process) throws Exception
{
if (process.args.isEmpty())
{
return list(process);
}
String id;
while ((id = process.args.consumeString()) != null)
{
show(process, id);
}
return 0;
}
private int list(Process process)
{
List<Thread> threads = getThreads();
int idLength = 0;
int nameLength = 0;
int classLength = 0;
for (Thread thread : threads)
{
idLength = Math.max(idLength, String.valueOf(thread.getId()).length());
nameLength = Math.max(nameLength, thread.getName().length());
classLength = Math.max(classLength, thread.getClass().getName().length());
}
process.out.printf(" %" + idLength + "s | %-" + nameLength + "s | %-" + classLength + "s \n", "ID", "Name",
"Class");
process.out.println("-" + Utils.repeat("-", idLength) + "-+-" + Utils.repeat("-", nameLength) + "-+-"
+ Utils.repeat("-", classLength) + "-");
for (Thread thread : threads)
{
process.out.printf(" %" + idLength + "d | %-" + nameLength + "s | %-" + classLength + "s \n",
thread.getId(), thread.getName(), thread.getClass().getName());
}
process.out.println();
process.out.printf("Thread count: %s\n", threads.size());
return 0;
}
private int show(Process process, String id)
{
List<Thread> threads = getThreads();
boolean hit = false;
for (Thread thread : threads)
{
if (WildcardUtils.match(String.valueOf(thread.getId()), id))
{
show(process, thread);
hit = true;
}
}
if (!hit)
{
throw new ArgumentException(String.format("Invalid thread ID: %s", id));
}
return 0;
}
private void show(Process process, Thread thread)
{
String title = thread.getId() + ".) " + thread.getName() + " (" + thread.getClass() + ")";
process.out.println(title);
process.out.println(Utils.repeat("-", title.length()));
StackTraceElement[] stackTraceElements = thread.getStackTrace();
for (StackTraceElement element : stackTraceElements)
{
process.out.println(element);
}
process.out.println();
}
private List<Thread> getThreads()
{
List<Thread> threads = new ArrayList<Thread>(Thread.getAllStackTraces().keySet());
Collections.sort(threads, new Comparator<Thread>()
{
public int compare(Thread o1, Thread o2)
{
return (int) (o1.getId() - o2.getId());
}
});
return threads;
}
}