Fields Summary |
---|
protected final PerMBeanCache | mCache |
private boolean | mCheckedForInvariantMBeanInfo |
protected static final String | DEBUG_ID |
private static final String | CREATE |
private static final String | GET |
private static final String | MAP_SUFFIX |
private static final String | SET_SUFFIX |
private static final String | LIST_SUFFIX |
private static final String | OBJECT_NAME_MAP_SUFFIX |
private static final String | OBJECT_NAME_SET_SUFFIX |
private static final String | OBJECT_NAME_LIST_SUFFIX |
private static final String | OBJECT_NAME_SUFFIX |
private static final String | CONTAINEE_J2EE_TYPES |
private static final String | CONTAINER |
private static final String | DOMAIN_ROOT |
private static final String | MBEAN_INFO |
private static final String | ATTRIBUTE_NAMES |
private static final String | J2EE_NAME |
private static final String | J2EE_TYPE |
public static final String | ADD_NOTIFICATION_LISTENER |
public static final String | REMOVE_NOTIFICATION_LISTENER |
private static final String | QUERY |
private static final String | STRING |
private static final String[] | EMPTY_SIG |
private static final String[] | STRING_SIG |
private static final String[] | STRING2_SIG |
private static final String | GET_SINGLETON_CONTAINEE |
private static final String | GET_CONTAINEE |
private static final String | GET_SINGLETON_CONTAINEE_OBJECT_NAME |
private static final String[] | GET_SINGLETON_CONTAINEE_OBJECT_NAME_SIG1 |
private static final String[] | GET_SINGLETON_CONTAINEE_OBJECT_NAME_SIG2 |
private static final String[] | GET_OBJECT_NAMES_SIG_EMPTY |
private static final String[] | GET_OBJECT_NAMES_SIG_STRING |
private static final Map | EMPTY_String_AMX |
private static final Class[] | NOTIFICATION_LISTENER_SIG1 |
private static final Class[] | NOTIFICATION_LISTENER_SIG2 |
private static final Set | CACHED_ATTRIBUTE_NAMESThe values of these Attributes are cached forever. Proxies are handled separately
because the API will be getXXX() wherease the Attribute name will be XXXObjectName. |
private static final String | GET_MBEAN_INFO |
private static final String | GET_J2EE_TYPE |
private static final String | GET_J2EE_NAME |
private static final String | GET_ATTRIBUTE_NAMES |
private static final String | GET_CONTAINER |
private static final String | GET_EXTRA |
private static final String | GET_ALL_ATTRIBUTES |
private static final String | GET_DOMAIN_ROOT |
private static final String | GET_OBJECT_NAME |
private static final Set | SPECIAL_METHOD_NAMESThese Attributes are handled specially. For example, J2EE_TYPE and
J2EE_NAME are part of the ObjectName. |
Methods Summary |
---|
private java.lang.String | _getInterfaceName()
return( (String)getCachedAttributeValue( AMXAttributes.ATTR_INTERFACE_NAME ) );
|
private synchronized javax.management.MBeanInfo | _getMBeanInfo()
MBeanInfo mbeanInfo = null;
if ( ! mCheckedForInvariantMBeanInfo )
{
mCheckedForInvariantMBeanInfo = true;
// see if target has the boolean which tells us if caching is OK
try
{
final Boolean cacheIt = (Boolean)
getAttribute( AMXAttributes.ATTR_MBEAN_INFO_IS_INVARIANT );
setMBeanInfoIsInvariant( cacheIt.booleanValue() );
cacheMBeanInfo( cacheIt.booleanValue() );
}
catch( Exception e )
{
// not found, or other problem, have to assume we can't cache it
cacheMBeanInfo( false );
setMBeanInfoIsInvariant( false );
}
}
mbeanInfo = getMBeanInfo( getCacheMBeanInfo() );
return( mbeanInfo );
|
protected java.lang.Object | _invoke(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)
debugMethod( method.getName(), args );
// clients can retain proxies that go invalid if their corresponding
// MBeans are removed.
if ( ! targetIsValid() )
{
throw new InstanceNotFoundException( getTargetObjectName().toString() );
}
Object result = null;
final String methodName = method.getName();
final int numArgs = args == null ? 0 : args.length;
boolean handled = false;
if ( SPECIAL_METHOD_NAMES.contains( methodName ) )
{
handled = true;
result = handleSpecialMethod( myProxy, method, args );
}
else if ( JMXUtil.isIsOrGetter( method ) )
{
assert( ! handled );
final String attrName = JMXUtil.getAttributeName( method );
if ( CACHED_ATTRIBUTE_NAMES.contains( attrName ) )
{
result = getCachedAttributeValue( attrName );
handled = true;
}
}
if ( ! handled )
{
if ( isSingleProxyGetter( method, numArgs) )
{
result = invokeSingleProxyGetter( myProxy, method, args );
}
else if ( isProxySetGetter( method, numArgs ) )
{
result = invokeProxySetGetter( myProxy, method, args );
}
else if ( isProxyMapGetter( method, numArgs ) )
{
result = invokeProxyMapGetter( myProxy, method, args );
}
else if ( isProxyListGetter( method, numArgs ) )
{
result = invokeProxyListGetter( myProxy, method, args );
}
else if ( isProxyCreator( method ) )
{
result = invokeProxyCreator( method, args );
}
else
{
result = super.invoke( myProxy, method, args );
}
}
if ( getDebug() )
{
debug( AMXDebug.methodString( methodName, args ) +
" => " + toString( result ) );
}
return( result );
|
protected void | addNotificationListener(java.lang.Object[] args)
final NotificationListener listener = (NotificationListener)args[ 0 ];
final NotificationFilter filter = (NotificationFilter)(args.length <= 1 ? null : args[ 1 ]);
final Object handback = args.length <= 1 ? null : args[ 2 ];
getConnection().addNotificationListener(
getTargetObjectName(), listener, filter, handback );
|
protected void | cacheAttribute(javax.management.Attribute attr)
mCache.cacheAttribute( attr );
|
private void | cacheProxy(java.lang.String key, com.sun.appserv.management.base.AMX proxy)A proxy cached by ObjectName can safely be shared globally, since the
ObjectNames are unique per connection. But non-ObjectName keys may
actually conflict from like MBeans
mCache.cacheItem( key, proxy );
|
protected static java.lang.String | convertMethodName(java.lang.String srcName, java.lang.String srcSuffix, java.lang.String resultSuffix)
if ( ! srcName.endsWith( srcSuffix ) )
{
throw new IllegalArgumentException( srcName + " does not end with " + srcSuffix );
}
final String baseName = srcName.substring( 0, srcName.lastIndexOf( srcSuffix ) );
return( baseName + resultSuffix );
|
protected synchronized com.sun.appserv.management.base.AMX | createProxy(javax.management.ObjectName objectName)
return( getProxyFactory().getProxy( objectName, AMX.class ) );
|
public java.util.Map | getAllAttributes()
Map<String,Object> result = Collections.emptyMap();
try
{
final String[] names = getAttributeNames();
final AttributeList attrs = getAttributes(names );
result = JMXUtil.attributeListToValueMap( attrs );
}
catch( Exception e )
{
throw new RuntimeException( e );
}
return( result );
|
public java.lang.String[] | getAttributeNames()
final String attrName = "AttributeNames";
Attribute attr = null;
try
{
attr = getCachedAttribute( attrName );
}
catch( AttributeNotFoundException e )
{
// it's supposed to be there!
attr = null;
}
catch( Exception e )
{
throw new RuntimeException( e );
}
String[] names = null;
if ( attr == null )
{
final MBeanInfo mbeanInfo = getMBeanInfo();
names = JMXUtil.getAttributeNames( mbeanInfo.getAttributes() );
if ( getMBeanInfoIsInvariant() )
{
// only cache if MBeanInfo is invariant
cacheAttribute( new Attribute( attrName, names ) );
}
}
else
{
names = (String[])attr.getValue();
}
return( names );
|
protected javax.management.Attribute | getCachedAttribute(java.lang.String attrName)Get an Attribute, first from the cache, but if not in the cache, fetching a new
copy, then caching it. This routine should only be used on invariant Attributes.
Attribute attr = mCache.getCachedAttribute( attrName );
if ( attr == null )
{
final MBeanServerConnection conn = getConnection();
final Object value = getConnection().getAttribute( getTargetObjectName(), attrName );
attr = new Attribute( attrName, value );
mCache.cacheAttribute( attr );
}
return( attr );
|
protected java.lang.Object | getCachedAttributeValue(java.lang.String attrName)
final Attribute attr = getCachedAttribute( attrName );
assert( attr != null ) : "getCachedAttributeValue: null for " + attrName;
return( attr == null ? null : attr.getValue() );
|
private com.sun.appserv.management.base.AMX | getCachedProxy(java.lang.Object key)All proxies cached by ObjectName get cached by the ProxyFactory.
Proxies keyed by other values may not be unique and need to be cached
as items in mCache.
AMX proxy = null;
if ( key instanceof ObjectName )
{
proxy = getProxyFactory().getProxy( (ObjectName)key, AMX.class );
}
else
{
proxy = Util.asAMX(mCache.getCachedItem( key ) );
}
if ( proxy != null )
{
final AMXProxyHandler handler = (AMXProxyHandler)Proxy.getInvocationHandler( proxy );
if ( ! handler.targetIsValid() )
{
debug( "removing cached proxy for key: ", key );
mCache.remove( key );
proxy = null;
}
}
return( proxy );
|
synchronized com.sun.appserv.management.base.Container | getContainer(com.sun.appserv.management.base.AMX myProxy)Get the proxy which is the parent of this one.
Container containerProxy = null;
if ( ! ( myProxy instanceof DomainRoot ) )
{
final ObjectName objectName = getContainerObjectName();
// a few MBeans propogated from other instances, such as Logging,
// do not have a Container.
if ( objectName != null )
{
containerProxy =
getProxyFactory().getProxy( objectName, Container.class );
}
}
return( containerProxy );
|
protected javax.management.ObjectName | getContainerObjectName()
return( (ObjectName)getCachedAttributeValue( AMXAttributes.ATTR_CONTAINER_OBJECT_NAME ) );
|
protected java.lang.String | getDebugID()
return DEBUG_ID;
|
private final com.sun.appserv.management.DomainRoot | getDomainRoot()Get the proxy corresponding to the DomainMBean for the domain to which
this proxy corresponds.
return( getProxyFactory().getDomainRoot( ) );
|
public java.lang.String | getInterfaceName()
try
{
return( _getInterfaceName() );
}
catch( Exception e )
{
throw new RuntimeException( e );
}
|
private java.lang.String | getJ2EEType(java.lang.Class c)
return( (String)ClassUtil.getFieldValue( c, "J2EE_TYPE" ) );
|
public javax.management.MBeanInfo | getMBeanInfo()
try
{
return( _getMBeanInfo() );
}
catch( Exception e )
{
throw new RuntimeException( e );
}
|
public javax.management.ObjectName | getObjectName()
return( getTargetObjectName() );
|
public com.sun.appserv.management.client.ProxyFactory | getProxyFactory()
return( ProxyFactory.getInstance( getConnectionSource() ) );
|
protected java.lang.Class | getProxyInterface(javax.management.ObjectName objectName)
// by fetching a proxy this way, it may already exist, with an already-cached
// interface.
final AMX proxy = getProxyFactory().getProxy( objectName, AMX.class );
final Class proxyInterface = ClassUtil.getClassFromName( Util.getExtra( proxy ).getInterfaceName() );
return( proxyInterface );
|
private static java.lang.String[] | getStringSig(java.lang.reflect.Method method)
final Class[] sig = method.getParameterTypes();
final String[] stringSig = ClassUtil.classnamesFromSignature( sig );
return( stringSig );
|
private java.lang.Object | handleSpecialMethod(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)Handle a "special" method; one that requires special handling and/or can
be dealt with on the client side and/or can be handled most efficiently
by special-casing it.
final String methodName = method.getName();
final int numArgs = args == null ? 0 : args.length;
Object result = null;
boolean handled = true;
if ( numArgs == 0 )
{
if ( methodName.equals( GET_CONTAINER ) )
{
result = getContainer( Util.asAMX(myProxy) );
}
else if ( methodName.equals( GET_EXTRA ) )
{
assert( this instanceof Extra );
result = this;
}
else if ( methodName.equals( GET_OBJECT_NAME ) )
{
result = getTargetObjectName();
}
else if ( methodName.equals( GET_DOMAIN_ROOT ) )
{
result = getDomainRoot( );
}
else if ( methodName.equals( GET_ATTRIBUTE_NAMES ) )
{
result = getAttributeNames();
}
else if ( methodName.equals( GET_J2EE_TYPE ) )
{
result = Util.getJ2EEType( getTargetObjectName() );
}
else if ( methodName.equals( GET_J2EE_NAME ) )
{
result = Util.getName( getTargetObjectName() );
}
else if ( methodName.equals( GET_ALL_ATTRIBUTES ) )
{
result = getAllAttributes();
}
else
{
handled = false;
}
}
else if ( numArgs == 1 && methodName.equals( "equals" ) )
{
return equals( args[ 0 ] );
}
else
{
final Class[] signature = method.getParameterTypes();
if ( methodName.equals( ADD_NOTIFICATION_LISTENER ) &&
( ClassUtil.sigsEqual( NOTIFICATION_LISTENER_SIG1, signature ) ||
ClassUtil.sigsEqual( NOTIFICATION_LISTENER_SIG2, signature ) )
)
{
addNotificationListener( args );
}
else if ( methodName.equals( REMOVE_NOTIFICATION_LISTENER ) &&
( ClassUtil.sigsEqual( NOTIFICATION_LISTENER_SIG1, signature ) ||
ClassUtil.sigsEqual( NOTIFICATION_LISTENER_SIG2, signature ) )
)
{
removeNotificationListener( args );
}
else
{
handled = false;
}
}
if ( ! handled )
{
assert( false );
throw new RuntimeException( "unknown method: " + method );
}
return( result );
|
public final java.lang.Object | invoke(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)
try
{
final Object result = _invoke( myProxy, method, args );
assert( result == null ||
ClassUtil.IsPrimitiveClass( method.getReturnType() ) ||
method.getReturnType().isAssignableFrom( result.getClass() ) ) :
method.getName() + ": result of type " + result.getClass().getName() +
" not assignable to " + method.getReturnType().getName() + ", " +
"interfaces: " + toString( result.getClass().getInterfaces() +
", ObjectName = " + JMXUtil.toString( getTargetObjectName() ) );
return result;
}
catch( IOException e )
{
getProxyFactory().checkConnection();
throw e;
}
catch( InstanceNotFoundException e )
{
checkValid();
throw e;
}
|
com.sun.appserv.management.base.AMX | invokeProxyCreator(java.lang.reflect.Method method, java.lang.Object[] args)
final String methodName = method.getName();
final String[] stringSig = getStringSig( method );
final ObjectName objectName = (ObjectName)invokeTarget( methodName, args, stringSig );
assert( objectName != null ) :
"received null ObjectName from: " + methodName + " on target " + getTargetObjectName();
final AMX proxy = createProxy( objectName );
assert( getProxyFactory().getProxy( Util.getExtra( proxy ).getObjectName(),AMX.class, false ) == proxy );
return( proxy );
|
private java.util.List | invokeProxyListGetter(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)
// get the List<ObjectName> from the MBean
final String remoteNAME =
convertMethodName( method.getName(), LIST_SUFFIX, OBJECT_NAME_LIST_SUFFIX );
final List<ObjectName> objectNames = TypeCast.asList(
invokeTarget( remoteNAME, args, getStringSig( method ) ) );
final List<AMX> result = getProxyFactory().toProxyList( objectNames );
return( result );
|
private java.util.Map | invokeProxyMapGetter(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)
final int argCount = args == null ? 0 : args.length;
// turn getXXXObjectNameMap() into getXXXMap()
final String methodName = method.getName();
final String getObjectNameMapName =
convertMethodName( methodName, MAP_SUFFIX, OBJECT_NAME_MAP_SUFFIX );
final MBeanServerConnection conn = getConnection();
final Map<String,?> m = TypeCast.asMap(
invokeTarget( getObjectNameMapName, args, getStringSig( method ) ) );
assert( m != null ) :
"mbean " + getTargetObjectName() + " returned null Map for " + getObjectNameMapName;
/*
The Map may be either a:
- Map of <name>=<ObjectName>
- Map of <j2eeType>=<Map of <name>=<ObjectName>
*/
Map<String,?> result = null;
if ( m.keySet().size() != 0 )
{
final ProxyFactory proxyFactory = getProxyFactory();
final Object firstValue = m.values().iterator().next();
if ( firstValue instanceof ObjectName )
{
// it's <name>=<ObjectName>
final Map<String,ObjectName> onm = TypeCast.asMap( m );
final Map<String,AMX> proxyMap = proxyFactory.toProxyMap( onm );
result = proxyMap;
}
else if ( firstValue instanceof Map )
{
final Map<String,Map<String,ObjectName>> objectNameMaps = TypeCast.asMap( m );
final Map<String,Map<String,AMX>> proxyMaps = new HashMap<String,Map<String,AMX>>();
for ( final String j2eeType : objectNameMaps.keySet() )
{
final Map<String,ObjectName> objectNameMap = objectNameMaps.get( j2eeType );
final Map<String,AMX> proxyMap = proxyFactory.toProxyMap( objectNameMap );
proxyMaps.put( j2eeType, proxyMap );
}
result = proxyMaps;
}
else
{
throw new IllegalArgumentException();
}
}
else
{
result = EMPTY_String_AMX;
}
return( result );
|
private java.util.Set | invokeProxySetGetter(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)The method is one that requests a Set of Proxies. Create the proxies by asking the
target MBean for the ObjectNames. Then generate proxies of the appropriate type
for each resulting ObjectName.
assert( Set.class.isAssignableFrom( method.getReturnType() ) );
final String methodName = method.getName();
final String getObjectNamesName =
convertMethodName( methodName, SET_SUFFIX, OBJECT_NAME_SET_SUFFIX );
final MBeanServerConnection conn = getConnection();
final String[] stringSig = getStringSig( method );
// ask the MBean for an ObjectName corresponding to an id (name)
final Set<ObjectName> objectNames = TypeCast.asSet( invokeTarget( getObjectNamesName, args, stringSig ) );
final Set<AMX> proxies = getProxyFactory().toProxySet( objectNames );
return( proxies );
|
com.sun.appserv.management.base.AMX | invokeSingleProxyGetter(java.lang.Object myProxy, java.lang.reflect.Method method, java.lang.Object[] args)The method is one that requests a Proxy. Create the proxy by asking the
target MBean for the appropriate ObjectName. The resulting Proxy will implement
the interface given as the return type of the Method.
// use the methodName as the key for the cache
final String methodName = method.getName();
final int numArgs = (args == null) ? 0 : args.length;
final String argString = args == null ? "" : ArrayStringifier.stringify( args, "_" );
final String cacheKey = methodName + argString;
AMX proxy = getCachedProxy( cacheKey );
if ( proxy == null )
{
final Class returnClass = method.getReturnType();
ObjectName objectName = null;
final String j2eeType = getJ2EEType( returnClass );
if ( numArgs == 0 ) // of the form getXXX() eg getSSLConfig()
{
final String newMethodName = proxyGetterToObjectNameGetter( methodName );
objectName = (ObjectName) invokeTarget( newMethodName, null, EMPTY_SIG);
}
else if ( numArgs == 1 && args[ 0 ].getClass() == String.class )
{
final String newMethodName = proxyGetterToObjectNameGetter( methodName );
objectName = (ObjectName) invokeTarget( newMethodName, args, STRING_SIG );
}
else if ( (methodName.equals( GET_SINGLETON_CONTAINEE ) ||
methodName.equals( GET_CONTAINEE )) && numArgs == 2 )
{
// getContainee( j2eeType, name )
final String newMethodName = proxyGetterToObjectNameGetter( methodName );
objectName = (ObjectName)
invokeTarget( newMethodName, args, GET_SINGLETON_CONTAINEE_OBJECT_NAME_SIG2 );
}
else
{
getProxyLogger().warning( "Unknown form of proxy getter: " + method );
assert( false );
throw new IllegalArgumentException();
}
if ( objectName != null )
{
proxy = createProxy( objectName );
}
// the underlying object may not exist, this occurs normally sometimes
if ( proxy != null )
{
if ( cacheKey != null )
{
//debug( "CACHING: " + cacheKey + " => " + Util.getExtra( proxy ).getObjectName);
cacheProxy( cacheKey, proxy );
}
else
{
//debug( "NOT CACHING: " + Util.getExtra( proxy ).getObjectName);
}
}
else
{
getProxyLogger().fine( "invokeSingleProxyGetter: NULL ObjectName for: " +
methodName + "()" );
}
}
else
{
//debug( "FOUND CACHED using \"" + cacheKey + "\": " + Util.getExtra( proxy ).getObjectName);
}
return( proxy );
|
private java.lang.Object | invokeTarget(java.lang.String methodName, java.lang.Object[] args, java.lang.String[] sig)
final int numArgs = args == null ? 0 : args.length;
Object result = null;
if ( numArgs == 0 &&
methodName.startsWith( GET ) )
{
final String attributeName = StringUtil.stripPrefix( methodName, GET );
result = getConnection().getAttribute( getTargetObjectName(), attributeName );
}
else
{
result = getConnection().invoke( getTargetObjectName(), methodName, args, sig );
}
return result;
|
protected static boolean | isProxyCreator(java.lang.reflect.Method method)
final String methodName = method.getName();
return( methodName.startsWith( CREATE ) &&
AMX.class.isAssignableFrom( method.getReturnType() ) );
|
protected static boolean | isProxyListGetter(java.lang.reflect.Method method, int argCount)Return true if the method is one that is requesting a List of AMX object.
boolean isProxyListGetter = false;
final String name = method.getName();
if ( ( name.startsWith( GET ) || name.startsWith( QUERY ) ) &&
name.endsWith( LIST_SUFFIX ) &&
(! name.endsWith( OBJECT_NAME_LIST_SUFFIX )) &&
argCount <= 1 &&
List.class.isAssignableFrom( method.getReturnType() ) )
{
isProxyListGetter = true;
}
return( isProxyListGetter );
|
protected static boolean | isProxyMapGetter(java.lang.reflect.Method method, int argCount)Return true if the method is one that is requesting a Map of AMX object.
boolean isProxyMapGetter = false;
final String name = method.getName();
if ( name.startsWith( GET ) &&
name.endsWith( MAP_SUFFIX ) &&
(! name.endsWith( OBJECT_NAME_MAP_SUFFIX )) &&
argCount <= 1 &&
Map.class.isAssignableFrom( method.getReturnType() ) )
{
isProxyMapGetter = true;
}
return( isProxyMapGetter );
|
protected static boolean | isProxySetGetter(java.lang.reflect.Method method, int argCount)
boolean isProxySetGetter = false;
final String name = method.getName();
if ( ( name.startsWith( GET ) || name.startsWith( QUERY ) ) &&
name.endsWith( SET_SUFFIX ) &&
!name.endsWith( OBJECT_NAME_SET_SUFFIX ) &&
argCount <= 2 &&
Set.class.isAssignableFrom( method.getReturnType() ) )
{
isProxySetGetter = true;
}
return( isProxySetGetter );
|
protected static boolean | isSingleProxyGetter(java.lang.reflect.Method method, int argCount)Return true if the method is one that is requesting a single AMX object.
Such methods are client-side methods and do not operate on the target MBean.
boolean isProxyGetter = false;
final String name = method.getName();
if ( ( name.startsWith( GET ) || name.startsWith( QUERY ) ) &&
argCount <= 2 &&
AMX.class.isAssignableFrom( method.getReturnType() ) )
{
isProxyGetter = true;
}
return( isProxyGetter );
|
private static java.lang.String | proxyGetterToObjectNameGetter(java.lang.String methodName)
return( methodName + OBJECT_NAME_SUFFIX );
|
protected void | removeNotificationListener(java.lang.Object[] args)
final NotificationListener listener = (NotificationListener)args[ 0 ];
// important:
// this form removes the same listener registered with different filters and/or handbacks
if ( args.length == 1 )
{
getConnection().removeNotificationListener( getTargetObjectName(), listener );
}
else
{
final NotificationFilter filter = (NotificationFilter)args[ 1 ];
final Object handback = args[ 2 ];
getConnection().removeNotificationListener(
getTargetObjectName(), listener, filter, handback );
}
|
private static java.lang.String | toString(java.lang.Object o)
String result = o == null ? "null" : SmartStringifier.toString( o );
final int MAX_LENGTH = 256;
if ( result.length() > MAX_LENGTH )
{
result = result.substring( 0, MAX_LENGTH - 1 ) + "...";
}
return result;
|