|
|||||||||||||||||||
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover | |||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
XJavaDoc.java | 57.8% | 65.8% | 62.5% | 63.3% |
|
1 |
/*
|
|
2 |
* Copyright (c) 2001-2003 The XDoclet team
|
|
3 |
* All rights reserved.
|
|
4 |
*/
|
|
5 |
package xjavadoc;
|
|
6 |
|
|
7 |
import xjavadoc.filesystem.AbstractFile;
|
|
8 |
import xjavadoc.tags.TagIntrospector;
|
|
9 |
|
|
10 |
import java.io.PrintStream;
|
|
11 |
import java.util.*;
|
|
12 |
|
|
13 |
import org.apache.commons.collections.Predicate;
|
|
14 |
import org.apache.commons.collections.CollectionUtils;
|
|
15 |
|
|
16 |
/**
|
|
17 |
* This class represents the entry-point for xjavadoc classes. Come here to get
|
|
18 |
* classes and packages.
|
|
19 |
*
|
|
20 |
* @author Aslak Hellesøy
|
|
21 |
* @created 3. januar 2002
|
|
22 |
*/
|
|
23 |
public final class XJavaDoc |
|
24 |
{ |
|
25 |
/**
|
|
26 |
* Indicates whether this XJavaDoc was built with or without unicode support
|
|
27 |
*/
|
|
28 |
public final static String IS_UNICODE = "@IS_UNICODE@"; |
|
29 |
/**
|
|
30 |
* messgage level for reporting unqualified classes when there are no imported
|
|
31 |
* packages
|
|
32 |
*/
|
|
33 |
public final static int NO_IMPORTED_PACKAGES = 0; |
|
34 |
/**
|
|
35 |
* messgage level for reporting unqualified classes when there are one or more
|
|
36 |
* imported packages
|
|
37 |
*/
|
|
38 |
public final static int ONE_OR_MORE_IMPORTED_PACKAGES = 1; |
|
39 |
|
|
40 |
private final static List PRIMITIVES = Collections.unmodifiableList( Arrays.asList( new String[] |
|
41 |
{"void", "java.lang.Void.TYPE", |
|
42 |
"byte", "java.lang.Byte.TYPE", |
|
43 |
"short", "java.lang.Short.TYPE", |
|
44 |
"int", "java.lang.Integer.TYPE", |
|
45 |
"long", "java.lang.Long.TYPE", |
|
46 |
"char", "java.lang.Character.TYPE", |
|
47 |
"float", "java.lang.Float.TYPE", |
|
48 |
"double", "java.lang.Double.TYPE", |
|
49 |
"boolean", "java.lang.Boolean.TYPE" |
|
50 |
} ) ); |
|
51 |
|
|
52 |
private static HashMap _primitiveClasses = new HashMap(); |
|
53 |
private final Map _binaryClasses = new HashMap(); |
|
54 |
private final Map _unknownClasses = new HashMap(); |
|
55 |
private final Map _packages = new HashMap(); |
|
56 |
private final Set _sourceSets = new HashSet(); |
|
57 |
|
|
58 |
/**
|
|
59 |
* This map contains all the classes that were passed in the source sets,
|
|
60 |
* excluding all inner classes.
|
|
61 |
*/
|
|
62 |
private final Map _sourceSetSourceClasses = new HashMap(); |
|
63 |
|
|
64 |
/**
|
|
65 |
* This map contains the same classes as _sourceSetSourceClasses, but it is
|
|
66 |
* also populated with additional classes that may be accessed that were not in
|
|
67 |
* the source sets. This can be superclasses, classes referenced in methods,
|
|
68 |
* import statements etc.
|
|
69 |
*/
|
|
70 |
private final Map _allSourceClasses = new HashMap(); |
|
71 |
|
|
72 |
private final Set _sourceSetClassNames = new TreeSet(); |
|
73 |
|
|
74 |
private final Map _properties = new HashMap(); |
|
75 |
|
|
76 |
private final Map _abstractFileClasses = new HashMap(); |
|
77 |
|
|
78 |
private final XTagFactory _tagFactory = new XTagFactory(); |
|
79 |
|
|
80 |
/**
|
|
81 |
* This map contains all the classes that were passed in the source sets,
|
|
82 |
* including all inner classes.
|
|
83 |
*/
|
|
84 |
private Collection _sourceSetSourceClassesWithInnerClasses = new ArrayList(); |
|
85 |
|
|
86 |
/**
|
|
87 |
* Remember when we're born. We hate sources that are born after us and we
|
|
88 |
* pretend they don't exist, because if we don't we'll have very unpredictable
|
|
89 |
* behaviour. Well, since we have editor plugin and this is singleton object,
|
|
90 |
* we have to relax our policy on this. Or we will have to restart editor every
|
|
91 |
* time we like to tag the same class again...
|
|
92 |
*/
|
|
93 |
private long _birthday; |
|
94 |
|
|
95 |
/**
|
|
96 |
* info, error and warning messages related to parsing and class qualification
|
|
97 |
*/
|
|
98 |
private List _logMessages = new LinkedList(); |
|
99 |
|
|
100 |
/**
|
|
101 |
* sticky parameter for useNodeParser. _useNodeParser = true -> slower parsing,
|
|
102 |
* but modifiable javaodcs.
|
|
103 |
*/
|
|
104 |
private boolean _useNodeParser = false; |
|
105 |
|
|
106 |
/** charset for source file */
|
|
107 |
private String _encoding = null; |
|
108 |
|
|
109 |
/** charset for generated file */
|
|
110 |
private String _docEncoding = null; |
|
111 |
|
|
112 | 66 |
public XJavaDoc()
|
113 |
{ |
|
114 | 66 |
_birthday = System.currentTimeMillis(); |
115 | 66 |
for( int i = 0; i < PRIMITIVES.size(); i += 2 ) |
116 |
{ |
|
117 | 594 |
addPrimitive( ( String ) PRIMITIVES.get( i ), ( String ) PRIMITIVES.get( i + 1 ) ); |
118 |
} |
|
119 |
} |
|
120 |
|
|
121 |
/**
|
|
122 |
* Dump to sytem out the status of XJavadoc.
|
|
123 |
*/
|
|
124 | 0 |
public static void printMemoryStatus() |
125 |
{ |
|
126 | 0 |
System.out.println( "ParameterImpl instances: " + ParameterImpl.instanceCount );
|
127 | 0 |
System.out.println( "MethodImpl instances: " + MethodImpl.instanceCount );
|
128 | 0 |
System.out.println( "ConstructorImpl instances: " + ConstructorImpl.instanceCount );
|
129 | 0 |
System.out.println( "SimpleNode instances: " + SimpleNode.instanceCount );
|
130 | 0 |
System.out.println( "SourceClass instances: " + SourceClass.instanceCount );
|
131 | 0 |
System.out.println( "XDoc instances: " + XDoc.instanceCount );
|
132 | 0 |
System.out.println( "DefaultXTag instances: " + DefaultXTag.instanceCount );
|
133 | 0 |
System.out.println( "BinaryClass instances: " + BinaryClass.instanceCount );
|
134 | 0 |
System.out.println( "UnknownClass instances: " + UnknownClass.instanceCount );
|
135 |
|
|
136 | 0 |
System.out.println( "Total memory: " + ( Runtime.getRuntime().totalMemory() / ( 1024 * 1024 ) ) );
|
137 | 0 |
System.out.println( "Free memory: " + Runtime.getRuntime().freeMemory() / ( 1024 * 1024 ) );
|
138 |
} |
|
139 |
|
|
140 |
/**
|
|
141 |
* Replaces <code>${xxx}</code> style constructions in the given value with the
|
|
142 |
* string value of the corresponding data types. NOTE: This method was taken
|
|
143 |
* directly from Ant's source code (org.apache.tools.ant.ProjectHelper) and
|
|
144 |
* modified slightly to use a Map instead of a HashMap.
|
|
145 |
*
|
|
146 |
* @param value The string to be scanned for property references. May be
|
|
147 |
* <code>null</code> , in which case this method returns immediately with
|
|
148 |
* no effect.
|
|
149 |
* @param keys Mapping (String to String) of property names to their values.
|
|
150 |
* Must not be <code>null</code>.
|
|
151 |
* @return the original string with the properties replaced, or <code>null</code>
|
|
152 |
* if the original string is <code>null</code>.
|
|
153 |
*/
|
|
154 | 371 |
public static String replaceProperties( String value, Map keys ) |
155 |
{ |
|
156 | 371 |
if( value == null ) |
157 |
{ |
|
158 | 0 |
return null; |
159 |
} |
|
160 |
|
|
161 | 371 |
ArrayList fragments = new ArrayList();
|
162 | 371 |
ArrayList propertyRefs = new ArrayList();
|
163 |
|
|
164 | 371 |
parsePropertyString( value, fragments, propertyRefs ); |
165 |
|
|
166 | 371 |
StringBuffer sbuf = new StringBuffer();
|
167 | 371 |
Iterator i = fragments.iterator(); |
168 | 371 |
Iterator j = propertyRefs.iterator(); |
169 |
|
|
170 | 371 |
while( i.hasNext() )
|
171 |
{ |
|
172 | 387 |
String fragment = ( String ) i.next(); |
173 |
|
|
174 | 387 |
if( fragment == null ) |
175 |
{ |
|
176 | 9 |
String propertyName = ( String ) j.next(); |
177 |
|
|
178 | 9 |
fragment = ( keys.containsKey( propertyName ) ) ? ( String ) keys.get( propertyName ) |
179 |
: "${" + propertyName + '}';
|
|
180 |
} |
|
181 | 387 |
sbuf.append( fragment ); |
182 |
} |
|
183 |
|
|
184 | 371 |
return sbuf.toString();
|
185 |
} |
|
186 |
|
|
187 |
/**
|
|
188 |
* Parses a string containing <code>${xxx}</code> style property references
|
|
189 |
* into two lists. The first list is a collection of text fragments, while the
|
|
190 |
* other is a set of string property names. <code>null</code> entries in the
|
|
191 |
* first list indicate a property reference from the second list. NOTE: This
|
|
192 |
* method was taken directly from Ant's source code
|
|
193 |
* ({@link org.apache.tools.ant.ProjectHelper}) with the BuildException throwing
|
|
194 |
* removed.
|
|
195 |
*
|
|
196 |
* @param value Text to parse. Must not be <code>null</code>.
|
|
197 |
* @param fragments List to add text fragments to. Must not be <code>null</code>.
|
|
198 |
* @param propertyRefs List to add property names to. Must not be <code>null</code>.
|
|
199 |
*/
|
|
200 | 371 |
public static void parsePropertyString( String value, List fragments, List propertyRefs ) |
201 |
{ |
|
202 | 371 |
int prev = 0;
|
203 | 371 |
int pos;
|
204 |
|
|
205 | ? |
while( ( pos = value.indexOf( '$', prev ) ) >= 0 )
|
206 |
{ |
|
207 |
|
|
208 | 9 |
if( pos > 0 )
|
209 |
{ |
|
210 | 9 |
String fragment = value.substring( prev, pos ); |
211 |
|
|
212 | 9 |
fragments.add( fragment ); |
213 |
} |
|
214 |
|
|
215 | 9 |
if( pos == ( value.length() - 1 ) )
|
216 |
{ |
|
217 | 0 |
fragments.add( "$" );
|
218 | 0 |
prev = pos + 1; |
219 |
} |
|
220 | 9 |
else if( value.charAt( pos + 1 ) != '{' ) |
221 |
{ |
|
222 | 0 |
fragments.add( value.substring( pos, pos + 1 ) ); |
223 | 0 |
prev = pos + 1; |
224 |
} |
|
225 |
else
|
|
226 |
{ |
|
227 | 9 |
int endName = value.indexOf( '}', pos );
|
228 |
|
|
229 | 9 |
if( endName < 0 )
|
230 |
{ |
|
231 |
// In Ant this is a BuildException condition as its an
|
|
232 |
// incomplete property reference. Here we'll leave it
|
|
233 |
// in the output string
|
|
234 | 0 |
String fragment = value.substring( pos ); |
235 |
|
|
236 | 0 |
fragments.add( fragment ); |
237 | 0 |
continue;
|
238 |
} |
|
239 |
|
|
240 | 9 |
String propertyName = value.substring( pos + 2, endName ); |
241 |
|
|
242 | 9 |
fragments.add( null );
|
243 | 9 |
propertyRefs.add( propertyName ); |
244 | 9 |
prev = endName + 1; |
245 |
} |
|
246 |
} |
|
247 |
|
|
248 | 371 |
if( prev < value.length() )
|
249 |
{ |
|
250 | 369 |
String fragment = value.substring( prev ); |
251 |
|
|
252 | 369 |
fragments.add( fragment ); |
253 |
} |
|
254 |
} |
|
255 |
|
|
256 |
/**
|
|
257 |
* Gets the Primitive attribute of the XJavaDoc class
|
|
258 |
*
|
|
259 |
* @param name Describe what the parameter does
|
|
260 |
* @return The Primitive value
|
|
261 |
*/
|
|
262 | 2275 |
static Primitive getPrimitive( String name )
|
263 |
{ |
|
264 | 2275 |
return ( Primitive ) _primitiveClasses.get( name );
|
265 |
} |
|
266 |
|
|
267 |
/**
|
|
268 |
* Gets the file the pe is contained in. Note: calling this method with a
|
|
269 |
* XProgramElement not from source (but from a binary or unknown class) will
|
|
270 |
* result in a ClassCastException, so don't do that. This method is only used
|
|
271 |
* for diagnostics in error reporting.
|
|
272 |
*
|
|
273 |
* @param pe the program element we want the source for.
|
|
274 |
* @return the file the program element is contained in.
|
|
275 |
*/
|
|
276 | 0 |
static AbstractFile getSourceFileFor( XProgramElement pe )
|
277 |
{ |
|
278 | 0 |
SourceClass containingClass = null;
|
279 |
|
|
280 | 0 |
if( !( pe instanceof SourceClass ) ) |
281 |
{ |
|
282 |
// pe is a field, method or constructor. get the surrounding class
|
|
283 | 0 |
containingClass = ( SourceClass ) pe.getContainingClass(); |
284 |
} |
|
285 |
else
|
|
286 |
{ |
|
287 | 0 |
containingClass = ( SourceClass ) pe; |
288 |
} |
|
289 |
// in case the class is an inner class, loop until we have the outermost.
|
|
290 | 0 |
while( containingClass.getContainingClass() != null ) |
291 |
{ |
|
292 | 0 |
containingClass = ( SourceClass ) containingClass.getContainingClass(); |
293 |
} |
|
294 | 0 |
return containingClass.getFile();
|
295 |
} |
|
296 |
|
|
297 |
/**
|
|
298 |
* Describe the method
|
|
299 |
*
|
|
300 |
* @param name Describe the method parameter
|
|
301 |
* @param type The feature to be added to the Primitive attribute
|
|
302 |
*/
|
|
303 | 594 |
private final void addPrimitive( String name, String type ) |
304 |
{ |
|
305 | 594 |
_primitiveClasses.put( name, new Primitive( this, name, type ) ); |
306 |
} |
|
307 |
|
|
308 | 0 |
public Collection getSourceClasses( Predicate predicate )
|
309 |
{ |
|
310 | 0 |
return CollectionUtils.select( getSourceClasses(), predicate );
|
311 |
} |
|
312 |
|
|
313 |
/**
|
|
314 |
* Returns all classes in the registered source sets, including inner classes
|
|
315 |
*
|
|
316 |
* @return A Collection of XClass
|
|
317 |
*/
|
|
318 | 2 |
public Collection getSourceClasses()
|
319 |
{ |
|
320 | 2 |
if( _sourceSetSourceClassesWithInnerClasses.isEmpty() )
|
321 |
{ |
|
322 |
// Add the regular classes
|
|
323 | 2 |
_sourceSetSourceClassesWithInnerClasses.addAll( getOuterSourceClasses() ); |
324 |
|
|
325 |
// Add inner classes
|
|
326 | 2 |
for( Iterator outers = getOuterSourceClasses().iterator(); outers.hasNext(); )
|
327 |
{ |
|
328 | 16 |
addInnerClassRecursive( (XClass) outers.next(), _sourceSetSourceClassesWithInnerClasses ); |
329 |
} |
|
330 |
} |
|
331 | 2 |
return Collections.unmodifiableCollection( _sourceSetSourceClassesWithInnerClasses );
|
332 |
} |
|
333 |
|
|
334 |
/**
|
|
335 |
* Returns the packages of the specified classes during parsing.
|
|
336 |
*
|
|
337 |
* @return Describe the return value
|
|
338 |
*/
|
|
339 | 1 |
public Collection getSourcePackages()
|
340 |
{ |
|
341 | 1 |
Set packages = new TreeSet();
|
342 | 1 |
Collection classes = getSourceClasses(); |
343 |
|
|
344 | 1 |
for( Iterator i = classes.iterator(); i.hasNext(); )
|
345 |
{ |
|
346 | 21 |
packages.add( ((XClass)i.next()).getContainingPackage() ); |
347 |
} |
|
348 |
|
|
349 | 1 |
return Collections.unmodifiableCollection( packages );
|
350 |
} |
|
351 |
|
|
352 | 0 |
public Map getPropertyMap()
|
353 |
{ |
|
354 | 0 |
return Collections.unmodifiableMap( _properties );
|
355 |
} |
|
356 |
|
|
357 |
/**
|
|
358 |
* Get the XClass corresponding to the qualifiedName. This can be a class from
|
|
359 |
* source, a precompiled class or a primitive. UnknownClass is never returned
|
|
360 |
* from this method, unless it has been previously instantiated. <b>IMPORTANT:
|
|
361 |
* </b> If the Java source can be located, an instance of SourceClass will be
|
|
362 |
* returned. -Even if that file was not among the files in the fileset or
|
|
363 |
* sourceset. <b>IMPORTANT: </b> If qualifiedName represents an inner class, an
|
|
364 |
* UnknownClass will be returned unless the enclousing "outer" class has been
|
|
365 |
* resolved first.
|
|
366 |
*
|
|
367 |
* @param qualifiedName Fully qualified class name
|
|
368 |
* @return The XClass value
|
|
369 |
*/
|
|
370 | 1689 |
public XClass getXClass( String qualifiedName )
|
371 |
{ |
|
372 | 1689 |
if( qualifiedName.equals( "" ) ) |
373 |
{ |
|
374 | 0 |
throw new IllegalStateException( "Classname can't be empty String" ); |
375 |
} |
|
376 |
|
|
377 | 1689 |
XClass result = null;
|
378 | 1689 |
Primitive primitive; |
379 | 1689 |
SourceClass sourceClass; |
380 | 1689 |
BinaryClass binaryClass; |
381 | 1689 |
UnknownClass unknownClass; |
382 |
|
|
383 |
// first, check all caches
|
|
384 | ? |
if( ( primitive = getPrimitive( qualifiedName ) ) != null ) |
385 |
{ |
|
386 | 8 |
result = primitive; |
387 |
} |
|
388 | ? |
else if( ( sourceClass = ( SourceClass ) _allSourceClasses.get( qualifiedName ) ) != null ) |
389 |
{ |
|
390 | 142 |
result = sourceClass; |
391 |
} |
|
392 | ? |
else if( ( binaryClass = ( BinaryClass ) _binaryClasses.get( qualifiedName ) ) != null ) |
393 |
{ |
|
394 | 509 |
result = binaryClass; |
395 |
} |
|
396 | ? |
else if( ( unknownClass = ( UnknownClass ) _unknownClasses.get( qualifiedName ) ) != null ) |
397 |
{ |
|
398 | 0 |
result = unknownClass; |
399 |
} |
|
400 |
else
|
|
401 |
{ |
|
402 |
// Let's try to read the class from source
|
|
403 | 1030 |
if( sourceExists( qualifiedName ) )
|
404 |
{ |
|
405 |
// The source exists. Let's parse it.
|
|
406 | 336 |
sourceClass = scanAndPut( qualifiedName ); |
407 | 336 |
result = sourceClass; |
408 |
} |
|
409 |
else
|
|
410 |
{ |
|
411 |
// Couldn't find the class among the sources.
|
|
412 |
// Try a BinaryClass
|
|
413 | 694 |
Class clazz = getClass( qualifiedName ); |
414 |
|
|
415 | 694 |
if( clazz != null ) |
416 |
{ |
|
417 | 684 |
binaryClass = new BinaryClass( this, clazz ); |
418 | 684 |
_binaryClasses.put( qualifiedName, binaryClass ); |
419 | 684 |
result = binaryClass; |
420 |
} |
|
421 |
else
|
|
422 |
{ |
|
423 |
// Binary didn't exist either. Return an UnknownClass
|
|
424 | 10 |
result = new UnknownClass( this, qualifiedName ); |
425 | 10 |
_unknownClasses.put( qualifiedName, result ); |
426 |
} |
|
427 |
} |
|
428 |
} |
|
429 | 1689 |
return result;
|
430 |
} |
|
431 |
|
|
432 |
/**
|
|
433 |
* Returns the package. The package must be one of the packages of the sources.
|
|
434 |
* Other packages, such as java.lang are not available.
|
|
435 |
*
|
|
436 |
* @param packageName
|
|
437 |
* @return an XPackage, or null if the packageName is not among the
|
|
438 |
* sources.
|
|
439 |
*/
|
|
440 | 1 |
public XPackage getSourcePackage( String packageName )
|
441 |
{ |
|
442 |
// This is not optimal, but this method is primarily used for testing.
|
|
443 | 3 |
for( Iterator i = getSourcePackages().iterator(); i.hasNext(); )
|
444 |
{ |
|
445 | 3 |
XPackage p = ( XPackage ) i.next(); |
446 |
|
|
447 | 3 |
if( p.getName().equals( packageName ) )
|
448 |
{ |
|
449 | 1 |
return p;
|
450 |
} |
|
451 |
} |
|
452 | 0 |
return null; |
453 |
} |
|
454 |
|
|
455 |
/**
|
|
456 |
* This method can be called prior to parsing so that all classes are parsed
|
|
457 |
* with AST (to make it possible to write the source back to disk)
|
|
458 |
*
|
|
459 |
* @param useNodeParser
|
|
460 |
*/
|
|
461 | 4 |
public void setUseNodeParser( boolean useNodeParser ) |
462 |
{ |
|
463 | 4 |
_useNodeParser = useNodeParser; |
464 |
} |
|
465 |
|
|
466 | 25 |
public void setPropertyMap( Map properties ) |
467 |
{ |
|
468 | 25 |
_properties.putAll( properties ); |
469 |
} |
|
470 |
|
|
471 |
/**
|
|
472 |
* Resets the caches.
|
|
473 |
*
|
|
474 |
* @param resetTimeStamp true if timestamps should be reset too.
|
|
475 |
*/
|
|
476 | 60 |
public void reset( boolean resetTimeStamp ) |
477 |
{ |
|
478 | 60 |
for( Iterator iterator = _packages.values().iterator(); iterator.hasNext(); )
|
479 |
{ |
|
480 | 0 |
XPackage xPackage = (XPackage) iterator.next(); |
481 |
|
|
482 | 0 |
for( Iterator i = xPackage.getClasses().iterator(); i.hasNext(); )
|
483 |
{ |
|
484 | 0 |
AbstractClass clazz = ( AbstractClass ) i.next(); |
485 |
|
|
486 | 0 |
clazz.reset(); |
487 |
} |
|
488 |
} |
|
489 | 60 |
_binaryClasses.clear(); |
490 | 60 |
_unknownClasses.clear(); |
491 | 60 |
_packages.clear(); |
492 | 60 |
_sourceSets.clear(); |
493 | 60 |
_sourceSetSourceClasses.clear(); |
494 | 60 |
_sourceSetClassNames.clear(); |
495 | 60 |
_allSourceClasses.clear(); |
496 | 60 |
_sourceSetSourceClassesWithInnerClasses.clear(); |
497 |
|
|
498 | 60 |
_logMessages.clear(); |
499 | 60 |
_properties.clear(); |
500 | 60 |
_abstractFileClasses.clear(); |
501 |
|
|
502 |
//_primitiveClasses = null;
|
|
503 |
|
|
504 |
//AbstractProgramElement.NULL_XDOC = null;
|
|
505 |
|
|
506 |
// if we start new life, we can as well get new birth certificate,
|
|
507 |
// so classes saved in previous life can be loaded again without
|
|
508 |
// hating them :)
|
|
509 | 60 |
if( resetTimeStamp )
|
510 |
{ |
|
511 | 60 |
_birthday = System.currentTimeMillis(); |
512 |
} |
|
513 |
} |
|
514 |
|
|
515 |
/**
|
|
516 |
* Prints the log messages encountered during parsing
|
|
517 |
*
|
|
518 |
* @param out
|
|
519 |
* @param level
|
|
520 |
*/
|
|
521 | 0 |
public void printLogMessages( PrintStream out, int level ) |
522 |
{ |
|
523 | 0 |
boolean printedHeader = false; |
524 |
|
|
525 | 0 |
for( Iterator i = _logMessages.iterator(); i.hasNext(); )
|
526 |
{ |
|
527 | 0 |
LogMessage m = ( LogMessage ) i.next(); |
528 |
|
|
529 | 0 |
if( m._level == level )
|
530 |
{ |
|
531 | 0 |
if( !printedHeader )
|
532 |
{ |
|
533 | 0 |
if( level == ONE_OR_MORE_IMPORTED_PACKAGES )
|
534 |
{ |
|
535 |
// Could be an inner class too!!!
|
|
536 | 0 |
out.println( "WARNING: Some classes refer to other classes that were not found among the sources or on the classpath." );
|
537 | 0 |
out.println( " (Perhaps the referred class doesn't exist? Hasn't been generated yet?)" );
|
538 | 0 |
out.println( " The referring classes do not import any fully qualified classes matching these classes." );
|
539 | 0 |
out.println( " Since at least one package is imported, it is impossible for xjavadoc to figure out" );
|
540 | 0 |
out.println( " what package the referred classes belong to. The classes are:" );
|
541 |
} |
|
542 |
else
|
|
543 |
{ |
|
544 | 0 |
out.println( "INFO: Some classes refer to other classes that were not found among the sources or on the classpath." );
|
545 | 0 |
out.println( " (Perhaps the referred class doesn't exist? Hasn't been generated yet?)" );
|
546 | 0 |
out.println( " The referring classes do not import any fully qualified classes matching these classes." );
|
547 | 0 |
out.println( " However, since no packages are imported, xjavadoc has assumed that the referred classes" );
|
548 | 0 |
out.println( " belong to the same package as the referring class. The classes are:" );
|
549 |
} |
|
550 | 0 |
printedHeader = true;
|
551 |
} |
|
552 | 0 |
out.println( m._sourceClass.getFile().getPath() + " --> " + m._unqualifiedClassName + " qualified to " + m._unknownClass.getQualifiedName() ); |
553 |
} |
|
554 |
} |
|
555 |
} |
|
556 |
|
|
557 |
/**
|
|
558 |
* Adds a new set of java sources to be parsed.
|
|
559 |
*
|
|
560 |
* @param sourceSet a set of java sources.
|
|
561 |
*/
|
|
562 | 60 |
public void addSourceSet( SourceSet sourceSet ) |
563 |
{ |
|
564 | 60 |
_sourceSets.add( sourceSet ); |
565 | 60 |
for( int j = 0; j < sourceSet.getSize(); j++ ) |
566 |
{ |
|
567 | 250 |
String qualifiedName = sourceSet.getQualifiedName( j ); |
568 |
|
|
569 | 250 |
if( _sourceSetClassNames.contains( qualifiedName ) )
|
570 |
{ |
|
571 | 0 |
String msg = "The class \"" + qualifiedName + "\" occurs in more than one fileset. That's illegal."; |
572 |
|
|
573 | 0 |
System.err.println( msg ); |
574 |
} |
|
575 | 250 |
_sourceSetClassNames.add( qualifiedName ); |
576 |
} |
|
577 |
} |
|
578 |
|
|
579 | 0 |
public void addAbstractFile( String qualifiedName, AbstractFile file ) |
580 |
{ |
|
581 | 0 |
_abstractFileClasses.put( qualifiedName, file ); |
582 |
|
|
583 | 0 |
if( _sourceSetClassNames.contains( qualifiedName ) )
|
584 |
{ |
|
585 | 0 |
String msg = "The class \"" + qualifiedName + "\" occurs in more than one fileset. That's illegal."; |
586 |
|
|
587 | 0 |
System.err.println( msg ); |
588 |
} |
|
589 | 0 |
_sourceSetClassNames.add( qualifiedName ); |
590 |
} |
|
591 |
|
|
592 |
/**
|
|
593 |
* Describe what the method does
|
|
594 |
*
|
|
595 |
* @param className qualified name of class
|
|
596 |
* @param tagName tag name
|
|
597 |
* @param parameterName parameter name
|
|
598 |
* @param parameterValue new parameter value
|
|
599 |
* @param tagIndex index of tag (??)
|
|
600 |
* @param methodNameWithSignature method name followed by signature. no
|
|
601 |
* spaces. Ex:<br>
|
|
602 |
* <code>doIt(java.lang.String,int)</code>
|
|
603 |
* @return the class corresponding to the className
|
|
604 |
* @exception XJavaDocException If the tag for some reason couldn't be
|
|
605 |
* updated
|
|
606 |
*/
|
|
607 | 2 |
public XClass updateMethodTag(
|
608 |
String className, |
|
609 |
String methodNameWithSignature, |
|
610 |
String tagName, |
|
611 |
String parameterName, |
|
612 |
String parameterValue, |
|
613 |
int tagIndex
|
|
614 |
) throws XJavaDocException
|
|
615 |
{ |
|
616 | 2 |
XClass clazz = getXClass( className ); |
617 | 2 |
XMethod method = clazz.getMethod( methodNameWithSignature ); |
618 |
|
|
619 | 2 |
XDoc doc = method.getDoc(); |
620 |
|
|
621 | 2 |
doc.updateTagValue( tagName, parameterName, parameterValue, tagIndex ); |
622 |
|
|
623 | 2 |
return clazz;
|
624 |
} |
|
625 |
|
|
626 |
/**
|
|
627 |
* Describe what the method does
|
|
628 |
*
|
|
629 |
* @param className Describe what the parameter does
|
|
630 |
* @param tagName Describe what the parameter does
|
|
631 |
* @param parameterName Describe what the parameter does
|
|
632 |
* @param parameterValue Describe what the parameter does
|
|
633 |
* @param tagIndex Describe what the parameter does
|
|
634 |
* @return Describe the return value
|
|
635 |
* @exception XJavaDocException Describe the exception
|
|
636 |
*/
|
|
637 | 1 |
public XClass updateClassTag(
|
638 |
String className, |
|
639 |
String tagName, |
|
640 |
String parameterName, |
|
641 |
String parameterValue, |
|
642 |
int tagIndex
|
|
643 |
) throws XJavaDocException
|
|
644 |
{ |
|
645 | 1 |
XClass clazz = getXClass( className ); |
646 | 1 |
XDoc doc = clazz.getDoc(); |
647 |
|
|
648 | 1 |
doc.updateTagValue( tagName, parameterName, parameterValue, tagIndex ); |
649 | 1 |
return clazz;
|
650 |
} |
|
651 |
|
|
652 | 371 |
public String dereferenceProperties( String value )
|
653 |
{ |
|
654 |
|
|
655 | 371 |
return replaceProperties( value, _properties );
|
656 |
} |
|
657 |
|
|
658 |
/**
|
|
659 |
* @param qualifiedClassName
|
|
660 |
* @return true if the class exists, either as source or
|
|
661 |
* binary
|
|
662 |
*/
|
|
663 | 1410 |
final boolean classExists( final String qualifiedClassName )
|
664 |
{ |
|
665 |
// See if we have the source
|
|
666 | 1410 |
if( sourceExists( qualifiedClassName ) )
|
667 |
{ |
|
668 | 224 |
return true; |
669 |
} |
|
670 |
// See if we kand find the class (binary)
|
|
671 | 1186 |
else if( getClass( qualifiedClassName ) != null ) |
672 |
{ |
|
673 | 171 |
return true; |
674 |
} |
|
675 |
else
|
|
676 |
{ |
|
677 | 1015 |
return false; |
678 |
} |
|
679 |
} |
|
680 |
|
|
681 | 0 |
void logMessage( SourceClass clazz, UnknownClass unknownClass, String unqualifiedClassName, int level ) |
682 |
{ |
|
683 | 0 |
_logMessages.add( new LogMessage( clazz, unknownClass, unqualifiedClassName, level ) );
|
684 |
} |
|
685 |
|
|
686 |
/**
|
|
687 |
* Describe the method
|
|
688 |
*
|
|
689 |
* @param packageName Describe the method parameter
|
|
690 |
* @return Describe the return value
|
|
691 |
*/
|
|
692 | 1778 |
XPackage addPackageMaybe( String packageName ) |
693 |
{ |
|
694 | 1778 |
XPackage result = ( XPackage ) _packages.get( packageName ); |
695 |
|
|
696 | 1778 |
if( result == null ) |
697 |
{ |
|
698 |
// The package doesn't exist yet. Add it then
|
|
699 | 412 |
result = new XPackage( packageName );
|
700 | 412 |
_packages.put( packageName, result ); |
701 |
} |
|
702 | 1778 |
return result;
|
703 |
} |
|
704 |
|
|
705 |
/**
|
|
706 |
* Adds a source class to the cache. This method is also called from JavaParser
|
|
707 |
* when parsing inner classes.
|
|
708 |
*
|
|
709 |
* @param sourceClass Describe the method parameter
|
|
710 |
*/
|
|
711 | 779 |
void addSourceClass( SourceClass sourceClass )
|
712 |
{ |
|
713 | 779 |
_allSourceClasses.put( sourceClass.getQualifiedName(), sourceClass ); |
714 |
|
|
715 |
// Also add it to _sourceSetSourceClasses if it was among the source sets
|
|
716 |
// or if it is an "extra" class (this is due to XJD-8)
|
|
717 | 779 |
if( _sourceSetClassNames.contains( sourceClass.getQualifiedName() ) || sourceClass.isExtraClass() )
|
718 |
{ |
|
719 | 130 |
_sourceSetSourceClasses.put( sourceClass.getQualifiedName(), sourceClass ); |
720 |
} |
|
721 |
} |
|
722 |
|
|
723 |
/**
|
|
724 |
* Returns the Class with the given name, or null if unknown.
|
|
725 |
*
|
|
726 |
* @param qualifiedName Describe what the parameter does
|
|
727 |
* @return The Class value
|
|
728 |
*/
|
|
729 | 1880 |
private final Class getClass( String qualifiedName )
|
730 |
{ |
|
731 | 1880 |
try
|
732 |
{ |
|
733 | 1880 |
return Class.forName( qualifiedName, false, getClass().getClassLoader() ); |
734 |
} |
|
735 |
catch( Throwable e )
|
|
736 |
{ |
|
737 |
// e can be LinkageError, ClassNotFoundException or ExceptionInInitializerError
|
|
738 |
// We don't care what we get. If the forName fails, we don't have a class to return
|
|
739 | 1025 |
return null; |
740 |
} |
|
741 |
} |
|
742 |
|
|
743 |
/**
|
|
744 |
* Returns all classes in the registered source sets
|
|
745 |
*
|
|
746 |
* @return A Collection of XClass
|
|
747 |
*/
|
|
748 | 4 |
private Collection getOuterSourceClasses()
|
749 |
{ |
|
750 | 4 |
if( _sourceSetSourceClasses.isEmpty() )
|
751 |
{ |
|
752 | 2 |
for( Iterator i = _sourceSetClassNames.iterator(); i.hasNext(); )
|
753 |
{ |
|
754 | 20 |
String qualifiedName = ( String ) i.next(); |
755 |
|
|
756 |
/*
|
|
757 |
* This will result in the class being added to
|
|
758 |
* _sourceSetSourceClasses AND _allSourceClasses
|
|
759 |
*/
|
|
760 | 20 |
getXClass( qualifiedName ); |
761 |
} |
|
762 |
|
|
763 | 2 |
for( Iterator iterator = _abstractFileClasses.keySet().iterator(); iterator.hasNext(); )
|
764 |
{ |
|
765 | 0 |
String fqcn = ( String ) iterator.next(); |
766 |
|
|
767 | 0 |
getXClass( fqcn ); |
768 |
} |
|
769 |
} |
|
770 |
|
|
771 |
//a new collection should be created, becuase we might be looping over classes and generatePerClass for each
|
|
772 |
//one, now if a new class is discovered and registered (maybe we are analyzing a new class, maybe a template
|
|
773 |
//is now interested in superclass of a class, maybe ...), we'll get a ConcurrentModificationException. To prevent
|
|
774 |
//it we need to looping over a new collection (initiated from XJavaDoc mostly).
|
|
775 | 4 |
Collection new_collection = new ArrayList( _sourceSetSourceClasses.values() ); |
776 |
|
|
777 | 4 |
return Collections.unmodifiableCollection( new_collection ); |
778 |
} |
|
779 |
|
|
780 |
/**
|
|
781 |
* Gets the SourceFile attribute of the XJavaDoc object
|
|
782 |
*
|
|
783 |
* @param qualifiedName Describe what the parameter does
|
|
784 |
* @return The SourceFile value
|
|
785 |
*/
|
|
786 | 2776 |
private AbstractFile getSourceFile( String qualifiedName )
|
787 |
{ |
|
788 |
// loop over all SourceSets. If a source is found more than once -> bang!
|
|
789 | 2776 |
AbstractFile found = null;
|
790 |
|
|
791 | 2776 |
for( Iterator i = _sourceSets.iterator(); i.hasNext(); )
|
792 |
{ |
|
793 | 2737 |
SourceSet sourceSet = ( SourceSet ) i.next(); |
794 | 2737 |
AbstractFile javaFile = sourceSet.getSourceFile( qualifiedName ); |
795 |
|
|
796 | 2737 |
if( javaFile != null ) |
797 |
{ |
|
798 |
// isn't this an impossible situation? Have a look at addSourceSet - we check
|
|
799 |
// there to ensure that no classes are added twice.....
|
|
800 |
// if( found != null && !found.getAbsolutePath().equals( javaFile.getAbsolutePath() ) )
|
|
801 |
// {
|
|
802 |
// throw new IllegalStateException( "Ambiguous sources for " + qualifiedName + " : " + found.getAbsolutePath() + " or " + javaFile.getAbsolutePath() );
|
|
803 |
// }
|
|
804 | 896 |
found = javaFile; |
805 |
} |
|
806 |
} |
|
807 | 2776 |
return found;
|
808 |
} |
|
809 |
|
|
810 |
/**
|
|
811 |
* Recursively adds inner classes to a collection
|
|
812 |
*
|
|
813 |
* @param outer The feature to be added to the InnerClassRecursive attribute
|
|
814 |
* @param c The feature to be added to the InnerClassRecursive attribute
|
|
815 |
*/
|
|
816 | 42 |
private void addInnerClassRecursive( XClass outer, Collection c ) |
817 |
{ |
|
818 | 42 |
for( Iterator inners = outer.getInnerClasses().iterator(); inners.hasNext(); )
|
819 |
{ |
|
820 | 26 |
XClass inner = (XClass) inners.next(); |
821 |
|
|
822 | 26 |
c.add( inner ); |
823 | 26 |
addInnerClassRecursive( inner, c ); |
824 |
} |
|
825 |
} |
|
826 |
|
|
827 |
/**
|
|
828 |
* Checks is the source exists
|
|
829 |
*
|
|
830 |
* @param qualifiedName the class to check for
|
|
831 |
* @return true if source exists.
|
|
832 |
*/
|
|
833 | 2440 |
private boolean sourceExists( String qualifiedName ) |
834 |
{ |
|
835 |
/*
|
|
836 |
* When used with XDoclet, some classes might be resolved by xjavadoc
|
|
837 |
* after they are generated by XDoclet.
|
|
838 |
* (An example is e.g. a primary key
|
|
839 |
* class that doesn't exist before XDoclet is run, and which might be
|
|
840 |
* referenced by some of the methods in the @tagged classes).
|
|
841 |
* We will pretend that any classes that didn't exist before xjavadoc started
|
|
842 |
* scanning sources (generated classes) don't exist. This is to avoid modifying
|
|
843 |
* collections that are being iterated over in parallel, as this will throw
|
|
844 |
* ConcurrentModificationException. (Aslak)
|
|
845 |
*/
|
|
846 | 2440 |
AbstractFile sourceFile = getSourceFile( qualifiedName ); |
847 |
|
|
848 | 2440 |
if( sourceFile != null ) |
849 |
{ |
|
850 | 560 |
if( sourceFile.lastModified() > _birthday )
|
851 |
{ |
|
852 |
// The source appeared after xjavadoc was reset. Pretend it doesn't exist.
|
|
853 | 0 |
System.out.println( "XJavaDoc Ignoring class " + qualifiedName + " in " + sourceFile.getPath() + ". It was generated (" + new Date( sourceFile.lastModified() ) + ") after XJavaDoc's timestamp was reset (" + new Date( _birthday ) + ")" ); |
854 | 0 |
return false; |
855 |
} |
|
856 |
} |
|
857 |
|
|
858 | 2440 |
boolean sourceFileExists = sourceFile != null; |
859 |
|
|
860 | 2440 |
if( !sourceFileExists )
|
861 |
{ |
|
862 | 1880 |
sourceFileExists = _abstractFileClasses.containsKey( qualifiedName ); |
863 |
} |
|
864 |
|
|
865 | 2440 |
return sourceFileExists;
|
866 |
} |
|
867 |
|
|
868 |
/**
|
|
869 |
* Scan's a class and puts it in the cache.
|
|
870 |
*
|
|
871 |
* @param qualifiedName Describe what the parameter does
|
|
872 |
* @return Describe the return value
|
|
873 |
*/
|
|
874 | 336 |
private SourceClass scanAndPut( String qualifiedName )
|
875 |
{ |
|
876 | 336 |
AbstractFile sourceFile = getSourceFile( qualifiedName ); |
877 |
|
|
878 | 336 |
sourceFile = sourceFile != null ? sourceFile : ( AbstractFile ) _abstractFileClasses.get( qualifiedName );
|
879 |
|
|
880 | 336 |
if( sourceFile == null ) |
881 |
{ |
|
882 | 0 |
throw new IllegalStateException( "No source found for " + qualifiedName ); |
883 |
} |
|
884 |
|
|
885 | 336 |
SourceClass sourceClass = new SourceClass( this, sourceFile, _useNodeParser, _tagFactory ,_encoding); |
886 |
|
|
887 |
// now that the entire file is parsed, validate the tags.
|
|
888 | 336 |
if( _tagFactory.isValidating() )
|
889 |
{ |
|
890 | 0 |
sourceClass.validateTags(); |
891 |
} |
|
892 |
|
|
893 |
// addSourceClass( sourceClass );
|
|
894 |
|
|
895 | 336 |
return sourceClass;
|
896 |
} |
|
897 |
|
|
898 | 0 |
public XTagFactory getTagFactory() {
|
899 | 0 |
return _tagFactory;
|
900 |
} |
|
901 |
|
|
902 |
/**
|
|
903 |
* Registers tags.
|
|
904 |
*
|
|
905 |
* @param classpath where tags are found.
|
|
906 |
*/
|
|
907 | 0 |
public void registerTags( String classpath ) { |
908 | 0 |
new TagIntrospector().registerTags( classpath, getTagFactory() );
|
909 |
} |
|
910 |
|
|
911 |
public final static class NoInnerClassesPredicate implements Predicate |
|
912 |
{ |
|
913 | 0 |
public boolean evaluate( Object o ) |
914 |
{ |
|
915 | 0 |
XClass clazz = ( XClass ) o; |
916 |
|
|
917 | 0 |
return !clazz.isInner();
|
918 |
} |
|
919 |
} |
|
920 |
|
|
921 |
class LogMessage
|
|
922 |
{ |
|
923 |
public final SourceClass _sourceClass;
|
|
924 |
public final UnknownClass _unknownClass;
|
|
925 |
public final String _unqualifiedClassName;
|
|
926 |
public final int _level; |
|
927 | 0 |
LogMessage( SourceClass sourceClass, UnknownClass unknownClass, String unqualifiedClassName, int level )
|
928 |
{ |
|
929 | 0 |
_sourceClass = sourceClass; |
930 | 0 |
_unknownClass = unknownClass; |
931 | 0 |
_unqualifiedClassName = unqualifiedClassName; |
932 | 0 |
_level = level; |
933 |
} |
|
934 |
} |
|
935 |
|
|
936 |
/**
|
|
937 |
* Getter for source file charset.
|
|
938 |
* @return encoding
|
|
939 |
*/
|
|
940 | 0 |
public String getEncoding() {
|
941 | 0 |
return _encoding;
|
942 |
} |
|
943 |
|
|
944 |
/**
|
|
945 |
* Setter for source file charset.
|
|
946 |
* @param string encoding
|
|
947 |
*/
|
|
948 | 0 |
public void setEncoding(String encoding) { |
949 | 0 |
_encoding = encoding; |
950 |
} |
|
951 |
|
|
952 |
/**
|
|
953 |
* Getter for generated file charset.
|
|
954 |
* @return encoding
|
|
955 |
*/
|
|
956 | 0 |
public String getDocEncoding() {
|
957 | 0 |
return _docEncoding;
|
958 |
} |
|
959 |
|
|
960 |
/**
|
|
961 |
* Setter for generated file charset.
|
|
962 |
* @param string encoding
|
|
963 |
*/
|
|
964 | 0 |
public void setDocEncoding(String docencoding) { |
965 | 0 |
_docEncoding = docencoding; |
966 |
} |
|
967 |
|
|
968 |
} |
|
969 |
|
|