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 }