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 * ({@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 public static void parsePropertyString( String value, List fragments, List propertyRefs )
201 {
202 int prev = 0;
203 int pos;
204
205 while( ( pos = value.indexOf( '$', prev ) ) >= 0 )
206 {
207
208 if( pos > 0 )
209 {
210 String fragment = value.substring( prev, pos );
211
212 fragments.add( fragment );
213 }
214
215 if( pos == ( value.length() - 1 ) )
216 {
217 fragments.add( "$" );
218 prev = pos + 1;
219 }
220 else if( value.charAt( pos + 1 ) != '{' )
221 {
222 fragments.add( value.substring( pos, pos + 1 ) );
223 prev = pos + 1;
224 }
225 else
226 {
227 int endName = value.indexOf( '}', pos );
228
229 if( endName < 0 )
230 {
231
232
233
234 String fragment = value.substring( pos );
235
236 fragments.add( fragment );
237 continue;
238 }
239
240 String propertyName = value.substring( pos + 2, endName );
241
242 fragments.add( null );
243 propertyRefs.add( propertyName );
244 prev = endName + 1;
245 }
246 }
247
248 if( prev < value.length() )
249 {
250 String fragment = value.substring( prev );
251
252 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 static Primitive getPrimitive( String name )
263 {
264 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 static AbstractFile getSourceFileFor( XProgramElement pe )
277 {
278 SourceClass containingClass = null;
279
280 if( !( pe instanceof SourceClass ) )
281 {
282
283 containingClass = ( SourceClass ) pe.getContainingClass();
284 }
285 else
286 {
287 containingClass = ( SourceClass ) pe;
288 }
289
290 while( containingClass.getContainingClass() != null )
291 {
292 containingClass = ( SourceClass ) containingClass.getContainingClass();
293 }
294 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 private final void addPrimitive( String name, String type )
304 {
305 _primitiveClasses.put( name, new Primitive( this, name, type ) );
306 }
307
308 public Collection getSourceClasses( Predicate predicate )
309 {
310 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 public Collection getSourceClasses()
319 {
320 if( _sourceSetSourceClassesWithInnerClasses.isEmpty() )
321 {
322
323 _sourceSetSourceClassesWithInnerClasses.addAll( getOuterSourceClasses() );
324
325
326 for( Iterator outers = getOuterSourceClasses().iterator(); outers.hasNext(); )
327 {
328 addInnerClassRecursive( (XClass) outers.next(), _sourceSetSourceClassesWithInnerClasses );
329 }
330 }
331 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 public Collection getSourcePackages()
340 {
341 Set packages = new TreeSet();
342 Collection classes = getSourceClasses();
343
344 for( Iterator i = classes.iterator(); i.hasNext(); )
345 {
346 packages.add( ((XClass)i.next()).getContainingPackage() );
347 }
348
349 return Collections/unmodifiableCollection( packages )/package-summary.html">g> Collections.unmodifiableCollection( packages );
350 }
351
352 public Map getPropertyMap()
353 {
354 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 public XClass getXClass( String qualifiedName )
371 {
372 if( qualifiedName.equals( "" ) )
373 {
374 throw new IllegalStateException( "Classname can't be empty String" );
375 }
376
377 XClass result = null;
378 Primitive primitive;
379 SourceClass sourceClass;
380 BinaryClass binaryClass;
381 UnknownClass unknownClass;
382
383
384 if( ( primitive = getPrimitive( qualifiedName ) ) != null )
385 {
386 result = primitive;
387 }
388 else if( ( sourceClass = ( SourceClass ) _allSourceClasses.get( qualifiedName ) ) != null )
389 {
390 result = sourceClass;
391 }
392 else if( ( binaryClass = ( BinaryClass ) _binaryClasses.get( qualifiedName ) ) != null )
393 {
394 result = binaryClass;
395 }
396 else if( ( unknownClass = ( UnknownClass ) _unknownClasses.get( qualifiedName ) ) != null )
397 {
398 result = unknownClass;
399 }
400 else
401 {
402
403 if( sourceExists( qualifiedName ) )
404 {
405
406 sourceClass = scanAndPut( qualifiedName );
407 result = sourceClass;
408 }
409 else
410 {
411
412
413 Class clazz = getClass( qualifiedName );
414
415 if( clazz != null )
416 {
417 binaryClass = new BinaryClass( this, clazz );
418 _binaryClasses.put( qualifiedName, binaryClass );
419 result = binaryClass;
420 }
421 else
422 {
423
424 result = new UnknownClass( this, qualifiedName );
425 _unknownClasses.put( qualifiedName, result );
426 }
427 }
428 }
429 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 public XPackage getSourcePackage( String packageName )/package-summary.html">> XPackage getSourcePackage( String packageName )
441 {
442
443 for( Iterator i = getSourcePackages().iterator(); i.hasNext(); )
444 {
445 XPackage p = ( XPackage ) i.next();
446
447 if( p/getName()/equals( packageName ) )/package-summary.html">g>( p.getName().equals( packageName ) )
448 {
449 return p;
450 }
451 }
452 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 public void setUseNodeParser( boolean useNodeParser )
462 {
463 _useNodeParser = useNodeParser;
464 }
465
466 public void setPropertyMap( Map properties )
467 {
468 _properties.putAll( properties );
469 }
470
471 /***
472 * Resets the caches.
473 *
474 * @param resetTimeStamp true if timestamps should be reset too.
475 */
476 public void reset( boolean resetTimeStamp )
477 {
478 for( Iterator iterator = _packages.values().iterator(); iterator.hasNext(); )
479 {
480 XPackage xPackage = (XPackage) iterator.next();
481
482 for( Iterator i = xPackage.getClasses().iterator(); i.hasNext(); )
483 {
484 AbstractClass clazz = ( AbstractClass ) i.next();
485
486 clazz.reset();
487 }
488 }
489 _binaryClasses.clear();
490 _unknownClasses.clear();
491 _packages.clear();
492 _sourceSets.clear();
493 _sourceSetSourceClasses.clear();
494 _sourceSetClassNames.clear();
495 _allSourceClasses.clear();
496 _sourceSetSourceClassesWithInnerClasses.clear();
497
498 _logMessages.clear();
499 _properties.clear();
500 _abstractFileClasses.clear();
501
502
503
504
505
506
507
508
509 if( resetTimeStamp )
510 {
511 _birthday = System.currentTimeMillis();
512 }
513 }
514
515 /***
516 * Prints the log messages encountered during parsing
517 *
518 * @param out
519 * @param level
520 */
521 public void printLogMessages( PrintStream out, int level )
522 {
523 boolean printedHeader = false;
524
525 for( Iterator i = _logMessages.iterator(); i.hasNext(); )
526 {
527 LogMessage m = ( LogMessage ) i.next();
528
529 if( m._level == level )
530 {
531 if( !printedHeader )
532 {
533 if( level == ONE_OR_MORE_IMPORTED_PACKAGES )
534 {
535
536 out.println( "WARNING: Some classes refer to other classes that were not found among the sources or on the classpath." );
537 out.println( " (Perhaps the referred class doesn't exist? Hasn't been generated yet?)" );
538 out.println( " The referring classes do not import any fully qualified classes matching these classes." );
539 out.println( " Since at least one package is imported, it is impossible for xjavadoc to figure out" );
540 out.println( " what package the referred classes belong to. The classes are:" );
541 }
542 else
543 {
544 out.println( "INFO: Some classes refer to other classes that were not found among the sources or on the classpath." );
545 out.println( " (Perhaps the referred class doesn't exist? Hasn't been generated yet?)" );
546 out.println( " The referring classes do not import any fully qualified classes matching these classes." );
547 out.println( " However, since no packages are imported, xjavadoc has assumed that the referred classes" );
548 out.println( " belong to the same package as the referring class. The classes are:" );
549 }
550 printedHeader = true;
551 }
552 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 public void addSourceSet( SourceSet sourceSet )
563 {
564 _sourceSets.add( sourceSet );
565 for( int j = 0; j < sourceSet.getSize(); j++ )
566 {
567 String qualifiedName = sourceSet.getQualifiedName( j );
568
569 if( _sourceSetClassNames.contains( qualifiedName ) )
570 {
571 String msg = "The class \"" + qualifiedName + "\" occurs in more than one fileset. That's illegal.";
572
573 System.err.println( msg );
574 }
575 _sourceSetClassNames.add( qualifiedName );
576 }
577 }
578
579 public void addAbstractFile( String qualifiedName, AbstractFile file )
580 {
581 _abstractFileClasses.put( qualifiedName, file );
582
583 if( _sourceSetClassNames.contains( qualifiedName ) )
584 {
585 String msg = "The class \"" + qualifiedName + "\" occurs in more than one fileset. That's illegal.";
586
587 System.err.println( msg );
588 }
589 _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 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 XClass clazz = getXClass( className );
617 XMethod method = clazz.getMethod( methodNameWithSignature );
618
619 XDoc doc = method.getDoc();
620
621 doc.updateTagValue( tagName, parameterName, parameterValue, tagIndex );
622
623 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 public XClass updateClassTag(
638 String className,
639 String tagName,
640 String parameterName,
641 String parameterValue,
642 int tagIndex
643 ) throws XJavaDocException
644 {
645 XClass clazz = getXClass( className );
646 XDoc doc = clazz.getDoc();
647
648 doc.updateTagValue( tagName, parameterName, parameterValue, tagIndex );
649 return clazz;
650 }
651
652 public String dereferenceProperties( String value )
653 {
654
655 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 final boolean classExists( final String qualifiedClassName )
664 {
665
666 if( sourceExists( qualifiedClassName ) )
667 {
668 return true;
669 }
670
671 else if( getClass( qualifiedClassName ) != null )
672 {
673 return true;
674 }
675 else
676 {
677 return false;
678 }
679 }
680
681 void logMessage( SourceClass clazz, UnknownClass unknownClass, String unqualifiedClassName, int level )
682 {
683 _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 XPackage addPackageMaybe( String packageName )
693 {
694 XPackage result = ( XPackage ) _packages.get( packageName );
695
696 if( result == null )
697 {
698
699 resXPackage( packageName )/package-summary.html">ult = new XPackage( packageName );
700 _packages.put( packageName, result );
701 }
702 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 void addSourceClass( SourceClass sourceClass )
712 {
713 _allSourceClasses.put( sourceClass.getQualifiedName(), sourceClass );
714
715
716
717 if( _sourceSetClassNames.contains( sourceClass.getQualifiedName() ) || sourceClass.isExtraClass() )
718 {
719 _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 private final Class getClass( String qualifiedName )
730 {
731 try
732 {
733 return Class.forName( qualifiedName, false, getClass().getClassLoader() );
734 }
735 catch( Throwable e )
736 {
737
738
739 return null;
740 }
741 }
742
743 /***
744 * Returns all classes in the registered source sets
745 *
746 * @return A Collection of XClass
747 */
748 private Collection getOuterSourceClasses()
749 {
750 if( _sourceSetSourceClasses.isEmpty() )
751 {
752 for( Iterator i = _sourceSetClassNames.iterator(); i.hasNext(); )
753 {
754 String qualifiedName = ( String ) i.next();
755
756
757
758
759
760 getXClass( qualifiedName );
761 }
762
763 for( Iterator iterator = _abstractFileClasses.keySet().iterator(); iterator.hasNext(); )
764 {
765 String fqcn = ( String ) iterator.next();
766
767 getXClass( fqcn );
768 }
769 }
770
771
772
773
774
775 Collection new_collection = new ArrayList( _sourceSetSourceClasses.values() );
776
777 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 private AbstractFile getSourceFile( String qualifiedName )
787 {
788
789 AbstractFile found = null;
790
791 for( Iterator i = _sourceSets.iterator(); i.hasNext(); )
792 {
793 SourceSet sourceSet = ( SourceSet ) i.next();
794 AbstractFile javaFile = sourceSet.getSourceFile( qualifiedName );
795
796 if( javaFile != null )
797 {
798
799
800
801
802
803
804 found = javaFile;
805 }
806 }
807 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 private void addInnerClassRecursive( XClass outer, Collection c )
817 {
818 for( Iterator inners = outer.getInnerClasses().iterator(); inners.hasNext(); )
819 {
820 XClass inner = (XClass) inners.next();
821
822 c.add( inner );
823 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 private boolean sourceExists( String qualifiedName )
834 {
835
836
837
838
839
840
841
842
843
844
845
846 AbstractFile sourceFile = getSourceFile( qualifiedName );
847
848 if( sourceFile != null )
849 {
850 if( sourceFile.lastModified() > _birthday )
851 {
852
853 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 return false;
855 }
856 }
857
858 boolean sourceFileExists = sourceFile != null;
859
860 if( !sourceFileExists )
861 {
862 sourceFileExists = _abstractFileClasses.containsKey( qualifiedName );
863 }
864
865 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 private SourceClass scanAndPut( String qualifiedName )
875 {
876 AbstractFile sourceFile = getSourceFile( qualifiedName );
877
878 sourceFile = sourceFile != null ? sourceFile : ( AbstractFile ) _abstractFileClasses.get( qualifiedName );
879
880 if( sourceFile == null )
881 {
882 throw new IllegalStateException( "No source found for " + qualifiedName );
883 }
884
885 SourceClass sourceClass = new SourceClass( this, sourceFile, _useNodeParser, _tagFactory ,_encoding);
886
887
888 if( _tagFactory.isValidating() )
889 {
890 sourceClass.validateTags();
891 }
892
893
894
895 return sourceClass;
896 }
897
898 public XTagFactory getTagFactory() {
899 return _tagFactory;
900 }
901
902 /***
903 * Registers tags.
904 *
905 * @param classpath where tags are found.
906 */
907 public void registerTags( String classpath ) {
908 new TagIntrospector().registerTags( classpath, getTagFactory() );
909 }
910
911 public final static class NoInnerClassesPredicate implements Predicate
912 {
913 public boolean evaluate( Object o )
914 {
915 XClass clazz = ( XClass ) o;
916
917 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 LogMessage( SourceClass sourceClass, UnknownClass unknownClass, String unqualifiedClassName, int level )
928 {
929 _sourceClass = sourceClass;
930 _unknownClass = unknownClass;
931 _unqualifiedClassName = unqualifiedClassName;
932 _level = level;
933 }
934 }
935
936 /***
937 * Getter for source file charset.
938 * @return encoding
939 */
940 public String getEncoding() {
941 return _encoding;
942 }
943
944 /***
945 * Setter for source file charset.
946 * @param string encoding
947 */
948 public void setEncoding(String encoding) {
949 _encoding = encoding;
950 }
951
952 /***
953 * Getter for generated file charset.
954 * @return encoding
955 */
956 public String getDocEncoding() {
957 return _docEncoding;
958 }
959
960 /***
961 * Setter for generated file charset.
962 * @param string encoding
963 */
964 public void setDocEncoding(String docencoding) {
965 _docEncoding = docencoding;
966 }
967
968 }