1
2
3
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()/package-summary.html">> 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 public XJavaDoc()
113 {
114 _birthday = System.currentTimeMillis();
115 for( int i = 0; i < PRIMITIVES.size(); i += 2 )
116 {
117 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 public static void printMemoryStatus()
125 {
126 System.out.println( "ParameterImpl instances: " + ParameterImpl.instanceCount );
127 System.out.println( "MethodImpl instances: " + MethodImpl.instanceCount );
128 System.out.println( "ConstructorImpl instances: " + ConstructorImpl.instanceCount );
129 System.out.println( "SimpleNode instances: " + SimpleNode.instanceCount );
130 System.out.println( "SourceClass instances: " + SourceClass.instanceCount );
131 System.out.println( "XDoc instances: " + XDoc.instanceCount );
132 System.out.println( "DefaultXTag instances: " + DefaultXTag.instanceCount );
133 System.out.println( "BinaryClass instances: " + BinaryClass.instanceCount );
134 System.out.println( "UnknownClass instances: " + UnknownClass.instanceCount );
135
136 System.out.println( "Total memory: " + ( Runtime.getRuntime().totalMemory() / ( 1024 * 1024 ) ) );
137 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 public static String replaceProperties( String value, Map keys )
155 {
156 if( value == null )
157 {
158 return null;
159 }
160
161 ArrayList fragments = new ArrayList();
162 ArrayList propertyRefs = new ArrayList();
163
164 parsePropertyString( value, fragments, propertyRefs );
165
166 StringBuffer sbuf = new StringBuffer();
167 Iterator i = fragments.iterator();
168 Iterator j = propertyRefs.iterator();
169
170 while( i.hasNext() )
171 {
172 String fragment = ( String ) i.next();
173
174 if( fragment == null )
175 {
176 String propertyName = ( String ) j.next();
177
178 fragment = ( keys.containsKey( propertyName ) ) ? ( String ) keys.get( propertyName )
179 : "${" + propertyName + '}';
180 }
181 sbuf.append( fragment );
182 }
183
184 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 * (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 * .
199 * @param propertyRefs List to add property names to. Must not be <code>null</code>
200 */
201 public static void parsePropertyString( String value, List fragments, List propertyRefs )
202 {
203 int prev = 0;
204 int pos;
205
206 while( ( pos = value.indexOf( '$', prev ) ) >= 0 )
207 {
208
209 if( pos > 0 )
210 {
211 String fragment = value.substring( prev, pos );
212
213 fragments.add( fragment );
214 }
215
216 if( pos == ( value.length() - 1 ) )
217 {
218 fragments.add( "$" );
219 prev = pos + 1;
220 }
221 else if( value.charAt( pos + 1 ) != '{' )
222 {
223 fragments.add( value.substring( pos, pos + 1 ) );
224 prev = pos + 1;
225 }
226 else
227 {
228 int endName = value.indexOf( '}', pos );
229
230 if( endName < 0 )
231 {
232
233
234
235 String fragment = value.substring( pos );
236
237 fragments.add( fragment );
238 continue;
239 }
240
241 String propertyName = value.substring( pos + 2, endName );
242
243 fragments.add( null );
244 propertyRefs.add( propertyName );
245 prev = endName + 1;
246 }
247 }
248
249 if( prev < value.length() )
250 {
251 String fragment = value.substring( prev );
252
253 fragments.add( fragment );
254 }
255 }
256
257 /***
258 * Gets the Primitive attribute of the XJavaDoc class
259 *
260 * @param name Describe what the parameter does
261 * @return The Primitive value
262 */
263 static Primitive getPrimitive( String name )
264 {
265 return ( Primitive ) _primitiveClasses.get( name );
266 }
267
268 /***
269 * Gets the file the pe is contained in. Note: calling this method with a
270 * XProgramElement not from source (but from a binary or unknown class) will
271 * result in a ClassCastException, so don't do that. This method is only used
272 * for diagnostics in error reporting.
273 *
274 * @param pe the program element we want the source for.
275 * @return the file the program element is contained in.
276 */
277 static AbstractFile getSourceFileFor( XProgramElement pe )
278 {
279 SourceClass containingClass = null;
280
281 if( !( pe instanceof SourceClass ) )
282 {
283
284 containingClass = ( SourceClass ) pe.getContainingClass();
285 }
286 else
287 {
288 containingClass = ( SourceClass ) pe;
289 }
290
291 while( containingClass.getContainingClass() != null )
292 {
293 containingClass = ( SourceClass ) containingClass.getContainingClass();
294 }
295 return containingClass.getFile();
296 }
297
298 /***
299 * Describe the method
300 *
301 * @param name Describe the method parameter
302 * @param type The feature to be added to the Primitive attribute
303 */
304 private final void addPrimitive( String name, String type )
305 {
306 _primitiveClasses.put( name, new Primitive( this, name, type ) );
307 }
308
309 public Collection getSourceClasses( Predicate predicate )
310 {
311 return CollectionUtils.select( getSourceClasses(), predicate );
312 }
313
314 /***
315 * @param useNodeParser
316 * @param inner
317 * @return A Collection of XClass
318 * @deprecated Call setUseNodeParser() prior to parsing and call the
319 * no-arg getSourceClasses() or getSourceClasses(Predicate) with a
320 * Predicate that doesn't accept inner classes.
321 */
322 public Collection getSourceClasses( boolean useNodeParser, boolean inner )
323 {
324 if( inner )
325 {
326 return getSourceClasses();
327 }
328 else
329 {
330 return getSourceClasses( new NoInnerClassesPredicate() );
331 }
332 }
333
334 /***
335 * @param useNodeParser
336 * @return A Collection of XClass
337 * @deprecated Call setUseNodeParser() prior to parsing and call the
338 * no-arg getSourceClasses()
339 */
340 public Collection getSourceClasses( boolean useNodeParser )
341 {
342 return getSourceClasses();
343 }
344
345 /***
346 * Returns all classes in the registered source sets, including inner classes
347 *
348 * @return A Collection of XClass
349 */
350 public Collection getSourceClasses()
351 {
352 if( _sourceSetSourceClassesWithInnerClasses.isEmpty() )
353 {
354
355 _sourceSetSourceClassesWithInnerClasses.addAll( getOuterSourceClasses() );
356
357
358 for( Iterator outers = getOuterSourceClasses().iterator(); outers.hasNext(); )
359 {
360 addInnerClassRecursive( (XClass) outers.next(), _sourceSetSourceClassesWithInnerClasses );
361 }
362 }
363 return Collections.unmodifiableCollection( _sourceSetSourceClassesWithInnerClasses );
364 }
365
366 /***
367 * Returns the packages of the specified classes during parsing.
368 *
369 * @return Describe the return value
370 */
371 public Collection getSourcePackages()
372 {
373 Set packages = new TreeSet();
374 Collection classes = getSourceClasses();
375
376 for( Iterator i = classes.iterator(); i.hasNext(); )
377 {
378 packages.add( ((XClass)i.next()).getContainingPackage() );
379 }
380
381 return Collections/unmodifiableCollection( packages )/package-summary.html">g> Collections.unmodifiableCollection( packages );
382 }
383
384 public Map getPropertyMap()
385 {
386 return Collections.unmodifiableMap( _properties );
387 }
388
389 /***
390 * Get the XClass corresponding to the qualifiedName. This can be a class from
391 * source, a precompiled class or a primitive. UnknownClass is never returned
392 * from this method, unless it has been previously instantiated. <b>IMPORTANT:
393 * </b> If the Java source can be located, an instance of SourceClass will be
394 * returned. -Even if that file was not among the files in the fileset or
395 * sourceset. <b>IMPORTANT: </b> If qualifiedName represents an inner class, an
396 * UnknownClass will be returned unless the enclousing "outer" class has been
397 * resolved first.
398 *
399 * @param qualifiedName Fully qualified class name
400 * @return The XClass value
401 */
402 public XClass getXClass( String qualifiedName )
403 {
404 if( qualifiedName.equals( "" ) )
405 {
406 throw new IllegalStateException( "Classname can't be empty String" );
407 }
408
409 XClass result = null;
410 Primitive primitive;
411 SourceClass sourceClass;
412 BinaryClass binaryClass;
413 UnknownClass unknownClass;
414
415
416 if( ( primitive = getPrimitive( qualifiedName ) ) != null )
417 {
418 result = primitive;
419 }
420 else if( ( sourceClass = ( SourceClass ) _allSourceClasses.get( qualifiedName ) ) != null )
421 {
422 result = sourceClass;
423 }
424 else if( ( binaryClass = ( BinaryClass ) _binaryClasses.get( qualifiedName ) ) != null )
425 {
426 result = binaryClass;
427 }
428 else if( ( unknownClass = ( UnknownClass ) _unknownClasses.get( qualifiedName ) ) != null )
429 {
430 result = unknownClass;
431 }
432 else
433 {
434
435 if( sourceExists( qualifiedName ) )
436 {
437
438 sourceClass = scanAndPut( qualifiedName );
439 result = sourceClass;
440 }
441 else
442 {
443
444
445 Class clazz = getClass( qualifiedName );
446
447 if( clazz != null )
448 {
449 binaryClass = new BinaryClass( this, clazz );
450 _binaryClasses.put( qualifiedName, binaryClass );
451 result = binaryClass;
452 }
453 else
454 {
455
456 result = new UnknownClass( this, qualifiedName );
457 _unknownClasses.put( qualifiedName, result );
458 }
459 }
460 }
461 return result;
462 }
463
464 /***
465 * Returns the package. The package must be one of the packages of the sources.
466 * Other packages, such as java.lang are not available.
467 *
468 * @param packageName
469 * @return an XPackage, or null if the packageName is not among the
470 * sources.
471 */
472 public XPackage getSourcePackage( String packageName )/package-summary.html">> XPackage getSourcePackage( String packageName )
473 {
474
475 for( Iterator i = getSourcePackages().iterator(); i.hasNext(); )
476 {
477 XPackage p = ( XPackage ) i.next();
478
479 if( p/getName()/equals( packageName ) )/package-summary.html">g>( p.getName().equals( packageName ) )
480 {
481 return p;
482 }
483 }
484 return null;
485 }
486
487 /***
488 * This method can be called prior to parsing so that all classes are parsed
489 * with AST (to make it possible to write the source back to disk)
490 *
491 * @param useNodeParser
492 */
493 public void setUseNodeParser( boolean useNodeParser )
494 {
495 _useNodeParser = useNodeParser;
496 }
497
498 public void setPropertyMap( Map properties )
499 {
500 _properties.putAll( properties );
501 }
502
503 /***
504 * Resets the caches. Same as calling <code>reset(true)</code>.
505 *
506 * @deprecated use reset(boolean).
507 */
508 public void reset()
509 {
510 reset( true );
511 }
512
513 /***
514 * Resets the caches.
515 *
516 * @param resetTimeStamp true if timestamps should be reset too.
517 */
518 public void reset( boolean resetTimeStamp )
519 {
520 for( Iterator iterator = _packages.values().iterator(); iterator.hasNext(); )
521 {
522 XPackage xPackage = (XPackage) iterator.next();
523
524 for( Iterator i = xPackage.getClasses().iterator(); i.hasNext(); )
525 {
526 AbstractClass clazz = ( AbstractClass ) i.next();
527
528 clazz.reset();
529 }
530 }
531 _binaryClasses.clear();
532 _unknownClasses.clear();
533 _packages.clear();
534 _sourceSets.clear();
535 _sourceSetSourceClasses.clear();
536 _sourceSetClassNames.clear();
537 _allSourceClasses.clear();
538 _sourceSetSourceClassesWithInnerClasses.clear();
539
540 _logMessages.clear();
541 _properties.clear();
542 _abstractFileClasses.clear();
543
544
545
546
547
548
549
550
551 if( resetTimeStamp )
552 {
553 _birthday = System.currentTimeMillis();
554 }
555 }
556
557 /***
558 * Prints the log messages encountered during parsing
559 *
560 * @param out
561 * @param level
562 */
563 public void printLogMessages( PrintStream out, int level )
564 {
565 boolean printedHeader = false;
566
567 for( Iterator i = _logMessages.iterator(); i.hasNext(); )
568 {
569 LogMessage m = ( LogMessage ) i.next();
570
571 if( m._level == level )
572 {
573 if( !printedHeader )
574 {
575 if( level == ONE_OR_MORE_IMPORTED_PACKAGES )
576 {
577
578 out.println( "WARNING: Some classes refer to other classes that were not found among the sources or on the classpath." );
579 out.println( " (Perhaps the referred class doesn't exist? Hasn't been generated yet?)" );
580 out.println( " The referring classes do not import any fully qualified classes matching these classes." );
581 out.println( " Since at least one package is imported, it is impossible for xjavadoc to figure out" );
582 out.println( " what package the referred classes belong to. The classes are:" );
583 }
584 else
585 {
586 out.println( "INFO: Some classes refer to other classes that were not found among the sources or on the classpath." );
587 out.println( " (Perhaps the referred class doesn't exist? Hasn't been generated yet?)" );
588 out.println( " The referring classes do not import any fully qualified classes matching these classes." );
589 out.println( " However, since no packages are imported, xjavadoc has assumed that the referred classes" );
590 out.println( " belong to the same package as the referring class. The classes are:" );
591 }
592 printedHeader = true;
593 }
594 out.println( m._sourceClass.getFile().getPath() + " --> " + m._unqualifiedClassName + " qualified to " + m._unknownClass.getQualifiedName() );
595 }
596 }
597 }
598
599 /***
600 * Adds a new set of java sources to be parsed.
601 *
602 * @param sourceSet a set of java sources.
603 */
604 public void addSourceSet( SourceSet sourceSet )
605 {
606 _sourceSets.add( sourceSet );
607 for( int j = 0; j < sourceSet.getSize(); j++ )
608 {
609 String qualifiedName = sourceSet.getQualifiedName( j );
610
611 if( _sourceSetClassNames.contains( qualifiedName ) )
612 {
613 String msg = "The class \"" + qualifiedName + "\" occurs in more than one fileset. That's illegal.";
614
615 System.err.println( msg );
616 }
617 _sourceSetClassNames.add( qualifiedName );
618 }
619 }
620
621 public void addAbstractFile( String qualifiedName, AbstractFile file )
622 {
623 _abstractFileClasses.put( qualifiedName, file );
624
625 if( _sourceSetClassNames.contains( qualifiedName ) )
626 {
627 String msg = "The class \"" + qualifiedName + "\" occurs in more than one fileset. That's illegal.";
628
629 System.err.println( msg );
630 }
631 _sourceSetClassNames.add( qualifiedName );
632 }
633
634 /***
635 * Describe what the method does
636 *
637 * @param className qualified name of class
638 * @param tagName tag name
639 * @param parameterName parameter name
640 * @param parameterValue new parameter value
641 * @param tagIndex index of tag (??)
642 * @param methodNameWithSignature method name followed by signature. no
643 * spaces. Ex:<br>
644 * <code>doIt(java.lang.String,int)</code>
645 * @return the class corresponding to the className
646 * @exception XJavaDocException If the tag for some reason couldn't be
647 * updated
648 */
649 public XClass updateMethodTag(
650 String className,
651 String methodNameWithSignature,
652 String tagName,
653 String parameterName,
654 String parameterValue,
655 int tagIndex
656 ) throws XJavaDocException
657 {
658 XClass clazz = getXClass( className );
659 XMethod method = clazz.getMethod( methodNameWithSignature );
660
661 XDoc doc = method.getDoc();
662
663 doc.updateTagValue( tagName, parameterName, parameterValue, tagIndex );
664
665 return clazz;
666 }
667
668 /***
669 * Describe what the method does
670 *
671 * @param className Describe what the parameter does
672 * @param tagName Describe what the parameter does
673 * @param parameterName Describe what the parameter does
674 * @param parameterValue Describe what the parameter does
675 * @param tagIndex Describe what the parameter does
676 * @return Describe the return value
677 * @exception XJavaDocException Describe the exception
678 */
679 public XClass updateClassTag(
680 String className,
681 String tagName,
682 String parameterName,
683 String parameterValue,
684 int tagIndex
685 ) throws XJavaDocException
686 {
687 XClass clazz = getXClass( className );
688 XDoc doc = clazz.getDoc();
689
690 doc.updateTagValue( tagName, parameterName, parameterValue, tagIndex );
691 return clazz;
692 }
693
694 public String dereferenceProperties( String value )
695 {
696
697 return replaceProperties( value, _properties );
698 }
699
700 /***
701 * @param qualifiedClassName
702 * @return true if the class exists, either as source or
703 * binary
704 */
705 final boolean classExists( final String qualifiedClassName )
706 {
707
708 if( sourceExists( qualifiedClassName ) )
709 {
710 return true;
711 }
712
713 else if( getClass( qualifiedClassName ) != null )
714 {
715 return true;
716 }
717 else
718 {
719 return false;
720 }
721 }
722
723 void logMessage( SourceClass clazz, UnknownClass unknownClass, String unqualifiedClassName, int level )
724 {
725 _logMessages.add( new LogMessage( clazz, unknownClass, unqualifiedClassName, level ) );
726 }
727
728 /***
729 * Describe the method
730 *
731 * @param packageName Describe the method parameter
732 * @return Describe the return value
733 */
734 XPackage addPackageMaybe( String packageName )
735 {
736 XPackage result = ( XPackage ) _packages.get( packageName );
737
738 if( result == null )
739 {
740
741 resXPackage( packageName )/package-summary.html">ult = new XPackage( packageName );
742 _packages.put( packageName, result );
743 }
744 return result;
745 }
746
747 /***
748 * Adds a source class to the cache. This method is also called from JavaParser
749 * when parsing inner classes.
750 *
751 * @param sourceClass Describe the method parameter
752 */
753 void addSourceClass( SourceClass sourceClass )
754 {
755 _allSourceClasses.put( sourceClass.getQualifiedName(), sourceClass );
756
757
758
759 if( _sourceSetClassNames.contains( sourceClass.getQualifiedName() ) || sourceClass.isExtraClass() )
760 {
761 _sourceSetSourceClasses.put( sourceClass.getQualifiedName(), sourceClass );
762 }
763 }
764
765 /***
766 * Returns the Class with the given name, or null if unknown.
767 *
768 * @param qualifiedName Describe what the parameter does
769 * @return The Class value
770 */
771 private final Class getClass( String qualifiedName )
772 {
773 try
774 {
775 return Class.forName( qualifiedName, false, getClass().getClassLoader() );
776 }
777 catch( Throwable e )
778 {
779
780
781 return null;
782 }
783 }
784
785 /***
786 * Returns all classes in the registered source sets
787 *
788 * @return A Collection of XClass
789 */
790 private Collection getOuterSourceClasses()
791 {
792 if( _sourceSetSourceClasses.isEmpty() )
793 {
794 for( Iterator i = _sourceSetClassNames.iterator(); i.hasNext(); )
795 {
796 String qualifiedName = ( String ) i.next();
797
798
799
800
801
802 getXClass( qualifiedName );
803 }
804
805 for( Iterator iterator = _abstractFileClasses.keySet().iterator(); iterator.hasNext(); )
806 {
807 String fqcn = ( String ) iterator.next();
808
809 getXClass( fqcn );
810 }
811 }
812
813
814
815
816
817 Collection new_collection = new ArrayList( _sourceSetSourceClasses.values() );
818
819 return Collections.unmodifiableCollection( new_collection );
820 }
821
822 /***
823 * Gets the SourceFile attribute of the XJavaDoc object
824 *
825 * @param qualifiedName Describe what the parameter does
826 * @return The SourceFile value
827 */
828 private AbstractFile getSourceFile( String qualifiedName )
829 {
830
831 AbstractFile found = null;
832
833 for( Iterator i = _sourceSets.iterator(); i.hasNext(); )
834 {
835 SourceSet sourceSet = ( SourceSet ) i.next();
836 AbstractFile javaFile = sourceSet.getSourceFile( qualifiedName );
837
838 if( javaFile != null )
839 {
840
841
842
843
844
845
846 found = javaFile;
847 }
848 }
849 return found;
850 }
851
852 /***
853 * Recursively adds inner classes to a collection
854 *
855 * @param outer The feature to be added to the InnerClassRecursive attribute
856 * @param c The feature to be added to the InnerClassRecursive attribute
857 */
858 private void addInnerClassRecursive( XClass outer, Collection c )
859 {
860 for( Iterator inners = outer.getInnerClasses().iterator(); inners.hasNext(); )
861 {
862 XClass inner = (XClass) inners.next();
863
864 c.add( inner );
865 addInnerClassRecursive( inner, c );
866 }
867 }
868
869 /***
870 * Checks is the source exists
871 *
872 * @param qualifiedName the class to check for
873 * @return true if source exists.
874 */
875 private boolean sourceExists( String qualifiedName )
876 {
877
878
879
880
881
882
883
884
885
886
887
888 AbstractFile sourceFile = getSourceFile( qualifiedName );
889
890 if( sourceFile != null )
891 {
892 if( sourceFile.lastModified() > _birthday )
893 {
894
895 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 ) + ")" );
896 return false;
897 }
898 }
899
900 boolean sourceFileExists = sourceFile != null;
901
902 if( !sourceFileExists )
903 {
904 sourceFileExists = _abstractFileClasses.containsKey( qualifiedName );
905 }
906
907 return sourceFileExists;
908 }
909
910 /***
911 * Scan's a class and puts it in the cache.
912 *
913 * @param qualifiedName Describe what the parameter does
914 * @return Describe the return value
915 */
916 private SourceClass scanAndPut( String qualifiedName )
917 {
918 AbstractFile sourceFile = getSourceFile( qualifiedName );
919
920 sourceFile = sourceFile != null ? sourceFile : ( AbstractFile ) _abstractFileClasses.get( qualifiedName );
921
922 if( sourceFile == null )
923 {
924 throw new IllegalStateException( "No source found for " + qualifiedName );
925 }
926
927 SourceClass sourceClass = new SourceClass( this, sourceFile, _useNodeParser, _tagFactory ,_encoding);
928
929
930 if( _tagFactory.isValidating() )
931 {
932 sourceClass.validateTags();
933 }
934
935
936
937 return sourceClass;
938 }
939
940 public XTagFactory getTagFactory() {
941 return _tagFactory;
942 }
943
944 /***
945 * Registers tags.
946 *
947 * @param classpath where tags are found.
948 */
949 public void registerTags( String classpath ) {
950 new TagIntrospector().registerTags( classpath, getTagFactory() );
951 }
952
953 public final static class NoInnerClassesPredicate implements Predicate
954 {
955 public boolean evaluate( Object o )
956 {
957 XClass clazz = ( XClass ) o;
958
959 return !clazz.isInner();
960 }
961 }
962
963 class LogMessage
964 {
965 public final SourceClass _sourceClass;
966 public final UnknownClass _unknownClass;
967 public final String _unqualifiedClassName;
968 public final int _level;
969 LogMessage( SourceClass sourceClass, UnknownClass unknownClass, String unqualifiedClassName, int level )
970 {
971 _sourceClass = sourceClass;
972 _unknownClass = unknownClass;
973 _unqualifiedClassName = unqualifiedClassName;
974 _level = level;
975 }
976 }
977
978 /***
979 * Getter for source file charset.
980 * @return encoding
981 */
982 public String getEncoding() {
983 return _encoding;
984 }
985
986 /***
987 * Setter for source file charset.
988 * @param string encoding
989 */
990 public void setEncoding(String encoding) {
991 _encoding = encoding;
992 }
993
994 /***
995 * Getter for generated file charset.
996 * @return encoding
997 */
998 public String getDocEncoding() {
999 return _docEncoding;
1000 }
1001
1002 /***
1003 * Setter for generated file charset.
1004 * @param string encoding
1005 */
1006 public void setDocEncoding(String docencoding) {
1007 _docEncoding = docencoding;
1008 }
1009
1010 }