/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
/*
* $Header: /cvs/glassfish/admin-cli/cli-api/src/java/com/sun/cli/jmx/test/CLISupportTestee.java,v 1.4 2007/05/05 05:24:53 tcfujii Exp $
* $Revision: 1.4 $
* $Date: 2007/05/05 05:24:53 $
*/
package com.sun.cli.jmx.test;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.ArrayList;
import javax.management.*;
import com.sun.cli.util.ArrayConversion;
import com.sun.cli.util.ClassUtil;
import com.sun.cli.util.stringifier.ArrayStringifier;
import com.sun.cli.util.stringifier.SmartStringifier;
import com.sun.cli.jmx.util.InvokeHelper;
/*
A DynamicMBean used as a target for testing CLI
*/
public final class CLISupportTestee implements DynamicMBean
{
final static String VIRTUAL_OPERATION_NAME = "virtualTest";
final static String D = ","; // delimiter
private void
p( Object o )
{
System.out.println( o.toString() );
}
final InvokeHelper mInvokeHelper;
public
CLISupportTestee()
{
mInvokeHelper = new InvokeHelper( this );
}
//-----------------------------------------------------------------------------
public String []
virtualTest()
{
return( new String [ 0 ] );
}
public String []
testFoo( long [][] p1 )
{
return( new String [ ] { "[[C", "char" } );
}
//-----------------------------------------------------------------------------
public void
testNamed( java.util.Properties props )
{
}
public void
testNamed( String p1)
{
}
public void
testNamed( String p1, String p2 )
{
}
public void
testNamed( String p1, String p2, String p3)
{
}
public void
testNamed( String p1, String p2, String p3, Properties p4)
{
}
//-----------------------------------------------------------------------------
public void
testPropertiesOnly( Properties p1 )
{
}
public void
testProperties1Arg( String p1, Properties p2 )
{
}
public void
testProperties2Args( String p1, Properties p2, String p3)
{
}
//-----------------------------------------------------------------------------
private MBeanInfo mMBeanInfo = null;
public MBeanParameterInfo []
createMBeanParameterInfos( Method m)
{
final Class [] parameterClasses = m.getParameterTypes();
final int numParams = Array.getLength( parameterClasses );
final MBeanParameterInfo infos [] = new MBeanParameterInfo[ numParams ];
for( int i = 0; i < numParams; ++i )
{
// use parameter names of p1, p2, p3, etc
final String parameterName = "p" + (i+1);
final MBeanParameterInfo info =
new MBeanParameterInfo( parameterName,
parameterClasses[ i ].getName(),
"parameter " + i + 1
);
infos[ i ] = info;
}
return( infos );
}
public MBeanOperationInfo []
createMBeanOperationInfos()
{
final Method [] allMethods = this.getClass().getDeclaredMethods();
final ArrayList exportMethods = new ArrayList();
final int allCount = Array.getLength( allMethods );
for( int i = 0; i < allCount; ++i )
{
final Method m = allMethods[ i ];
final String name = m.getName();
if ( name.startsWith( "test" ) )
{
final String description = "tests '" + name + "' operation";
final MBeanParameterInfo parameterInfo [] = createMBeanParameterInfos( m );
// our generic invoker will return the same type of result for each--
// the signature that was invoked
// final String returnTypeString = m.getReturnType().getName();
final String returnTypeString = String [].class.getName();
final MBeanOperationInfo info = new MBeanOperationInfo( name,
description,
parameterInfo,
returnTypeString,
MBeanOperationInfo.INFO );
exportMethods.add( info );
}
}
// add the virtual methods
final MBeanOperationInfo [] virtualOperations = createVirtualOperationInfos();
for( int i = 0; i < Array.getLength( virtualOperations ); ++i )
{
exportMethods.add( virtualOperations[ i ] );
}
MBeanOperationInfo [] infos = new MBeanOperationInfo[ exportMethods.size() ];
infos = (MBeanOperationInfo [])exportMethods.toArray( infos );
return( infos );
}
/*
All the base types we support
*/
private final static Class [] BASE_CLASSES =
{
char.class,
Character.class,
boolean.class,
Boolean.class,
short.class,
Short.class,
int.class,
Integer.class,
long.class,
Long.class,
float.class,
Float.class,
double.class,
Double.class,
Object.class,
String.class,
Properties.class,
Number.class,
java.math.BigInteger.class,
java.math.BigDecimal.class,
java.net.URI.class,
java.net.URL.class
};
private final static int NUM_BASE_CLASSES = Array.getLength( BASE_CLASSES );
public Class []
getSupportedClassList()
{
ArrayList classes = new ArrayList();
for( int i = 0; i < NUM_BASE_CLASSES; ++i )
{
Class derivedClass = BASE_CLASSES[ i ];
classes.add( derivedClass );
if ( derivedClass == Properties.class )
continue;
// 1D array
derivedClass = Array.newInstance( derivedClass, 0 ).getClass();
classes.add( derivedClass );
// 2D array
derivedClass = Array.newInstance( derivedClass, 0 ).getClass();
classes.add( derivedClass );
// we support any dimension arryas, but 3 is probably excessive from
// a testing standpoint
/*
// 3D array
derivedClass = Array.newInstance( derivedClass, 0 ).getClass();
classes.add( derivedClass );
*/
}
Class [] result = new Class[ classes.size() ];
classes.toArray( result );
return( result );
}
public MBeanOperationInfo
createVirtualOperationInfo( String operationName, Class [] argClasses )
{
final int numArgs = Array.getLength( argClasses );
// create a method for each supported class
final ArrayList paramInfos = new ArrayList();
for( int i = 0; i < numArgs; ++i )
{
final Class theClass = argClasses[ i ];
// create single parameter with name of "pX", where X is the index of the param 1,2,3, etc
final String parameterName = "p" + (i + 1);
final String parameterDescription = "parameter " + (i+1);
final MBeanParameterInfo param = new MBeanParameterInfo( parameterName, theClass.getName(), parameterDescription );
paramInfos.add( param );
}
MBeanParameterInfo [] infos = new MBeanParameterInfo [ paramInfos.size() ];
paramInfos.toArray( infos );
// create operation with return type of String [] (which will return the signature)
final String returnTypeString = String [].class.getName();
final String description = "virtual operation";
final MBeanOperationInfo info = new MBeanOperationInfo( operationName,
description,
infos,
returnTypeString,
MBeanOperationInfo.INFO );
return( info );
}
public MBeanOperationInfo []
createVirtualOperationInfos()
{
final String operationName = VIRTUAL_OPERATION_NAME;
ArrayList ops = new ArrayList();
/* create a method for each supported class consisting of a single parameter
*/
final Class [] classes = getSupportedClassList();
final int numClasses = classes.length;
for( int i = 0; i < numClasses; ++i )
{
final Class [] classList = new Class [] { classes[ i ] };
final MBeanOperationInfo info = createVirtualOperationInfo( operationName, classList );
ops.add( info );
}
// for each primitive type, create a signature with 3 parameters, each of which can vary between
// the primitive type and the Object form.
for( int i = 0; i < numClasses; ++i )
{
final Class theClass = classes[ i ];
if ( ! ClassUtil.IsPrimitiveClass( theClass ) )
continue;
final Class objectClass = ClassUtil.PrimitiveClassToObjectClass( theClass );
// generate all 8 variants
final Class [] both = new Class [] { theClass, objectClass };
for( int p1 = 0; p1 < 2; ++p1 )
{
for( int p2 = 0; p2 < 2; ++p2 )
{
for( int p3 = 0; p3 < 2; ++p3 )
{
final Class [] classList = new Class [] { both[ p1 ], both[ p2 ], both[ p3 ] };
MBeanOperationInfo info = createVirtualOperationInfo( operationName, classList );
ops.add( info );
}
}
}
}
// Create all method signature for depth of 2 with all variants of all supported types
// CAUTION: this generates (num classes)^2 operations, about 7000 or so.
final int depth = 2;
final int numCombinations = numClasses * numClasses; // must match depth
for( int i = 0; i < numCombinations; ++i )
{
final Class [] classList = new Class [ depth ];
// number of assignments must match depth
classList[ 0 ] = classes[ i % numClasses ];
classList[ 1 ] = classes[ (i / numClasses) % numClasses ];
if ( classList[ 0 ] == Properties.class || classList[ 1 ] == Properties.class )
{
// don't generate any methods with Properties; that is only for named invocation
continue;
}
assert( classList[ 0 ] != Properties.class && classList[ 1 ] != Properties.class );
final MBeanOperationInfo info = createVirtualOperationInfo( operationName + i, classList );
ops.add( info );
}
MBeanOperationInfo [] infos = new MBeanOperationInfo[ ops.size() ];
infos = (MBeanOperationInfo [])ops.toArray( infos );
return( infos );
}
public synchronized MBeanInfo
getMBeanInfo()
{
if ( mMBeanInfo == null )
{
final MBeanAttributeInfo [] attributeInfo = null;
final MBeanConstructorInfo [] constructorInfo = null;
final MBeanNotificationInfo [] notificationInfo = null;
final MBeanOperationInfo [] operationInfo = createMBeanOperationInfos();
mMBeanInfo = new MBeanInfo( this.getClass().getName(),
"Test MBean for the CLI support code",
attributeInfo,
constructorInfo,
operationInfo,
notificationInfo );
}
return( mMBeanInfo );
}
public Object
getAttribute(String attribute)
throws AttributeNotFoundException, MBeanException, ReflectionException
{
throw new AttributeNotFoundException();
}
public AttributeList
getAttributes(String[] attributes)
{
return new AttributeList();
}
public AttributeList
setAttributes(AttributeList attributes)
{
return new AttributeList();
}
public void
setAttribute(Attribute attribute)
throws AttributeNotFoundException, InvalidAttributeValueException,
MBeanException, ReflectionException
{
throw new AttributeNotFoundException();
}
public Object
invoke(
String actionName,
Object params[],
String signature[] )
throws MBeanException, ReflectionException
{
Object result = null;
if ( actionName.startsWith( VIRTUAL_OPERATION_NAME ) )
{
return( signature );
}
try
{
// p( "INVOKING HELPER: " + actionName + "(" + AutoStringifier.toString( signature ) + ")");
result = mInvokeHelper.invoke( actionName, params, signature );
// ignore result, always return signature of invoked method
result = signature;
// p( "SUCCESS: " + actionName + "(" + AutoStringifier.toString( signature ) + ")");
}
catch( Exception e )
{
// e.printStackTrace();
throw new MBeanException( e );
}
return( result );
}
}