Merge branch 'jetty-9' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project into jetty-9

This commit is contained in:
Joakim Erdfelt 2012-07-23 13:53:22 -07:00
commit 697d32beb4
11 changed files with 371 additions and 131 deletions

View File

@ -13,8 +13,10 @@
package org.eclipse.jetty.jmx;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@ -48,6 +50,8 @@ import javax.management.modelmbean.ModelMBean;
import org.eclipse.jetty.util.LazyList;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.annotation.Managed;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -224,69 +228,66 @@ public class ObjectMBean implements DynamicMBean
Object notifications=null;
// Find list of classes that can influence the mbean
Class o_class=_managed.getClass();
Class<?> o_class=_managed.getClass();
Object influences = findInfluences(null, _managed.getClass());
LOG.debug("Influence Count: " + LazyList.size(influences) );
// Set to record defined items
Set defined=new HashSet();
// Process Type Annotations
Managed primary = o_class.getAnnotation( Managed.class);
desc = primary.value();
// For each influence
for (int i=0;i<LazyList.size(influences);i++)
{
Class oClass = (Class)LazyList.get(influences, i);
Class<?> oClass = (Class<?>)LazyList.get(influences, i);
LOG.debug("Influence: " + oClass.getCanonicalName() );
Managed typeAnnotation = oClass.getAnnotation( Managed.class);
// look for a bundle defining methods
if (Object.class.equals(oClass))
oClass=ObjectMBean.class;
String pName = oClass.getPackage().getName();
String cName = oClass.getName().substring(pName.length() + 1);
String rName = pName.replace('.', '/') + "/jmx/" + cName+"-mbean";
try
LOG.debug("Influenced by: " + oClass.getCanonicalName() );
if ( typeAnnotation == null )
{
LOG.debug(rName);
ResourceBundle bundle = Loader.getResourceBundle(o_class, rName,true,Locale.getDefault());
// Extract meta data from bundle
Enumeration e = bundle.getKeys();
while (e.hasMoreElements())
LOG.debug("Annotations not found for: " + oClass.getCanonicalName() );
continue;
}
try
{
// Process Field Annotations
for ( Field field : oClass.getDeclaredFields())
{
String key = (String)e.nextElement();
String value = bundle.getString(key);
// Determin if key is for mbean , attribute or for operation
if (key.equals(cName))
LOG.debug("Checking: " + field.getName());
Managed fieldAnnotation = field.getAnnotation(Managed.class);
if ( fieldAnnotation != null )
{
// set the mbean description
if (desc==null)
desc=value;
LOG.debug("Field Annotation found for: " + field.getName() );
attributes=LazyList.add(attributes, defineAttribute(field.getName(), fieldAnnotation));
}
else if (key.indexOf('(')>0)
}
// Process Method Annotations
for ( Method method : oClass.getDeclaredMethods() )
{
Managed methodAnnotation = method.getAnnotation(Managed.class);
if ( methodAnnotation != null )
{
// define an operation
if (!defined.contains(key) && key.indexOf('[')<0)
if ( methodAnnotation.attribute() )
{
defined.add(key);
operations=LazyList.add(operations,defineOperation(key, value, bundle));
// 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=LazyList.add(attributes,defineAttribute(method.getName(),methodAnnotation));
}
}
else
{
// define an attribute
if (!defined.contains(key))
else
{
defined.add(key);
MBeanAttributeInfo info=defineAttribute(key, value);
if (info!=null)
attributes=LazyList.add(attributes,info);
LOG.debug("Method Annotation found for: " + method.getName() );
operations=LazyList.add(operations, defineOperation(method, methodAnnotation));
}
}
}
}
catch(MissingResourceException e)
{
@ -524,6 +525,8 @@ public class ObjectMBean implements DynamicMBean
/* ------------------------------------------------------------ */
/**
* TODO update to new behavior
*
* Define an attribute on the managed object. The meta data is defined by looking for standard
* getter and setter methods. Descriptions are obtained with a call to findDescription with the
* attribute name.
@ -538,31 +541,14 @@ public class ObjectMBean implements DynamicMBean
* </ul>
* the access is either "RW" or "RO".
*/
public MBeanAttributeInfo defineAttribute(String name, String metaData)
public MBeanAttributeInfo defineAttribute(String name, Managed fieldAnnotation)
{
String description = "";
boolean writable = true;
boolean onMBean = false;
boolean convert = false;
if (metaData!= null)
{
String[] tokens = metaData.split(":", 3);
for (int t=0;t<tokens.length-1;t++)
{
tokens[t]=tokens[t].trim();
if ("RO".equals(tokens[t]))
writable=false;
else
{
onMBean=("MMBean".equalsIgnoreCase(tokens[t]) || "MBean".equalsIgnoreCase(tokens[t]));
convert=("MMBean".equalsIgnoreCase(tokens[t]) || "MObject".equalsIgnoreCase(tokens[t]));
}
}
description=tokens[tokens.length-1];
}
//String name = field.getName();
String description = fieldAnnotation.value();
boolean writable = fieldAnnotation.readonly();
boolean onMBean = fieldAnnotation.proxied();
boolean convert = fieldAnnotation.managed();
String uName = name.substring(0, 1).toUpperCase() + name.substring(1);
Class oClass = onMBean ? this.getClass() : _managed.getClass();
@ -572,12 +558,35 @@ public class ObjectMBean implements DynamicMBean
Class type = null;
Method getter = null;
Method setter = null;
String declaredGetter = fieldAnnotation.getter();
String declaredSetter = fieldAnnotation.setter();
Method[] methods = oClass.getMethods();
for (int m = 0; m < methods.length; m++)
{
if ((methods[m].getModifiers() & Modifier.PUBLIC) == 0)
continue;
// Check if it is a declared getter
if (methods[m].getName().equals(declaredGetter) && 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();
LOG.debug("Declared Getter: " + declaredGetter);
}
// Look for a getter
if (methods[m].getName().equals("get" + uName) && methods[m].getParameterTypes().length == 0)
{
@ -612,8 +621,8 @@ public class ObjectMBean implements DynamicMBean
type = methods[m].getReturnType();
}
// look for a setter
if (writable && methods[m].getName().equals("set" + uName) && methods[m].getParameterTypes().length == 1)
// look for a declared setter
if (writable && methods[m].getName().equals(declaredSetter) && methods[m].getParameterTypes().length == 1)
{
if (setter != null)
{
@ -626,6 +635,24 @@ public class ObjectMBean implements DynamicMBean
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;
}
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];
}
}
@ -674,7 +701,7 @@ public class ObjectMBean implements DynamicMBean
}
catch (Exception e)
{
LOG.warn(name+": "+metaData, e);
LOG.warn(e);
throw new IllegalArgumentException(e.toString());
}
}
@ -682,6 +709,8 @@ public class ObjectMBean implements DynamicMBean
/* ------------------------------------------------------------ */
/**
* TODO update to new behavior
*
* Define an operation on the managed object. Defines an operation with parameters. Refection is
* used to determine find the method and it's return type. The description of the method is
* found with a call to findDescription on "name(signature)". The name and description of each
@ -693,77 +722,59 @@ public class ObjectMBean implements DynamicMBean
* the "Object","MBean", "MMBean" or "MObject" to indicate the method is on the object, the MBean or on the
* object but converted to an MBean reference, and impact is either "ACTION","INFO","ACTION_INFO" or "UNKNOWN".
*/
private MBeanOperationInfo defineOperation(String signature, String metaData, ResourceBundle bundle)
private MBeanOperationInfo defineOperation(Method method, Managed methodAnnotation)
{
String[] tokens=metaData.split(":",3);
int i=tokens.length-1;
String description=tokens[i--];
String impact_name = i<0?"UNKNOWN":tokens[i--].trim();
if (i==0)
tokens[0]=tokens[0].trim();
boolean onMBean= i==0 && ("MBean".equalsIgnoreCase(tokens[0])||"MMBean".equalsIgnoreCase(tokens[0]));
boolean convert= i==0 && ("MObject".equalsIgnoreCase(tokens[0])||"MMBean".equalsIgnoreCase(tokens[0]));
String description = methodAnnotation.value();
boolean onMBean = methodAnnotation.proxied();
boolean convert = methodAnnotation.managed();
String impactName = methodAnnotation.impact();
String signature = method.getName();
LOG.debug("defineOperation "+method.getName()+" "+onMBean+":"+impactName+":"+description);
if (LOG.isDebugEnabled())
LOG.debug("defineOperation "+signature+" "+onMBean+":"+impact_name+":"+description);
Class oClass = onMBean ? this.getClass() : _managed.getClass();
try
{
// Resolve the impact
int impact=MBeanOperationInfo.UNKNOWN;
if (impact_name==null || impact_name.equals("UNKNOWN"))
if (impactName==null || impactName.equals("UNKNOWN"))
impact=MBeanOperationInfo.UNKNOWN;
else if (impact_name.equals("ACTION"))
else if (impactName.equals("ACTION"))
impact=MBeanOperationInfo.ACTION;
else if (impact_name.equals("INFO"))
else if (impactName.equals("INFO"))
impact=MBeanOperationInfo.INFO;
else if (impact_name.equals("ACTION_INFO"))
else if (impactName.equals("ACTION_INFO"))
impact=MBeanOperationInfo.ACTION_INFO;
else
LOG.warn("Unknown impact '"+impact_name+"' for "+signature);
LOG.warn("Unknown impact '"+impactName+"' for "+signature);
// split the signature
String[] parts=signature.split("[\\(\\)]");
String method_name=parts[0];
String arguments=parts.length==2?parts[1]:null;
String[] args=arguments==null?new String[0]:arguments.split(" *, *");
Annotation[][] allParameterAnnotations = method.getParameterAnnotations();
Class<?>[] methodTypes = method.getParameterTypes();
MBeanParameterInfo[] pInfo = new MBeanParameterInfo[allParameterAnnotations.length];
// Check types and normalize signature.
Class[] types = new Class[args.length];
MBeanParameterInfo[] pInfo = new MBeanParameterInfo[args.length];
signature=method_name;
for (i = 0; i < args.length; i++)
for ( int i = 0 ; i < allParameterAnnotations.length ; ++i )
{
Class type = TypeUtil.fromName(args[i]);
if (type == null)
type = Thread.currentThread().getContextClassLoader().loadClass(args[i]);
types[i] = type;
args[i] = type.isPrimitive() ? TypeUtil.toName(type) : args[i];
signature+=(i>0?",":"(")+args[i];
Annotation[] parameterAnnotations = allParameterAnnotations[i];
for ( Annotation anno : parameterAnnotations )
{
if ( anno instanceof Name )
{
Name nameAnnotation = (Name) anno;
pInfo[i] = new MBeanParameterInfo(nameAnnotation.value(),methodTypes[i].getName(),nameAnnotation.description());
}
}
}
signature+=(i>0?")":"()");
// Build param infos
for (i = 0; i < args.length; i++)
{
String param_desc = bundle.getString(signature + "[" + i + "]");
parts=param_desc.split(" *: *",2);
if (LOG.isDebugEnabled())
LOG.debug(parts[0]+": "+parts[1]);
pInfo[i] = new MBeanParameterInfo(parts[0].trim(), args[i], parts[1].trim());
}
// build the operation info
Method method = oClass.getMethod(method_name, types);
Class returnClass = method.getReturnType();
_methods.put(signature, method);
if (convert)
_convert.add(signature);
return new MBeanOperationInfo(method_name, description, pInfo, returnClass.isPrimitive() ? TypeUtil.toName(returnClass) : (returnClass.getName()), impact);
return new MBeanOperationInfo(method.getName(), description, pInfo, returnClass.isPrimitive() ? TypeUtil.toName(returnClass) : (returnClass.getName()), impact);
}
catch (Exception e)
{

View File

@ -19,7 +19,7 @@ import org.eclipse.jetty.util.annotation.Name;
@Managed("Test the mbean stuff")
public class Derived extends Base implements Signature
{
@Managed("The full name of something")
@Managed(value="The full name of something", getter="getFullName", setter="setFullName")
String fname="Full Name";
public String getFullName()

View File

@ -51,12 +51,17 @@ 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());
}
/*
* 6 attributes from lifecycle and 1 from Derived
*/
Assert.assertEquals("attribute count does not match", 7, info.getAttributes().length);
Assert.assertEquals("attribute values does not match", "Full Name", mbean.getAttribute("fullName") );
Assert.assertEquals("attribute values does not match", "Full Name", mbean.getAttribute("fname") );
Assert.assertEquals("operation count does not match", 4, info.getOperations().length);
@ -82,8 +87,8 @@ public class ObjectMBeanTest
MBeanParameterInfo[] pinfos = opinfo.getSignature();
Assert.assertEquals("parameter description doesn't match", "A description of the argument.", pinfos[0].getDescription());
Assert.assertEquals("parameter name doesn't match", "argname", pinfos[0].getName());
Assert.assertEquals("parameter description doesn't match", "A description of the argument", pinfos[0].getDescription());
Assert.assertEquals("parameter name doesn't match", "doodle", pinfos[0].getName());
}
}

