View Javadoc

    1   /*
    2    * Copyright (c) 2001-2003 The XDoclet team
    3    * All rights reserved.
    4    */
    5   package xjavadoc;
    6
    7   import java.util.ArrayList;
    8   import java.util.List;
    9   import java.util.Collections;
    10  import java.util.Iterator;
    11  import java.lang.reflect.Modifier;
    12
    13  /***
    14   * Baseclass for XExecutableMember.
    15   *
    16   * @author    Aslak Hellesøy
    17   * @created   9. mars 2003
    18   */
    19  abstract class AbstractExecutableMember extends MemberImpl implements XExecutableMember
    20  {
    21  	/***
    22  	 * Maximum dimension of a parameter. We want to avoid exessive Integer object
    23  	 * creation.
    24  	 */
    25  	private final static int MAX_ARRAY_SIZE = 6;
    26  	private final static Integer[] _dimensions = new Integer[MAX_ARRAY_SIZE];
    27
    28  	/***
    29  	 * Initial size of data to hold parameters. Estimate of average number of
    30  	 * params in a method.
    31  	 */
    32  	private final static int PARAMETER_DATA_SIZE = 2;
    33
    34  	/***
    35  	 * Initial size of ParameterImpl pool. Estimate of max number of params in a
    36  	 * method
    37  	 */
    38  	private final static int INITIAL_PARAMETER_POOL_SIZE = 20;
    39  	private static ParameterImpl[] _parameterPool = new ParameterImpl[INITIAL_PARAMETER_POOL_SIZE];
    40  	private List       _thrownExceptions;
    41  	private List       _parameterData;
    42  	private String     _nameWithSignature;
    43  	private String     _signature;
    44  	private String     _stringId;
    45
    46  	static
    47  	{
    48  		for( int i = 0; i < MAX_ARRAY_SIZE; i++ )
    49  		{
    50  			_dimensions[i] = new Integer( i );
    51  		}
    52  	}
    53
    54  	static
    55  	{
    56  		for( int i = 0; i < INITIAL_PARAMETER_POOL_SIZE; i++ )
    57  		{
    58  			_parameterPool[i] = new ParameterImpl();
    59  		}
    60  	}
    61
    62  	protected AbstractExecutableMember( AbstractClass containingClass, XTagFactory tagFactory )
    63  	{
    64  		super( containingClass, tagFactory );
    65  		if( containingClass == null )
    66  		{
    67  			throw new IllegalArgumentException( "containingClass can't be null" );
    68  		}
    69  	}
    70
    71  	private final static String toString( XParameter parameter, boolean withParam )
    72  	{
    73  		if( parameter == null )
    74  		{
    75  			throw new IllegalStateException( "parameter can't be null!" );
    76  		}
    77
    78  		StringBuffer sb = new StringBuffer( parameter.getType().getQualifiedName() );
    79
    80  		Util.appendDimensionAsString( parameter.getDimension(), sb );
    81  		if( withParam )
    82  		{
    83  			sb.append( " " ).append( parameter.getName() );
    84  		}
    85  		return sb.toString();
    86  	}
    87
    88  	/***
    89  	 * Gets the Native attribute of the AbstractExecutableMember object
    90  	 *
    91  	 * @return   The Native value
    92  	 */
    93  	public final boolean isNative()
    94  	{
    95  		return ( getModifierSpecifier() & Modifier.NATIVE ) != 0;
    96  	}
    97
    98  	/***
    99  	 * Gets the Synchronized attribute of the AbstractExecutableMember object
    100 	 *
    101 	 * @return   The Synchronized value
    102 	 */
    103 	public final boolean isSynchronized()
    104 	{
    105 		return ( getModifierSpecifier() & Modifier.SYNCHRONIZED ) != 0;
    106 	}
    107
    108 	/***
    109 	 * Returns the method parameters.
    110 	 *
    111 	 * @return   the method parameters
    112 	 */
    113 	public final List getParameters()
    114 	{
    115 		List parameters = null;
    116
    117 		if( _parameterData == null )
    118 		{
    119 			parameters = EMPTY_LIST;
    120 		}
    121 		else
    122 		{
    123 			int requiredSize = _parameterData.size() / 3;
    124
    125 			parameters = new ArrayList( requiredSize );
    126 			if( _parameterPool.length < requiredSize )
    127 			{
    128 				// increase flyweight pool size
    129 				ParameterImpl[] newPool = new ParameterImpl[requiredSize];
    130
    131 				System.arraycopy( _parameterPool, 0, newPool, 0, _parameterPool.length );
    132 				for( int j = _parameterPool.length; j < newPool.length; j++ )
    133 				{
    134 					newPool[j] = new ParameterImpl();
    135 				}
    136 				_parameterPool = newPool;
    137 			}
    138
    139 			for( int i = 0; i < requiredSize; i++ )
    140 			{
    141 				try
    142 				{
    143 					_parameterPool[i].setState( this, i );
    144 					parameters.add( _parameterPool[i] );
    145 				}
    146 				catch( IndexOutOfBoundsException e )
    147 				{
    148 					throw new IllegalStateException( "In member " + getName() + ". Tried to set " + i + "th parameter. Size was " + requiredSize );
    149 				}
    150 			}
    151 		}
    152 		return Collections.unmodifiableList( parameters );
    153 	}
    154
    155 	/***
    156 	 * Gets the signature
    157 	 *
    158 	 * @param withParam  if true, include the parameters in the signature.
    159 	 *      Otherwise, only the types will be used.
    160 	 * @return           the signature
    161 	 */
    162 	public final String getSignature( boolean withParam )
    163 	{
    164 		if( _signature == null )
    165 		{
    166 			_signature = appendSignature( new StringBuffer(), withParam ).toString();
    167 		}
    168 		return _signature;
    169 	}
    170
    171 	/***
    172 	 * Gets the name and signature
    173 	 *
    174 	 * @param withParam  if true, include the parameters in the signature.
    175 	 *      Otherwise, only the types will be used.
    176 	 * @return           the name and signature
    177 	 */
    178 	public final String getNameWithSignature( boolean withParam )
    179 	{
    180 		if( _nameWithSignature == null )
    181 		{
    182 			_nameWithSignature = appendSignature( new StringBuffer( getName() ), withParam ).toString();
    183 		}
    184 		return _nameWithSignature;
    185 	}
    186
    187 	public String getParameterTypes()
    188 	{
    189 		StringBuffer sb = new StringBuffer();
    190
    191 		for( Iterator i = getParameters().iterator(); i.hasNext();  )
    192 		{
    193 			// resolve first
    194 			( ( XParameter ) i.next() ).getType();
    195 		}
    196
    197 		boolean comma = false;
    198
    199 		for( Iterator i = getParameters().iterator(); i.hasNext();  )
    200 		{
    201 			// By calling toString(XParameter) we risk that the current parameter flyweights'
    202 			// state is overwritten. This will happen when toString is calling parameter.type()
    203 			// and that type isn't resolved yet. That's why the additional loop is added above,
    204 			// to make sure everything required is resolved before calling toString.
    205 			// This solves the problem, but might slow down speed a little (Aslak)
    206 			if( comma )
    207 			{
    208 				sb.append( ',' );
    209 			}
    210
    211 			XParameter parameter = ( XParameter ) i.next();
    212
    213 			sb.append( parameter.getType().getType() );
    214 			comma = true;
    215 		}
    216 		return sb.toString();
    217 	}
    218
    219 	public List getThrownExceptions()
    220 	{
    221 		return _thrownExceptions == null ? EMPTY_LIST : Collections.unmodifiableList( getQualifiedExceptions() );
    222 	}
    223
    224 	public XProgramElement getSuperElement( boolean forMethod )
    225 	{
    226 		XClass superclass = getContainingClass().getSuperclass();
    227
    228 		while( superclass != null )
    229 		{
    230 			XExecutableMember superExecutableMember;
    231
    232 			if( forMethod )
    233 			{
    234 				superExecutableMember = superclass.getMethod( getNameWithSignature( false ) );
    235 			}
    236 			else
    237 			{
    238 				// for constructor
    239 				superExecutableMember = superclass.getConstructor( getNameWithSignature( false ) );
    240 			}
    241 			if( superExecutableMember != null )
    242 			{
    243 				return superExecutableMember;
    244 			}
    245 			else
    246 			{
    247 				superclass = superclass.getSuperclass();
    248 			}
    249 		}
    250 		return null;
    251 	}
    252
    253 	public boolean throwsException( String exception_class_name )
    254 	{
    255 		//we loop over _thrownExceptions, so we don't qualify exception classes unneccessarily
    256 		for( Iterator iterator = getThrownExceptions().iterator(); iterator.hasNext();  )
    257 		{
    258 			XClass exception = (XClass) iterator.next();
    259
    260 			if( exception.getQualifiedName().equals( exception_class_name ) )
    261 				return true;
    262 		}
    263
    264 		return false;
    265 	}
    266
    267 	/***
    268 	 * Adds a parameter
    269 	 *
    270 	 * @param type       qualified nyme of parameter type
    271 	 * @param name       parameter name
    272 	 * @param dimension  parameter dimension
    273 	 */
    274 	public void addParameterData( String type, String name, int dimension )
    275 	{
    276 		if( _parameterData == null )
    277 		{
    278 			_parameterData = new ArrayList( PARAMETER_DATA_SIZE * 3 );
    279 		}
    280 		_parameterData.add( type );
    281 		_parameterData.add( name );
    282 		_parameterData.add( _dimensions[dimension] );
    283 	}
    284
    285 	public void addThrownException( String thrownException )
    286 	{
    287 		if( _thrownExceptions == null )
    288 		{
    289 			_thrownExceptions = new ArrayList();
    290 		}
    291 		_thrownExceptions.add( thrownException );
    292 	}
    293
    294 	public boolean equals( Object o )
    295 	{
    296 		if( !( o.getClass() == getClass() ) )
    297 		{
    298 			return false;
    299 		}
    300
    301 		AbstractExecutableMember other = ( AbstractExecutableMember ) o;
    302
    303 		return stringId().equals( other.stringId() );
    304 	}
    305
    306 	public int hashCode()
    307 	{
    308 		return stringId().hashCode();
    309 	}
    310
    311 	public String toString()
    312 	{
    313 		return stringId();
    314 	}
    315
    316 	protected abstract String buildStringId();
    317
    318 	final String getParameterType( int index )
    319 	{
    320 		return ( String ) _parameterData.get( index * 3 );
    321 	}
    322
    323 	final String getParameterName( int index )
    324 	{
    325 		return ( String ) _parameterData.get( index * 3 + 1 );
    326 	}
    327
    328 	final int getParameterDimension( int index )
    329 	{
    330 		return ( ( Integer ) _parameterData.get( index * 3 + 2 ) ).intValue();
    331 	}
    332
    333 	private List getQualifiedExceptions()
    334 	{
    335 		//if the list is not yet full qualified then qualify it
    336 		if( _thrownExceptions.get( 0 ) instanceof String )
    337 		{
    338 			List qualified_thrown_exceptions = new ArrayList();
    339
    340 			for( Iterator iterator = _thrownExceptions.iterator(); iterator.hasNext();  )
    341 			{
    342 				String exception_class_name = ( String ) iterator.next();
    343
    344 				qualified_thrown_exceptions.add( getContainingAbstractClass().qualify( exception_class_name ) );
    345 			}
    346
    347 			_thrownExceptions = qualified_thrown_exceptions;
    348 		}
    349
    350 		return _thrownExceptions;
    351 	}
    352
    353 	/***
    354 	 * Gets the StringId attribute of the MethodImpl object
    355 	 *
    356 	 * @return   The StringId value
    357 	 */
    358 	private final String stringId()
    359 	{
    360 		if( _stringId == null )
    361 		{
    362 			_stringId = buildStringId();
    363 		}
    364 		return _stringId;
    365 	}
    366
    367 	private final StringBuffer appendSignature( StringBuffer sb, boolean withParam )
    368 	{
    369 		sb.append( '(' );
    370
    371 		for( Iterator i = getParameters().iterator(); i.hasNext();  )
    372 		{
    373 			// resolve first
    374 			( ( XParameter ) i.next() ).getType();
    375 		}
    376
    377 		boolean comma = false;
    378
    379 		for( Iterator i = getParameters().iterator(); i.hasNext();  )
    380 		{
    381 			// By calling toString(XParameter) we risk that the current parameter flyweights'
    382 			// state is overwritten. This will happen when toString is calling parameter.type()
    383 			// and that type isn't resolved yet. That's why the additional loop is added above,
    384 			// to make sure everything required is resolved before calling toString.
    385 			// This solves the problem, but might slow down speed a little (Aslak)
    386 			if( comma )
    387 			{
    388 				sb.append( ',' );
    389 			}
    390 			sb.append( toString( ( XParameter ) i.next(), withParam ) );
    391 			comma = true;
    392 		}
    393 		return sb.append( ')' );
    394 	}
    395 }