updates to managed attribute, tests, objectmbean impl and a note to improve id as viewed in jconsole

This commit is contained in:
Jesse McConnell 2012-08-10 10:29:09 -05:00
parent 95b70cac81
commit f92ebea9f0
11 changed files with 236 additions and 161 deletions

View File

@ -228,6 +228,8 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste
* Implementation of Container.Listener interface
*
* @see org.eclipse.jetty.util.component.Container.Listener#addBean(java.lang.Object)
*
* TODO improve the id property to include better information
*/
public synchronized void addBean(Object obj)
{

View File

@ -75,10 +75,10 @@ public class ObjectMBean implements DynamicMBean
protected Object _managed;
private MBeanInfo _info;
private Map _getters=new HashMap();
private Map _setters=new HashMap();
private Map _methods=new HashMap();
private Set _convert=new HashSet();
private Map<String, Method> _getters=new HashMap<String, Method>();
private Map<String, Method> _setters=new HashMap<String, Method>();
private Map<String, Method> _methods=new HashMap<String, Method>();
private Set<String> _convert=new HashSet<String>();
private ClassLoader _loader;
private MBeanContainer _mbeanContainer;
@ -261,19 +261,6 @@ public class ObjectMBean implements DynamicMBean
continue;
}
// Process Field Annotations
for (Field field : oClass.getDeclaredFields())
{
LOG.debug("Checking: " + field.getName());
ManagedAttribute fieldAnnotation = field.getAnnotation(ManagedAttribute.class);
if (fieldAnnotation != null)
{
LOG.debug("Field Annotation found for: " + field.getName());
attributes.add(defineAttribute(field.getName(),fieldAnnotation));
}
}
// Process Method Annotations
for (Method method : oClass.getDeclaredMethods())
@ -284,7 +271,7 @@ public class ObjectMBean implements DynamicMBean
{
// TODO sort out how a proper name could get here, its a method name as an attribute at this point.
LOG.debug("Attribute Annotation found for: " + method.getName());
attributes.add(defineAttribute(method.getName(),methodAttributeAnnotation));
attributes.add(defineAttribute(method,methodAttributeAnnotation));
}
ManagedOperation methodOperationAnnotation = method.getAnnotation(ManagedOperation.class);
@ -572,119 +559,80 @@ public class ObjectMBean implements DynamicMBean
* </ul>
* the access is either "RW" or "RO".
*/
public MBeanAttributeInfo defineAttribute(String name, ManagedAttribute attributeAnnotation)
public MBeanAttributeInfo defineAttribute(Method method, ManagedAttribute attributeAnnotation)
{
//String name = field.getName();
// determine the name of the managed attribute
String name = attributeAnnotation.name();
if ("".equals(name))
{
name = toVariableName(method.getName());
}
String description = attributeAnnotation.value();
boolean writable = !attributeAnnotation.readonly();
boolean readonly = attributeAnnotation.readonly();
boolean onMBean = attributeAnnotation.proxied();
boolean convert = attributeAnnotation.managed();
String uName = name.substring(0, 1).toUpperCase() + name.substring(1);
Class oClass = onMBean ? this.getClass() : _managed.getClass();
Class<?> oClass = onMBean ? this.getClass() : _managed.getClass();
LOG.debug("defineAttribute {} {}:{}:{}:{}",name,onMBean,writable,oClass,description);
LOG.debug("defineAttribute {} {}:{}:{}:{}",name,onMBean,readonly,oClass,description);
Class type = null;
Method getter = null;
Class<?> type = null;
Method setter = null;
type = method.getReturnType();
String declaredGetter = attributeAnnotation.getter();
String declaredSetter = attributeAnnotation.setter();
Method[] methods = oClass.getMethods();
for (int m = 0; m < methods.length; m++)
// dig out a setter if one exists
if (!readonly)
{
if ((methods[m].getModifiers() & Modifier.PUBLIC) == 0)
continue;
String declaredSetter = attributeAnnotation.setter();
// Check if it is a declared getter
if (methods[m].getName().equals(declaredGetter) && methods[m].getParameterTypes().length == 0)
LOG.debug("DeclaredSetter:" + declaredSetter);
Method[] methods = oClass.getMethods();
for (int m = 0; m < methods.length; m++)
{
if (getter != null)
{
LOG.warn("Multiple mbean getters for attr " + name+ " in "+oClass);
if ((methods[m].getModifiers() & Modifier.PUBLIC) == 0)
continue;
}
getter = methods[m];
if (type != null && !type.equals(methods[m].getReturnType()))
if (!"".equals(declaredSetter))
{
LOG.warn("Type conflict for mbean attr " + name+ " in "+oClass);
continue;
// look for a declared setter
if (methods[m].getName().equals(declaredSetter) && methods[m].getParameterTypes().length == 1)
{
if (setter != null)
{
LOG.warn("Multiple setters for mbean attr " + name + " in " + oClass);
continue;
}
setter = methods[m];
if ( !type.equals(methods[m].getParameterTypes()[0]))
{
LOG.warn("Type conflict for mbean attr " + name + " in " + oClass);
continue;
}
LOG.debug("Declared Setter: " + declaredSetter);
}
}
type = methods[m].getReturnType();
LOG.debug("Declared Getter: " + declaredGetter);
}
// Look for a getter
if (methods[m].getName().equals("get" + uName) && methods[m].getParameterTypes().length == 0)
{
if (getter != null)
// look for a setter
if ( methods[m].getName().equals("set" + uName) && methods[m].getParameterTypes().length == 1)
{
LOG.warn("Multiple mbean getters for attr " + name+ " in "+oClass);
continue;
}
getter = methods[m];
if (type != null && !type.equals(methods[m].getReturnType()))
{
LOG.warn("Type conflict for mbean attr " + name+ " in "+oClass);
continue;
}
type = methods[m].getReturnType();
}
// Look for an is getter
if (methods[m].getName().equals("is" + uName) && methods[m].getParameterTypes().length == 0)
{
if (getter != null)
{
LOG.warn("Multiple mbean getters for attr " + name+ " in "+oClass);
continue;
}
getter = methods[m];
if (type != null && !type.equals(methods[m].getReturnType()))
{
LOG.warn("Type conflict for mbean attr " + name+ " in "+oClass);
continue;
}
type = methods[m].getReturnType();
}
// look for a declared setter
if (writable && methods[m].getName().equals(declaredSetter) && methods[m].getParameterTypes().length == 1)
{
if (setter != null)
{
LOG.warn("Multiple setters for mbean attr " + name+ " in "+oClass);
continue;
}
setter = methods[m];
if (type != null && !type.equals(methods[m].getParameterTypes()[0]))
{
LOG.warn("Type conflict for mbean attr " + name+ " in "+oClass);
continue;
}
LOG.debug("Declared Setter: " + declaredSetter);
type = methods[m].getParameterTypes()[0];
}
// look for a setter
if (writable && methods[m].getName().equals("set" + uName) && methods[m].getParameterTypes().length == 1)
{
if (setter != null)
{
LOG.warn("Multiple setters for mbean attr " + name+ " in "+oClass);
continue;
if (setter != null)
{
LOG.warn("Multiple setters for mbean attr " + name + " in " + oClass);
continue;
}
setter = methods[m];
if ( !type.equals(methods[m].getParameterTypes()[0]))
{
LOG.warn("Type conflict for mbean attr " + name + " in " + oClass);
continue;
}
}
setter = methods[m];
if (type != null && !type.equals(methods[m].getParameterTypes()[0]))
{
LOG.warn("Type conflict for mbean attr " + name+ " in "+oClass);
continue;
}
type = methods[m].getParameterTypes()[0];
}
}
@ -704,16 +652,10 @@ public class ObjectMBean implements DynamicMBean
LOG.debug("passed convert checks {} for type {}", name, type);
}
if (getter == null && setter == null)
{
LOG.warn("No mbean getter or setters found for {} in {}", name, oClass);
return null;
}
try
{
// Remember the methods
_getters.put(name, getter);
_getters.put(name, method);
_setters.put(name, setter);
MBeanAttributeInfo info=null;
@ -723,16 +665,16 @@ public class ObjectMBean implements DynamicMBean
if (type.isArray())
{
info= new MBeanAttributeInfo(name,OBJECT_NAME_ARRAY_CLASS,description,getter!=null,setter!=null,getter!=null&&getter.getName().startsWith("is"));
info= new MBeanAttributeInfo(name,OBJECT_NAME_ARRAY_CLASS,description,true,setter!=null,method.getName().startsWith("is"));
}
else
{
info= new MBeanAttributeInfo(name,OBJECT_NAME_CLASS,description,getter!=null,setter!=null,getter!=null&&getter.getName().startsWith("is"));
info= new MBeanAttributeInfo(name,OBJECT_NAME_CLASS,description,true,setter!=null,method.getName().startsWith("is"));
}
}
else
{
info= new MBeanAttributeInfo(name,description,getter,setter);
info= new MBeanAttributeInfo(name,description,method,setter);
}
return info;
@ -834,5 +776,25 @@ public class ObjectMBean implements DynamicMBean
}
}
protected String toVariableName( String methodName )
{
String variableName = methodName;
if ( methodName.startsWith("get") || methodName.startsWith("set") )
{
variableName = variableName.substring(3);
}
else if ( methodName.startsWith("is") )
{
variableName = variableName.substring(2);
}
variableName = variableName.substring(0,1).toLowerCase() + variableName.substring(1);
return variableName;
}
}