View File

@ -69,7 +69,6 @@ import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.Managed;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.component.AggregateLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log;
@ -1204,8 +1203,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/*
* @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
*/
@Managed("Remove context attribute")
public void removeAttribute( @Name(value = "name", description="attribute name") String name)
public void removeAttribute(String name)
{
checkManagedAttribute(name,null);
_attributes.removeAttribute(name);
@ -1218,8 +1216,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
*
* @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
*/
@Managed("Set context attribute")
public void setAttribute(@Name(value = "name", description="attribute name") String name, @Name(value = "value", description="attribute value") Object value)
public void setAttribute( String name, Object value)
{
checkManagedAttribute(name,value);
_attributes.setAttribute(name,value);

View File

@ -19,6 +19,8 @@ import java.util.Map;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.annotation.Managed;
import org.eclipse.jetty.util.annotation.Name;
public class ContextHandlerMBean extends AbstractHandlerMBean
{
@ -27,6 +29,7 @@ public class ContextHandlerMBean extends AbstractHandlerMBean
super(managedObject);
}
@Managed(value="Map of context attributes", readonly=true, attribute=true)
public Map getContextAttributes()
{
Map map = new HashMap();
@ -41,19 +44,22 @@ public class ContextHandlerMBean extends AbstractHandlerMBean
return map;
}
public void setContextAttribute(String name, Object value)
@Managed(value="Set context attribute", impact="ACTION")
public void setContextAttribute(@Name(value = "name", description="attribute name") String name, @Name(value = "value", description="attribute value") Object value)
{
Attributes attrs = ((ContextHandler)_managed).getAttributes();
attrs.setAttribute(name,value);
}
public void setContextAttribute(String name, String value)
@Managed(value="Set context attribute", impact="ACTION")
public void setContextAttribute(@Name(value = "name", description="attribute name") String name, @Name(value = "value", description="attribute value") String value)
{
Attributes attrs = ((ContextHandler)_managed).getAttributes();
attrs.setAttribute(name,value);
}
public void removeContextAttribute(String name)
@Managed(value="Remove context attribute", impact="ACTION")
public void removeContextAttribute(@Name(value = "name", description="attribute name") String name)
{
Attributes attrs = ((ContextHandler)_managed).getAttributes();
attrs.removeAttribute(name);

View File

@ -23,7 +23,77 @@ import java.lang.annotation.Target;
@Target( { ElementType.TYPE, ElementType.METHOD, ElementType.FIELD } )
public @interface Managed
{
/**
* Description of the Managed Object
*
* @return
*/
String value() default "Not Specified";
/**
* Is the managed field read-only?
*
* NOTE: applies to FIELD
*
* @return true if readonly
*/
boolean readonly() default false;
/**
* Is the managed field itself a Managed Object?
*
* NOTE: applies to FIELD
*
* @return true if the target is a Managed Object
*/
boolean managed() default false;
/**
* Does the managed field or method exist on a proxy object?
*
* NOTE: applies to FIELD and METHOD
*
* @return true if a proxy object is involved
*/
boolean proxied() default false;
/**
* The impact of an operation.
*
* NOTE: Valid values are UNKNOWN, ACTION, INFO, ACTION_INFO
*
* NOTE: applies to METHOD
*
* @return String representing the impact of the operation
*/
String impact() default "UNKNOWN";
/**
* If is a field references a getter that doesn't conform to standards for discovery
* it can be set here.
*
* NOTE: applies to FIELD
*
* @return the full name of the getter in question
*/
String getter() default "";
/**
* If is a field references a setter that doesn't conform to standards for discovery
* it can be set here.
*
* NOTE: applies to FIELD
*
* @return the full name of the setter in question
*/
String setter() default "";
/**
* Treat method as an attribute and not an operation
*
* NOTE: applies to METHOD
*
* @return true of the method should be treating as an attribute
*/
boolean attribute() default false;
}

View File

@ -0,0 +1,71 @@
package org.eclipse.jetty.util.annotation;
//========================================================================
//Copyright 2011-2012 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//All rights reserved. This program and the accompanying materials
//are made available under the terms of the Eclipse Public License v1.0
//and Apache License v2.0 which accompanies this distribution.
//The Eclipse Public License is available at
//http://www.eclipse.org/legal/epl-v10.html
//The Apache License v2.0 is available at
//http://www.opensource.org/licenses/apache2.0.php
//You may elect to redistribute this code under either of these licenses.
//========================================================================
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target( { ElementType.METHOD, ElementType.FIELD } )
public @interface ManagedAttribute
{
/**
* Description of the Managed Object
*
* @return
*/
String value() default "Not Specified";
/**
* Is the managed field read-only?
*
* @return true if readonly
*/
boolean readonly() default false;
/**
* Is the managed field itself a Managed Object?
*
* @return true if the target is a Managed Object
*/
boolean managed() default false;
/**
* Does the managed field exist on a proxy object?
*
*
* @return true if a proxy object is involved
*/
boolean proxied() default false;
/**
* If is a field references a getter that doesn't conform to standards for discovery
* it can be set here.
*
* @return the full name of the getter in question
*/
String getter() default "";
/**
* If is a field references a setter that doesn't conform to standards for discovery
* it can be set here.
*
* @return the full name of the setter in question
*/
String setter() default "";
}

View File

@ -0,0 +1,21 @@
package org.eclipse.jetty.util.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target( { ElementType.TYPE, ElementType.METHOD, ElementType.FIELD } )
public @interface ManagedObject
{
/**
* Description of the Managed Object
*
* @return
*/
String value() default "Not Specified";
}

View File

@ -0,0 +1,45 @@
package org.eclipse.jetty.util.annotation;
//========================================================================
//Copyright 2011-2012 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//All rights reserved. This program and the accompanying materials
//are made available under the terms of the Eclipse Public License v1.0
//and Apache License v2.0 which accompanies this distribution.
//The Eclipse Public License is available at
//http://www.eclipse.org/legal/epl-v10.html
//The Apache License v2.0 is available at
//http://www.opensource.org/licenses/apache2.0.php
//You may elect to redistribute this code under either of these licenses.
//========================================================================
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target( { ElementType.METHOD } )
public @interface ManagedOperation
{
/**
* Description of the Managed Object
*
* @return
*/
String value() default "Not Specified";
/**
* The impact of an operation.
*
* NOTE: Valid values are UNKNOWN, ACTION, INFO, ACTION_INFO
*
* NOTE: applies to METHOD
*
* @return String representing the impact of the operation
*/
String impact() default "UNKNOWN";
}

View File

@ -15,6 +15,7 @@ package org.eclipse.jetty.util.component;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jetty.util.annotation.Managed;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -23,14 +24,22 @@ import org.eclipse.jetty.util.log.Logger;
*
*
*/
@Managed("Abstract Implementation of LifeCycle")
public abstract class AbstractLifeCycle implements LifeCycle
{
private static final Logger LOG = Log.getLogger(AbstractLifeCycle.class);
@Managed(value="instance is stopped", readonly=true, getter="isStopped")
public static final String STOPPED="STOPPED";
@Managed(value="instance is failed", readonly=true, getter="isFailed")
public static final String FAILED="FAILED";
@Managed(value="instance is starting", readonly=true, getter="isStarting")
public static final String STARTING="STARTING";
@Managed(value="instance is started", readonly=true, getter="isStarted")
public static final String STARTED="STARTED";
@Managed(value="instance is stopping", readonly=true, getter="isStopping")
public static final String STOPPING="STOPPING";
@Managed(value="instance is running", readonly=true, getter="isRunning")
public static final String RUNNING="RUNNING";
private final CopyOnWriteArrayList<LifeCycle.Listener> _listeners=new CopyOnWriteArrayList<LifeCycle.Listener>();

View File

@ -15,6 +15,8 @@ package org.eclipse.jetty.util.component;
import java.util.EventListener;
import org.eclipse.jetty.util.annotation.Managed;
/* ------------------------------------------------------------ */
/**
* The lifecycle interface for generic components.
@ -24,6 +26,7 @@ import java.util.EventListener;
*
*
*/
@Managed("Lifecycle Interface for startable components")
public interface LifeCycle
{
/* ------------------------------------------------------------ */
@ -34,6 +37,7 @@ public interface LifeCycle
* @see #stop()
* @see #isFailed()
*/
@Managed("Starts the instance")
public void start()
throws Exception;
@ -47,6 +51,7 @@ public interface LifeCycle
* @see #start()
* @see #isFailed()
*/
@Managed("Stops the instance")
public void stop()
throws Exception;