/*
* @(#)ParseCoverageLogger.java
*
* Copyright (C) 2002-2003 Matt Albrecht
* groboclown@users.sourceforge.net
* http://groboutils.sourceforge.net
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package net.sourceforge.groboutils.codecoverage.v2.compiler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import net.sourceforge.groboutils.codecoverage.v2.logger.ICoverageLoggerConst;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.Type;
/**
* Parses the CoverageLogger class to discover the BCEL compatible invocation
* objects and names.
*
* @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
* @version $Date: 2004/04/15 05:48:25 $
* @since December 17, 2002
*/
public class ParseCoverageLogger
{
//private static final Class COVERAGELOGGER_CLASS = CoverageLogger.class;
/**
* This is not the simplest or safest way to default to the coverage
* logger, but it does prevent loading the coverage logger class, thus
* preventing a possible error message.
*/
private static final String DEFAULT_COVERAGELOGGER_CLASSNAME =
ICoverageLoggerConst.COVERAGELOGGER_CLASSNAME;
private static final String DEFAULT_COVERAGELOGGER_METHODNAME =
ICoverageLoggerConst.INVOKE_METHOD_NAME;
private static final Class COVERAGE_SIGNATURE[] =
ICoverageLoggerConst.COVERAGE_SIGNATURE;
private static final Class COVERAGE_RETURNTYPE =
ICoverageLoggerConst.COVERAGE_RETURNTYPE;
private String methodSignature;
private String methodName;
private String className;
/**
* Reference the default CoverageLogger for creation.
*/
public ParseCoverageLogger()
{
// We will assume that the defaults given are correct. If they
// aren't valid, then this is a major bug in the logger, not
// this class.
storeData( DEFAULT_COVERAGELOGGER_CLASSNAME,
DEFAULT_COVERAGELOGGER_METHODNAME );
}
/**
* Discovers the method signature and accompanying information for a
* specific coverage logger to generate. The given method must exist
* with the correct parameters, attributes, and return type.
* Otherwise, an exception is raised.
*/
public ParseCoverageLogger( Class coverageClass, String methodName )
{
if (methodName == null || coverageClass == null)
{
throw new IllegalArgumentException( "No null args." );
}
parseCoverageLoggerType( coverageClass, methodName );
storeData( coverageClass.getName(), methodName );
}
/**
* Inner method to store the data of the class and method for the
* logger. It doesn't do any checking besides null. Thus, this
* method must be private to prevent inadvertent invalid class and
* method assignment.
*/
private void storeData( String className, String methodName )
{
this.methodName = methodName;
this.className = className;
if (methodName == null || className == null)
{
throw new IllegalArgumentException( "No null args." );
}
this.methodSignature = createSignature(
COVERAGE_SIGNATURE, COVERAGE_RETURNTYPE );
if (this.methodSignature == null)
{
throw new IllegalStateException(
"Returned null method signature." );
}
}
/**
* Returns the fully-qualified class name for the CoverageLogger.
*/
public String getClassName()
{
return this.className;
}
/**
* Returns the name of the method, without the signature.
*/
public String getMethodName()
{
return this.methodName;
}
/**
* Returns the signature of the method, without the method name.
*/
public String getMethodSignature()
{
return this.methodSignature;
}
private void parseCoverageLoggerType( Class clazz, String methodName )
{
// ensure that the method exists with the correct signature.
Method m = null;
try
{
m = clazz.getMethod( methodName, COVERAGE_SIGNATURE );
}
catch (NoSuchMethodException nsme)
{
// this will throw the next exception. Hide this one!
m = null;
}
if (m == null)
{
throw new IllegalStateException(
clazz.getName()+" doesn't have a method named '"+
methodName+"'" );
}
// the method MUST NOT return anything!
if (m.getReturnType() != null &&
!m.getReturnType().equals( COVERAGE_RETURNTYPE ))
{
throw new IllegalStateException(
clazz.getName()+" method '"+
methodName+"' incorrectly has a return value." );
}
// the method must also be static & public
int mod = m.getModifiers();
if (!Modifier.isStatic( mod ) || !Modifier.isPublic( mod ))
{
throw new IllegalStateException(
clazz.getName()+" method '"+
methodName+"' is not public or static." );
}
}
private static String createSignature( Class signature[],
Class returnClass )
{
Type returnType = getType( returnClass );
Type args[] = new Type[ signature.length ];
for (int i = 0; i < signature.length; ++i)
{
args[i] = getType( signature[i] );
}
return Type.getMethodSignature( returnType, args );
}
private static Type getType( Class c )
{
if (c.equals( Void.TYPE ))
{
return Type.VOID;
}
if (c.equals( Byte.TYPE ))
{
return Type.BYTE;
}
if (c.equals( Character.TYPE ))
{
return Type.CHAR;
}
if (c.equals( Short.TYPE ))
{
return Type.SHORT;
}
if (c.equals( Integer.TYPE ))
{
return Type.INT;
}
if (c.equals( Long.TYPE ))
{
return Type.LONG;
}
if (c.equals( Float.TYPE ))
{
return Type.FLOAT;
}
if (c.equals( Double.TYPE ))
{
return Type.DOUBLE;
}
// else
return new ObjectType( c.getName() );
}
}
|