View File

@ -17,11 +17,16 @@ import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.jmx.ObjectMBean;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.log.Log;
/* ------------------------------------------------------------ */
/**
*/
@ManagedObject("Jetty Logging")
public class LogMBean extends ObjectMBean
{
@ -30,18 +35,21 @@ public class LogMBean extends ObjectMBean
super(managedObject);
}
@ManagedAttribute(value="list of instantiated loggers")
public List<String> getLoggers()
{
List<String> keySet = new ArrayList<String>(Log.getLoggers().keySet());
return keySet;
}
public boolean isDebugEnabled(String logger)
@ManagedOperation(value="true if debug enabled for the given logger")
public boolean isDebugEnabled(@Name("logger") String logger)
{
return Log.getLogger(logger).isDebugEnabled();
}
public void setDebugEnabled(String logger, Boolean enabled)
@ManagedOperation(value="Set debug enabled for given logger")
public void setDebugEnabled(@Name("logger")String logger, @Name("enabled") Boolean enabled)
{
Log.getLogger(logger).setDebugEnabled(enabled);
}

View File

@ -21,12 +21,11 @@ import org.eclipse.jetty.util.annotation.Name;
@ManagedObject(value="Test the mbean stuff", wrapper="com.acme.jmx.DerivedMBean")
public class Derived extends Base implements Signature
{
@ManagedAttribute(value="The full name of something", getter="getFullName", setter="setFullName")
String fname="Full Name";
@ManagedAttribute( value="sample managed object")
Managed managedInstance = new Managed();
@ManagedAttribute(value="The full name of something", name="fname", setter="setFullName")
public String getFullName()
{
return fname;
@ -54,6 +53,7 @@ public class Derived extends Base implements Signature
return "bad";
}
@ManagedAttribute( value="sample managed object")
public Managed getManagedInstance()
{
return managedInstance;

View File

@ -6,9 +6,9 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
@ManagedObject(value="Managed Object", wrapper="com.acme.jmx.ManagedMBean")
public class Managed
{
@ManagedAttribute("Managed Attribute")
String managed = "foo";
@ManagedAttribute("Managed Attribute")
public String getManaged()
{
return managed;
@ -19,4 +19,10 @@ public class Managed
this.managed = managed;
}
public String bad()
{
return "bad";
}
}

View File

@ -6,6 +6,7 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation;
import com.acme.Derived;
import com.acme.Managed;
@ManagedObject("Managed MBean Wrapper")
public class ManagedMBean extends ObjectMBean
@ -18,7 +19,7 @@ public class ManagedMBean extends ObjectMBean
@ManagedOperation(value="test of proxy operations", managed=true)
public String good()
{
return "not " + ((Derived)_managed).bad();
return "not managed " + ((Managed)_managed).bad();
}
@ManagedAttribute(value="test of proxy attributes", getter="goop", proxied=true)

View File

@ -1,4 +1,4 @@
// ========================================================================
// =====7===================================================================
// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
@ -25,7 +25,10 @@ import junit.framework.Assert;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@ -39,15 +42,15 @@ public class ObjectMBeanTest
private static MBeanContainer container;
@BeforeClass
public static void beforeClass() throws Exception
@Before
public void beforeClass() throws Exception
{
container = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
container.start();
}
@AfterClass
public static void afterClass() throws Exception
@After
public void afterClass() throws Exception
{
container.stop();
container = null;
@ -57,7 +60,7 @@ public class ObjectMBeanTest
* this test uses the com.acme.Derived test classes
*/
@Test
public void testMbeanInfo() throws Exception
public void testDerivedAttributes() throws Exception
{
Derived derived = new Derived();
@ -67,8 +70,8 @@ public class ObjectMBeanTest
mbean.setMBeanContainer(container);
managed.setMBeanContainer(container);
container.addBean(mbean);
container.addBean(managed);
container.addBean(derived);
container.addBean(derived.getManagedInstance());
MBeanInfo toss = managed.getMBeanInfo();
@ -79,15 +82,15 @@ public class ObjectMBeanTest
Assert.assertEquals("name does not match", "com.acme.Derived", info.getClassName());
Assert.assertEquals("description does not match", "Test the mbean stuff", info.getDescription());
for ( MBeanAttributeInfo i : info.getAttributes())
{
LOG.debug(i.toString());
}
//for ( MBeanAttributeInfo i : info.getAttributes())
//{
// LOG.debug(i.toString());
//}
/*
* 6 attributes from lifecycle and 2 from Derived and 1 from MBean
* 1 attribute from lifecycle and 2 from Derived and 1 from MBean
*/
Assert.assertEquals("attribute count does not match", 9, info.getAttributes().length);
Assert.assertEquals("attribute count does not match", 4, info.getAttributes().length);
Assert.assertEquals("attribute values does not match", "Full Name", mbean.getAttribute("fname") );
@ -95,10 +98,25 @@ public class ObjectMBeanTest
Assert.assertEquals("set attribute value does not match", "Fuller Name", mbean.getAttribute("fname") );
Assert.assertEquals("proxy attribute values do not match", "goop", mbean.getAttribute("goop") );
Assert.assertEquals("proxy attribute values do not match", "goop", mbean.getAttribute("goop") );
//Thread.sleep(100000);
}
@Test
public void testDerivedOperations() throws Exception
{
Derived derived = new Derived();
ObjectMBean mbean = (ObjectMBean)ObjectMBean.mbeanFor(derived);
mbean.setMBeanContainer(container);
container.addBean(derived);
MBeanInfo info = mbean.getMBeanInfo();
Assert.assertEquals("operation count does not match", 5, info.getOperations().length);
MBeanOperationInfo[] opinfos = info.getOperations();
boolean publish = false;
boolean doodle = false;
@ -106,9 +124,7 @@ public class ObjectMBeanTest
for ( int i = 0 ; i < opinfos.length; ++i )
{
MBeanOperationInfo opinfo = opinfos[i];
LOG.debug(opinfo.getName());
if ("publish".equals(opinfo.getName()))
{
publish = true;
@ -126,6 +142,7 @@ public class ObjectMBeanTest
Assert.assertEquals("parameter name doesn't match", "doodle", pinfos[0].getName());
}
// This is a proxied operation on the JMX wrapper
if ("good".equals(opinfo.getName()))
{
good = true;
@ -138,11 +155,63 @@ public class ObjectMBeanTest
Assert.assertTrue("publish operation was not not found", publish);
Assert.assertTrue("doodle operation was not not found", doodle);
Assert.assertTrue("good operation was not not found", good);
// TODO sort out why this is not working...something off in Bean vs MBean ism's
}
@Test
public void testDerivedObjectAttributes() throws Exception
{
Derived derived = new Derived();
ObjectMBean mbean = (ObjectMBean)ObjectMBean.mbeanFor(derived);
ObjectMBean managed = (ObjectMBean)ObjectMBean.mbeanFor(derived.getManagedInstance());
mbean.setMBeanContainer(container);
managed.setMBeanContainer(container);
Assert.assertNotNull(mbean.getMBeanInfo());
container.addBean(derived);
container.addBean(derived.getManagedInstance());
Managed managedInstance = (Managed)mbean.getAttribute("managedInstance");
Assert.assertNotNull(managedInstance);
Assert.assertEquals("managed instance returning nonsense", "foo", managedInstance.getManaged());
}
@Test
public void testThreadPool() throws Exception
{
QueuedThreadPool qtp = new QueuedThreadPool();
ObjectMBean bqtp = (ObjectMBean)ObjectMBean.mbeanFor(qtp);
bqtp.getMBeanInfo();
container.addBean(qtp);
Thread.sleep(10000000);
}
@Test
public void testMethodNameMining() throws Exception
{
ObjectMBean mbean = new ObjectMBean(new Derived());
Assert.assertEquals("fullName",mbean.toVariableName("getFullName"));
Assert.assertEquals("fullName",mbean.toVariableName("getfullName"));
Assert.assertEquals("fullName",mbean.toVariableName("isFullName"));
Assert.assertEquals("fullName",mbean.toVariableName("isfullName"));
Assert.assertEquals("fullName",mbean.toVariableName("setFullName"));
Assert.assertEquals("fullName",mbean.toVariableName("setfullName"));
Assert.assertEquals("fullName",mbean.toVariableName("FullName"));
Assert.assertEquals("fullName",mbean.toVariableName("fullName"));
}
}

View File

@ -20,16 +20,23 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target( { ElementType.METHOD, ElementType.FIELD } )
@Target( { ElementType.METHOD } )
public @interface ManagedAttribute
{
/**
* Description of the Managed Object
* Description of the Managed Attribute
*
* @return
* @returngit checkout
*/
String value() default "Not Specified";
/**
* name to use for the attribute
*
* @return the name of the attribute
*/
String name() default "";
/**
* Is the managed field read-only?
*

View File

@ -30,17 +30,11 @@ public abstract class AbstractLifeCycle implements LifeCycle
{
private static final Logger LOG = Log.getLogger(AbstractLifeCycle.class);
@ManagedAttribute(value="instance is stopped", readonly=true, getter="isStopped")
public static final String STOPPED="STOPPED";
@ManagedAttribute(value="instance is failed", readonly=true, getter="isFailed")
public static final String FAILED="FAILED";
@ManagedAttribute(value="instance is starting", readonly=true, getter="isStarting")
public static final String STARTING="STARTING";
@ManagedAttribute(value="instance is started", readonly=true, getter="isStarted")
public static final String STARTED="STARTED";
@ManagedAttribute(value="instance is stopping", readonly=true, getter="isStopping")
public static final String STOPPING="STOPPING";
@ManagedAttribute(value="instance is running", readonly=true, getter="isRunning")
public static final String RUNNING="RUNNING";
private final CopyOnWriteArrayList<LifeCycle.Listener> _listeners=new CopyOnWriteArrayList<LifeCycle.Listener>();
@ -139,6 +133,7 @@ public abstract class AbstractLifeCycle implements LifeCycle
_listeners.remove(listener);
}
@ManagedAttribute(value="Lifecycle State for this instance", readonly=true)
public String getState()
{
switch(_state)

View File

@ -28,6 +28,10 @@ import java.util.concurrent.atomic.AtomicLong;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.component.AggregateLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
@ -36,6 +40,7 @@ import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.ThreadPool.SizedThreadPool;
@ManagedObject("A thread pool with no max bound by default")
public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPool, Dumpable
{
private static final Logger LOG = Log.getLogger(QueuedThreadPool.class);
@ -46,14 +51,20 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
private final ConcurrentLinkedQueue<Thread> _threads=new ConcurrentLinkedQueue<Thread>();
private final Object _joinLock = new Object();
private BlockingQueue<Runnable> _jobs;
private String _name;
private int _maxIdleTimeMs=60000;
private int _maxThreads;
private int _minThreads;
private int _maxQueued=-1;
private int _priority=Thread.NORM_PRIORITY;
private boolean _daemon=false;
private int _maxStopTime=100;
private boolean _detailedDump=false;
/* ------------------------------------------------------------------- */
@ -312,6 +323,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
* @return minimum number of threads.
*/
@Override
@ManagedAttribute("minimum number of threads in the pool")
public int getMinThreads()
{
return _minThreads;
@ -321,6 +333,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
/**
* @return The name of the BoundedThreadPool.
*/
@ManagedAttribute("name of the thread pool")
public String getName()
{
return _name;
@ -330,6 +343,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
/** Get the priority of the pool threads.
* @return the priority of the pool threads.
*/
@ManagedAttribute("priority of threads in the pool")
public int getThreadsPriority()
{
return _priority;
@ -339,12 +353,14 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
/**
* Delegated to the named or anonymous Pool.
*/
@ManagedAttribute("thead pool using a daemon thread")
public boolean isDaemon()
{
return _daemon;
}
/* ------------------------------------------------------------ */
@ManagedAttribute("full stack detail on dump output")
public boolean isDetailedDump()
{
return _detailedDump;
@ -471,6 +487,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
/* ------------------------------------------------------------ */
@Override
@ManagedOperation("dump thread state")
public String dump()
{
return AggregateLifeCycle.dump(this);
@ -658,7 +675,8 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
* @param id The thread ID to interrupt.
* @return true if the thread was found and interrupted.
*/
public boolean interruptThread(long id)
@ManagedOperation("interrupt a pool thread")
public boolean interruptThread(@Name("id") long id)
{
for (Thread thread: _threads)
{
@ -676,7 +694,8 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
* @param id The thread ID to interrupt.
* @return true if the thread was found and interrupted.
*/
public String dumpThread(long id)
@ManagedOperation("dump a pool thread stack")
public String dumpThread(@Name("id") long id)
{
for (Thread thread: _threads)
{

View File

@ -15,6 +15,8 @@ package org.eclipse.jetty.util.thread;
import java.util.concurrent.Executor;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.LifeCycle;
/* ------------------------------------------------------------ */
@ -22,6 +24,7 @@ import org.eclipse.jetty.util.component.LifeCycle;
*
*
*/
@ManagedObject("Pool of Threads")
public interface ThreadPool extends Executor
{
/* ------------------------------------------------------------ */
@ -41,18 +44,21 @@ public interface ThreadPool extends Executor
/**
* @return The total number of threads currently in the pool
*/
@ManagedAttribute("number of threads in pool")
public int getThreads();
/* ------------------------------------------------------------ */
/**
* @return The number of idle threads in the pool
*/
@ManagedAttribute("number of idle threads in pool")
public int getIdleThreads();
/* ------------------------------------------------------------ */
/**
* @return True if the pool is low on threads
*/
@ManagedAttribute("indicates the pool is low on available threads")
public boolean isLowOnThreads();