/*
* ALMA - Atacama Large Millimiter Array
* (c) Universidad Tecnica Federico Santa Maria, 2008
* Copyright by ESO (in the framework of the ALMA collaboration),
* All rights reserved
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package alma.acs.monitoring;
import java.io.PrintStream;
import java.lang.Thread.State;
import java.lang.management.ThreadInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.management.openmbean.CompositeData;
import alma.acs.util.StringOutputStream;
/**
* This class is intended to have only <code>public static</code> methods to
* help in the management of information given by the {@link RemoteThreadsMBean}
* class, like type conversion and printing information.
* @author rtobar
* @since ACS 7.0
*/
public class RemoteThreadsUtil {
/**
* Converts a {@link CompositeData} array into a {@link ThreadInfo} one
* using the {@link ThreadInfo#from(javax.management.openmbean.CompositeData)}
* method.
* @param data The {@link CompositeData} array
* @return The {@link ThreadInfo} array corresponding to the <code>
* data</code> input data.
*/
public static ThreadInfo[] toThreadsInfo(CompositeData[] data) {
ThreadInfo[] info = new ThreadInfo[data.length];
for(int i=0; i!= data.length; i++)
info[i] = ThreadInfo.from(data[i]);
return info;
}
/**
* Returns an array with the information of a group of threads that can be
* printed. The information can be grouped or not by
* thread state and by the name of the class where the thread "started".
* @param info The {@link ThreadInfo} array with the information to be printed
* @param grouped If true, the information is grouped by class name and state,
* printing the count for each group.
*/
public static String printThreadsInfo(ThreadInfo[] info,boolean grouped) {
// We use the alma.acs.util.StringOutputStream class
StringOutputStream stringOS = new StringOutputStream();
PrintStream printer = new PrintStream(stringOS);
printThreadsInfo(info,printer,grouped);
printer.flush();
return stringOS.toString();
}
/**
* Prints the information of a group of threads into the specified printer
* object <code>printer</code>. The information can be grouped or not by
* thread state and by the name of the class where the thread "started".
* @param info The {@link ThreadInfo} array with the information to be printed
* @param printer Object where the information is going to be printed, such
* as {@link System.out}.
* @param grouped If true, the information is grouped by class name and state,
* printing the count for each group.
*/
public static void printThreadsInfo(ThreadInfo[] info, PrintStream printer, boolean grouped) {
// For grouped data
List<Data> threadStats = new ArrayList<Data>(info.length);
// Head
printer.printf("%-50s%-15s","Class name","State");
if( grouped ) {
printer.printf("%-5s","#");
}
printer.print("\n========== =====");
if( grouped ) {
printer.print(" =");
}
printer.println();
for(int i=0; i!=info.length; i++) {
StackTraceElement[] elements = info[i].getStackTrace();
int idx = elements.length - 1;
if( idx > 1 ) {
String className = elements[idx].getClassName();
if( className.equals("java.lang.Thread") )
className = elements[--idx].getClassName();
if( !grouped ) {
printer.printf("%-50s%-15s\n",elements[idx].getClassName(),info[i].getThreadState());
}
else {
boolean found = false;
Data threadEntry = new Data(className, info[i].getThreadState(), 1);
for (Iterator<Data> iterator = threadStats.iterator(); iterator
.hasNext();) {
Data candidate = iterator.next();
if (threadEntry.equals(candidate)) {
candidate.bumpCount(); // already there, increment count
found = true;
break;
}
}
if (!found) threadStats.add(threadEntry);
}
}
}
if( grouped ) {
Collections.sort(threadStats);
for (Iterator<Data> iterator = threadStats.iterator(); iterator
.hasNext();) {
if (iterator != null) {
Data dat = iterator.next();
printer.printf("%-50s%-15s%d\n",dat.getName(),
dat.getState(), dat.getCount());
}
}
}
return;
}
private static class Data implements Comparable<Data>{
private String name;
private State state;
private int count;
public Data(String name, State state, int count) {
super();
this.name = name;
this.state = state;
this.count = count;
}
public int getCount() {
return count;
}
// public void setCount(int count) {
// this.count = count;
// }
public void bumpCount() {
this.count++;
}
public String getName() {
return name;
}
public State getState() {
return state;
}
public boolean equals(Object o) {
if (o == null || !(o instanceof Data)) return false;
Data test = (Data) o;
if (name.equals(test.getName()) && state.equals(test.getState())) return true;
return false;
}
public int compareTo(Data o) {
if (o == null) throw new NullPointerException();
int nameResult = o.getName().compareTo(getName());
if ( nameResult == 0 )
return o.getState().compareTo(getState());
return nameResult;
}
}
}