package org.owasp.security.logging.util; import java.lang.Thread.State; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; import java.util.ArrayList; import com.sun.management.UnixOperatingSystemMXBean; /** * Default implementation of a IntervalLoggerModel. The DefaultIntervalLoggerModel * provides basic system information that most applications will find helpful when * diagnosing system problems like: MemoryTotal, MemoryFree, MemoryMax, ThreadNew, * ThreadRunnable, ThreadBlocked, ThreadWaiting, ThreadTerminated. Developers * can include new properties or remove existing properties from the model. To * include a new property consider the following. * <code> * // Add a new property to the list of current properties * DefaultIntervalLoggerModel model = new DefaultIntervalLoggerModel(); * model.addProperty( new DefaultIntervalProperty("YourPropertyName") { * public void refresh() { * value = sYourPropertyStringValue; * } * }); * </code> * Alternatively to remove only the ThreadNew property do the following. * <code> * // Remove default property from middle of the list like ThreadNew * IntervalProperty[] properties = model.getProperties(); * for ( IntervalProperty i : properties ) { * if( i.getName().equals("ThreadNew") ) * model.removeProperty(i); * } * </code> * * @author Milton Smith * */ public class DefaultIntervalLoggerModel implements IntervalLoggerModel { private static ThreadGroup rootThreadGroup = null; private ArrayList<IntervalProperty> list = new ArrayList<IntervalProperty>(); public DefaultIntervalLoggerModel() { super(); addProperty( new ByteIntervalProperty("MemoryTotal") { public void refresh() { value = addUnits(Long.toString(Runtime.getRuntime().totalMemory())); } } ); addProperty( new ByteIntervalProperty("MemoryFree") { public void refresh() { value = addUnits(Long.toString(Runtime.getRuntime().freeMemory())); } } ); addProperty( new ByteIntervalProperty("MemoryMax") { public void refresh() { value = addUnits(Long.toString(Runtime.getRuntime().maxMemory())); } } ); addProperty( new DefaultIntervalProperty("ThreadNew") { public void refresh() { value = Long.toString(getThreadState(State.NEW)); } } ); addProperty( new DefaultIntervalProperty("ThreadRunnable") { public void refresh() { value = Long.toString(getThreadState(State.RUNNABLE)); } } ); addProperty( new DefaultIntervalProperty("ThreadBlocked") { public void refresh() { value = Long.toString(getThreadState(State.BLOCKED)); } } ); addProperty( new DefaultIntervalProperty("ThreadWaiting") { public void refresh() { value = Long.toString(getThreadState(State.WAITING)); } } ); addProperty( new DefaultIntervalProperty("ThreadTerminated") { public String getValue() { return Long.toString(getThreadState(State.TERMINATED)); } } ); //TODO: need to figure this out. // addProperty( new DefaultIntervalProperty("ThreadTotal") { // public String getValue() { // return Long.toString(t_new+t_); // } // } // ); } /** * Add a new property to be included when printing the status message. * @param action Property to add */ @Override public synchronized void addProperty(IntervalProperty action) { list.add( action ); } /** * Remove property from status messages. * @param action Property to remove */ @Override public synchronized void removeProperty(IntervalProperty action) { list.remove(action); } /** * Return all properties. * @return Array of all properties available for printing in status message. */ @Override public synchronized IntervalProperty[] getProperties() { return list.toArray(new IntervalProperty[0]); } /** * Signal properties to update themselves. */ @Override public synchronized void refresh() { IntervalProperty[] properties = getProperties(); for(IntervalProperty p : properties ) { p.refresh(); } } /** * Utility method to retrieve the number of threads of * a specified state. * @param state Target Thread.State to retrieve. * @return Total threads in specified state. */ private int getThreadState( Thread.State state ) { Thread[] threads = getAllThreads(); int ct = 0; for( Thread thread : threads ) { if (state.equals(thread.getState()) ) ct++; } return ct; } /** * Utility method to return all threads in system owned by the * root ThreadGroup. * @return Array of all threads. */ private Thread[] getAllThreads() { final ThreadGroup root = getRootThreadGroup( ); int ct = Thread.activeCount(); int n = 0; Thread[] threads; do { ct *= 2; threads = new Thread[ ct ]; n = root.enumerate( threads, true ); } while ( n == ct ); return java.util.Arrays.copyOf( threads, n ); } /** * Utility method to retrieve the root ThreadGroup. Specifically, the * root ThreadGroups is where ThreadGroup.getParent() == null. * @return Root ThreadGroup */ private ThreadGroup getRootThreadGroup() { if ( rootThreadGroup != null ) return rootThreadGroup; ThreadGroup tg = Thread.currentThread( ).getThreadGroup( ); ThreadGroup ptg; while ( (ptg = tg.getParent( )) != null ) tg = ptg; return tg; } }