Clover coverage report - XJavaDoc - 1.1 Coverage timestamp: Sun Oct 3 2004 19:56:54 BST FRAMES NO FRAMES |
file stats: | LOC: | 969 |  | Methods: | 40
| NCLOC: | 534 |  | Classes: | 3
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 | 132 |
         public XJavaDoc()
113 |  |
         {
114 | 132 |
             _birthday = System.currentTimeMillis();
115 | 132 |
             for( int i = 0; i < PRIMITIVES.size(); i += 2 )
116 |  |
             {
117 | 1188 |
                 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 | 742 |
         public static String replaceProperties( String value, Map keys )
155 |  |
         {
156 | 742 |
             if( value == null )
157 |  |
             {
158 | 0 |
                 return null;
159 |  |
             }
160 |  |
161 | 742 |
             ArrayList fragments = new ArrayList();
162 | 742 |
             ArrayList propertyRefs = new ArrayList();
163 |  |
164 | 742 |
             parsePropertyString( value, fragments, propertyRefs );
165 |  |
166 | 742 |
             StringBuffer sbuf = new StringBuffer();
167 | 742 |
             Iterator i = fragments.iterator();
168 | 742 |
             Iterator j = propertyRefs.iterator();
169 |  |
170 | 742 |
             while( i.hasNext() )
171 |  |
             {
172 | 774 |
                 String fragment = ( String ) i.next();
173 |  |
174 | 774 |
                 if( fragment == null )
175 |  |
                 {
176 | 18 |
                     String propertyName = ( String ) j.next();
177 |  |
178 | 18 |
                     fragment = ( keys.containsKey( propertyName ) ) ? ( String ) keys.get( propertyName )
179 |  |
                          : "${" + propertyName + '}';
180 |  |
                 }
181 | 774 |
                 sbuf.append( fragment );
182 |  |
             }
183 |  |
184 | 742 |
             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 | 742 |
         public static void parsePropertyString( String value, List fragments, List propertyRefs )
201 |  |
         {
202 | 742 |
             int prev = 0;
203 | 742 |
             int pos;
204 |  |
205 | ? |
             while( ( pos = value.indexOf( '$', prev ) ) >= 0 )
206 |  |
             {
207 |  |
208 | 18 |
                 if( pos > 0 )
209 |  |
                 {
210 | 18 |
                     String fragment = value.substring( prev, pos );
211 |  |
212 | 18 |
                     fragments.add( fragment );
213 |  |
                 }
214 |  |
215 | 18 |
                 if( pos == ( value.length() - 1 ) )
216 |  |
                 {
217 | 0 |
                     fragments.add( "$" );
218 | 0 |
                     prev = pos + 1;
219 |  |
                 }
220 | 18 |
                 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 | 18 |
                     int endName = value.indexOf( '}', pos );
228 |  |
229 | 18 |
                     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 | 18 |
                     String propertyName = value.substring( pos + 2, endName );
241 |  |
242 | 18 |
                     fragments.add( null );
243 | 18 |
                     propertyRefs.add( propertyName );
244 | 18 |
                     prev = endName + 1;
245 |  |
                 }
246 |  |
             }
247 |  |
248 | 742 |
             if( prev < value.length() )
249 |  |
             {
250 | 738 |
                 String fragment = value.substring( prev );
251 |  |
252 | 738 |
                 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 | 4550 |
         static Primitive getPrimitive( String name )
263 |  |
         {
264 | 4550 |
             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 | 1188 |
         private final void addPrimitive( String name, String type )
304 |  |
         {
305 | 1188 |
             _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 | 4 |
         public Collection getSourceClasses()
319 |  |
         {
320 | 4 |
             if( _sourceSetSourceClassesWithInnerClasses.isEmpty() )
321 |  |
             {
322 |  |
                 // Add the regular classes
323 | 4 |
                 _sourceSetSourceClassesWithInnerClasses.addAll( getOuterSourceClasses() );
324 |  |
325 |  |
                 // Add inner classes
326 | 4 |
                 for( Iterator outers = getOuterSourceClasses().iterator(); outers.hasNext();  )
327 |  |
                 {
328 | 32 |
                     addInnerClassRecursive( (XClass) outers.next(), _sourceSetSourceClassesWithInnerClasses );
329 |  |
                 }
330 |  |
             }
331 | 4 |
             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 | 2 |
         public Collection getSourcePackages()
340 |  |
         {
341 | 2 |
             Set packages = new TreeSet();
342 | 2 |
             Collection classes = getSourceClasses();
343 |  |
344 | 2 |
             for( Iterator i = classes.iterator(); i.hasNext();  )
345 |  |
             {
346 | 42 |
                 packages.add( ((XClass)i.next()).getContainingPackage() );
347 |  |
             }
348 |  |
349 | 2 |
             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 | 3378 |
         public XClass getXClass( String qualifiedName )
371 |  |
         {
372 | 3378 |
             if( qualifiedName.equals( "" ) )
373 |  |
             {
374 | 0 |
                 throw new IllegalStateException( "Classname can't be empty String" );
375 |  |
             }
376 |  |
377 | 3378 |
             XClass result = null;
378 | 3378 |
             Primitive primitive;
379 | 3378 |
             SourceClass sourceClass;
380 | 3378 |
             BinaryClass binaryClass;
381 | 3378 |
             UnknownClass unknownClass;
382 |  |
383 |  |
             // first, check all caches
384 | ? |
             if( ( primitive = getPrimitive( qualifiedName ) ) != null )
385 |  |
             {
386 | 16 |
                 result = primitive;
387 |  |
             }
388 | ? |
             else if( ( sourceClass = ( SourceClass ) _allSourceClasses.get( qualifiedName ) ) != null )
389 |  |
             {
390 | 284 |
                 result = sourceClass;
391 |  |
             }
392 | ? |
             else if( ( binaryClass = ( BinaryClass ) _binaryClasses.get( qualifiedName ) ) != null )
393 |  |
             {
394 | 1018 |
                 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 | 2060 |
                 if( sourceExists( qualifiedName ) )
404 |  |
                 {
405 |  |
                     // The source exists. Let's parse it.
406 | 672 |
                     sourceClass = scanAndPut( qualifiedName );
407 | 672 |
                     result = sourceClass;
408 |  |
                 }
409 |  |
                 else
410 |  |
                 {
411 |  |
                     // Couldn't find the class among the sources.
412 |  |
                     // Try a BinaryClass
413 | 1388 |
                     Class clazz = getClass( qualifiedName );
414 |  |
415 | 1388 |
                     if( clazz != null )
416 |  |
                     {
417 | 1368 |
                         binaryClass = new BinaryClass( this, clazz );
418 | 1368 |
                         _binaryClasses.put( qualifiedName, binaryClass );
419 | 1368 |
                         result = binaryClass;
420 |  |
                     }
421 |  |
                     else
422 |  |
                     {
423 |  |
                         // Binary didn't exist either. Return an UnknownClass
424 | 20 |
                         result = new UnknownClass( this, qualifiedName );
425 | 20 |
                         _unknownClasses.put( qualifiedName, result );
426 |  |
                     }
427 |  |
                 }
428 |  |
             }
429 | 3378 |
             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 | 2 |
         public XPackage getSourcePackage( String packageName )
441 |  |
         {
442 |  |
             // This is not optimal, but this method is primarily used for testing.
443 | 6 |
             for( Iterator i = getSourcePackages().iterator(); i.hasNext();  )
444 |  |
             {
445 | 6 |
                 XPackage p = ( XPackage ) i.next();
446 |  |
447 | 6 |
                 if( p.getName().equals( packageName ) )
448 |  |
                 {
449 | 2 |
                     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 | 8 |
         public void setUseNodeParser( boolean useNodeParser )
462 |  |
         {
463 | 8 |
             _useNodeParser = useNodeParser;
464 |  |
         }
465 |  |
466 | 50 |
         public void setPropertyMap( Map properties )
467 |  |
         {
468 | 50 |
             _properties.putAll( properties );
469 |  |
         }
470 |  |
471 |  |
         /**
472 |  |
          * Resets the caches.
473 |  |
          *
474 |  |
          * @param resetTimeStamp  true if timestamps should be reset too.
475 |  |
          */
476 | 120 |
         public void reset( boolean resetTimeStamp )
477 |  |
         {
478 | 120 |
             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 | 120 |
             _binaryClasses.clear();
490 | 120 |
             _unknownClasses.clear();
491 | 120 |
             _packages.clear();
492 | 120 |
             _sourceSets.clear();
493 | 120 |
             _sourceSetSourceClasses.clear();
494 | 120 |
             _sourceSetClassNames.clear();
495 | 120 |
             _allSourceClasses.clear();
496 | 120 |
             _sourceSetSourceClassesWithInnerClasses.clear();
497 |  |
498 | 120 |
             _logMessages.clear();
499 | 120 |
             _properties.clear();
500 | 120 |
             _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 | 120 |
             if( resetTimeStamp )
510 |  |
             {
511 | 120 |
                 _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 | 120 |
         public void addSourceSet( SourceSet sourceSet )
563 |  |
         {
564 | 120 |
             _sourceSets.add( sourceSet );
565 | 120 |
             for( int j = 0; j < sourceSet.getSize(); j++ )
566 |  |
             {
567 | 500 |
                 String qualifiedName = sourceSet.getQualifiedName( j );
568 |  |
569 | 500 |
                 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 | 500 |
                 _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 | 4 |
         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 | 4 |
             XClass clazz = getXClass( className );
617 | 4 |
             XMethod method = clazz.getMethod( methodNameWithSignature );
618 |  |
619 | 4 |
             XDoc doc = method.getDoc();
620 |  |
621 | 4 |
             doc.updateTagValue( tagName, parameterName, parameterValue, tagIndex );
622 |  |
623 | 4 |
             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 | 2 |
         public XClass updateClassTag(
638 |  |
             String className,
639 |  |
             String tagName,
640 |  |
             String parameterName,
641 |  |
             String parameterValue,
642 |  |
             int tagIndex
643 |  |
              ) throws XJavaDocException
644 |  |
         {
645 | 2 |
             XClass clazz = getXClass( className );
646 | 2 |
             XDoc doc = clazz.getDoc();
647 |  |
648 | 2 |
             doc.updateTagValue( tagName, parameterName, parameterValue, tagIndex );
649 | 2 |
             return clazz;
650 |  |
         }
651 |  |
652 | 742 |
         public String dereferenceProperties( String value )
653 |  |
         {
654 |  |
655 | 742 |
             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 | 2820 |
         final boolean classExists( final String qualifiedClassName )
664 |  |
         {
665 |  |
             // See if we have the source
666 | 2820 |
             if( sourceExists( qualifiedClassName ) )
667 |  |
             {
668 | 448 |
                 return true;
669 |  |
             }
670 |  |
             // See if we kand find the class (binary)
671 | 2372 |
             else if( getClass( qualifiedClassName ) != null )
672 |  |
             {
673 | 342 |
                 return true;
674 |  |
             }
675 |  |
             else
676 |  |
             {
677 | 2030 |
                 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 | 3556 |
         XPackage addPackageMaybe( String packageName )
693 |  |
         {
694 | 3556 |
             XPackage result = ( XPackage ) _packages.get( packageName );
695 |  |
696 | 3556 |
             if( result == null )
697 |  |
             {
698 |  |
                 // The package doesn't exist yet. Add it then
699 | 824 |
                 result = new XPackage( packageName );
700 | 824 |
                 _packages.put( packageName, result );
701 |  |
             }
702 | 3556 |
             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 | 1558 |
         void addSourceClass( SourceClass sourceClass )
712 |  |
         {
713 | 1558 |
             _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 | 1558 |
             if( _sourceSetClassNames.contains( sourceClass.getQualifiedName() ) || sourceClass.isExtraClass() )
718 |  |
             {
719 | 260 |
                 _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 | 3760 |
         private final Class getClass( String qualifiedName )
730 |  |
         {
731 | 3760 |
             try
732 |  |
             {
733 | 3760 |
                 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 | 2050 |
                 return null;
740 |  |
             }
741 |  |
         }
742 |  |
743 |  |
         /**
744 |  |
          * Returns all classes in the registered source sets
745 |  |
          *
746 |  |
          * @return   A Collection of XClass
747 |  |
          */
748 | 8 |
         private Collection getOuterSourceClasses()
749 |  |
         {
750 | 8 |
             if( _sourceSetSourceClasses.isEmpty() )
751 |  |
             {
752 | 4 |
                 for( Iterator i = _sourceSetClassNames.iterator(); i.hasNext();  )
753 |  |
                 {
754 | 40 |
                     String qualifiedName = ( String ) i.next();
755 |  |
756 |  |
                     /*
757 |  |
                      * This will result in the class being added to
758 |  |
                      * _sourceSetSourceClasses AND _allSourceClasses
759 |  |
                      */
760 | 40 |
                     getXClass( qualifiedName );
761 |  |
                 }
762 |  |
763 | 4 |
                 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 | 8 |
             Collection new_collection = new ArrayList( _sourceSetSourceClasses.values() );
776 |  |
777 | 8 |
             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 | 5552 |
         private AbstractFile getSourceFile( String qualifiedName )
787 |  |
         {
788 |  |
             // loop over all SourceSets. If a source is found more than once -> bang!
789 | 5552 |
             AbstractFile found = null;
790 |  |
791 | 5552 |
             for( Iterator i = _sourceSets.iterator(); i.hasNext();  )
792 |  |
             {
793 | 5474 |
                 SourceSet sourceSet = ( SourceSet ) i.next();
794 | 5474 |
                 AbstractFile javaFile = sourceSet.getSourceFile( qualifiedName );
795 |  |
796 | 5474 |
                 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 | 1792 |
                     found = javaFile;
805 |  |
                 }
806 |  |
             }
807 | 5552 |
             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 | 84 |
         private void addInnerClassRecursive( XClass outer, Collection c )
817 |  |
         {
818 | 84 |
             for( Iterator inners = outer.getInnerClasses().iterator(); inners.hasNext();  )
819 |  |
             {
820 | 52 |
                 XClass inner = (XClass) inners.next();
821 |  |
822 | 52 |
                 c.add( inner );
823 | 52 |
                 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 | 4880 |
         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 | 4880 |
             AbstractFile sourceFile = getSourceFile( qualifiedName );
847 |  |
848 | 4880 |
             if( sourceFile != null )
849 |  |
             {
850 | 1120 |
                 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 | 4880 |
             boolean sourceFileExists = sourceFile != null;
859 |  |
860 | 4880 |
             if( !sourceFileExists )
861 |  |
             {
862 | 3760 |
                 sourceFileExists = _abstractFileClasses.containsKey( qualifiedName );
863 |  |
             }
864 |  |
865 | 4880 |
             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 | 672 |
         private SourceClass scanAndPut( String qualifiedName )
875 |  |
         {
876 | 672 |
             AbstractFile sourceFile = getSourceFile( qualifiedName );
877 |  |
878 | 672 |
             sourceFile = sourceFile != null ? sourceFile : ( AbstractFile ) _abstractFileClasses.get( qualifiedName );
879 |  |
880 | 672 |
             if( sourceFile == null )
881 |  |
             {
882 | 0 |
                 throw new IllegalStateException( "No source found for " + qualifiedName );
883 |  |
             }
884 |  |
885 | 672 |
             SourceClass sourceClass = new SourceClass( this, sourceFile, _useNodeParser, _tagFactory ,_encoding);
886 |  |
887 |  |
             // now that the entire file is parsed, validate the tags.
888 | 672 |
             if( _tagFactory.isValidating() )
889 |  |
             {
890 | 0 |
                 sourceClass.validateTags();
891 |  |
             }
892 |  |
893 |  |
     //        addSourceClass( sourceClass );
894 |  |
895 | 672 |
             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 |  |