OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [tools/] [gnu/] [classpath/] [tools/] [gjdoc/] [RootDocImpl.java] - Blame information for rev 779

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 779 jeremybenn
/* gnu.classpath.tools.gjdoc.RootDocImpl
2
   Copyright (C) 2001, 2007 Free Software Foundation, Inc.
3
 
4
   This file is part of GNU Classpath.
5
 
6
   GNU Classpath is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 2, or (at your option)
9
   any later version.
10
 
11
   GNU Classpath is distributed in the hope that it will be useful, but
12
   WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
   General Public License for more details.
15
 
16
   You should have received a copy of the GNU General Public License
17
   along with GNU Classpath; see the file COPYING.  If not, write to the
18
   Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19
   02111-1307 USA.
20
 
21
   Linking this library statically or dynamically with other modules is
22
   making a combined work based on this library.  Thus, the terms and
23
   conditions of the GNU General Public License cover the whole
24
   combination.
25
 
26
   As a special exception, the copyright holders of this library give you
27
   permission to link this library with independent modules to produce an
28
   executable, regardless of the license terms of these independent
29
   modules, and to copy and distribute the resulting executable under
30
   terms of your choice, provided that you also meet, for each linked
31
   independent module, the terms and conditions of the license of that
32
   module.  An independent module is a module which is not derived from
33
   or based on this library.  If you modify this library, you may extend
34
   this exception to your version of the library, but you are not
35
   obligated to do so.  If you do not wish to do so, delete this
36
   exception statement from your version. */
37
 
38
package gnu.classpath.tools.gjdoc;
39
 
40
import com.sun.javadoc.*;
41
import java.util.*;
42
import java.io.*;
43
import java.lang.reflect.*;
44
 
45
public class RootDocImpl
46
   extends DocImpl
47
   implements GjdocRootDoc {
48
 
49
   private ErrorReporter reporter = new ErrorReporter();
50
 
51
   private RandomAccessFile rawCommentCache;
52
 
53
   /**
54
    *  All options and their corresponding values which are not recognized
55
    *  by Gjdoc. These are passed to the Doclet as "custom options".
56
    *  Each element in this array is again a String array, with the
57
    *  option name as first element (including prefix dash) and possible
58
    *  option values as following elements.
59
    */
60
   private String[][] customOptionArr;
61
 
62
   /**
63
    *  All source files explicitly specified on the command line.
64
    *
65
    *  @contains File
66
    */
67
   private List specifiedSourceFiles = new LinkedList();
68
 
69
   /**
70
    *  The names of all packages explicitly specified on the
71
    *  command line.
72
    *
73
    *  @contains String
74
    */
75
   private Set specifiedPackageNames = new LinkedHashSet();
76
 
77
   /**
78
    *  Stores all classes specified by the user: those given by
79
    *  individual class names on the command line, and those
80
    *  contained in the packages given on the command line.
81
    *
82
    *  @contains ClassDocImpl
83
    */
84
   private List classesList = new LinkedList(); //new LinkedList();
85
 
86
   /**
87
    *  Stores all classes loaded in the course of preparing
88
    *  the documentation data. Maps the fully qualified name
89
    *  of a class to its ClassDocImpl representation.
90
    *
91
    *  @contains String->ClassDocImpl
92
    */
93
   private Map classDocMap = new HashMap();
94
 
95
   /**
96
    *  Stores all packages loaded in the course of preparing
97
    *  the documentation data. Maps the package name
98
    *  to its PackageDocImpl representation.
99
    *
100
    *  @contains String->PackageDocImpl
101
    */
102
   private Map packageDocMap = new HashMap();
103
 
104
   /**
105
    *  All classes specified by the user, both those explicitly
106
    *  individually specified on the command line and those contained
107
    *  in packages specified on the command line (as Array for quick
108
    *  retrieval by Doclet).  This is created from classesList after
109
    *  all classes have been loaded.
110
    */
111
   private ClassDocImpl[] classes;
112
 
113
   /**
114
    *  All classes which were individually specified on the command
115
    *  line (as Array for quick retrieval by Doclet). This is created
116
    *  from specifiedClassNames after all classes have been loaded.
117
    */
118
   private List specifiedClasses;
119
 
120
   /**
121
    *  All packages which were specified on the command line (as Array
122
    *  for quick retrieval by Doclet). This is created from
123
    *  specifiedPackageNames after all classes have been loaded.
124
    */
125
   private Set specifiedPackages;
126
 
127
 
128
   /**
129
    *  Temporarily stores a list of classes which are referenced
130
    *  by classes already loaded and which still have to be
131
    *  resolved.
132
    */
133
   private List scheduledClasses=new LinkedList();
134
 
135
   private List sourcePath;
136
 
137
   private String sourceEncoding;
138
 
139
   private Parser parser = new Parser();
140
 
141
   private Set unlocatableReportedSet = new HashSet();
142
 
143
   private Set inaccessibleReportedSet = new HashSet();
144
 
145
   //--------------------------------------------------------------------------
146
   //
147
   // Implementation of RootDoc interface
148
   //
149
   //--------------------------------------------------------------------------
150
 
151
   /**
152
    *  Return classes and interfaces to be documented.
153
    */
154
   public ClassDoc[] classes() { return classes; }
155
 
156
   /**
157
    *  Return a ClassDoc object for the specified class/interface
158
    *  name.
159
    *
160
    *  @return a ClassDoc object describing the given class, or
161
    *  <code>null</code> if no corresponding ClassDoc object
162
    *  has been constructed.
163
    */
164
   public ClassDoc classNamed(String qualifiedName) {
165
      return (ClassDoc)classDocMap.get(qualifiedName);
166
   }
167
 
168
   /**
169
    *  Return an xxx
170
    */
171
   public String[][] options() { return customOptionArr; }
172
 
173
   // Return a PackageDoc for the specified package name
174
   public PackageDoc packageNamed(String name) {
175
      return (PackageDoc)packageDocMap.get(name);
176
   }
177
 
178
 
179
  // classes and interfaces specified on the command line.
180
  public ClassDoc[] specifiedClasses()
181
  {
182
    return (ClassDocImpl[]) specifiedClasses.toArray(new ClassDocImpl[0]);
183
  }
184
 
185
   // packages specified on the command line.
186
  public PackageDoc[] specifiedPackages()
187
  {
188
    return (PackageDocImpl[])specifiedPackages.toArray(new PackageDocImpl[0]);
189
  }
190
 
191
   // Print error message, increment error count.
192
   public void printError(java.lang.String msg) {
193
      reporter.printError(msg);
194
   }
195
 
196
   // Print error message, increment error count.
197
   public void printFatal(java.lang.String msg) {
198
      reporter.printFatal(msg);
199
   }
200
 
201
   // Print a message.
202
   public void printNotice(java.lang.String msg) {
203
      reporter.printNotice(msg);
204
   }
205
 
206
   // Print warning message, increment warning count.
207
   public void printWarning(java.lang.String msg) {
208
      reporter.printWarning(msg);
209
   }
210
 
211
   public String name() {
212
      return "RootDoc";
213
   }
214
 
215
   public ErrorReporter getReporter() {
216
      return reporter;
217
   }
218
 
219
   public void build() throws ParseException, IOException {
220
 
221
      //--- Create a temporary random access file for caching comment text.
222
 
223
      //File rawCommentCacheFile=File.createTempFile("gjdoc_rawcomment",".cache");
224
      File rawCommentCacheFile = new File("gjdoc_rawcomment.cache");
225
      rawCommentCacheFile.deleteOnExit();
226
      rawCommentCache = new RandomAccessFile(rawCommentCacheFile, "rw");
227
 
228
      //--- Parse all files in "java.lang".
229
 
230
      List javaLangSourceDirs = findSourceFiles("java/lang");
231
      if (!javaLangSourceDirs.isEmpty()) {
232
         Iterator it = javaLangSourceDirs.iterator();
233
         while (it.hasNext()) {
234
            File javaLangSourceDir = (File)it.next();
235
            parser.processSourceDir(javaLangSourceDir,
236
                                    sourceEncoding, "java.lang");
237
         }
238
      }
239
      else {
240
 
241
         Debug.log(1, "Sourcepath is "+sourcePath);
242
 
243
         // Core docs not included in source-path:
244
         // we need to gather the information about java.lang
245
         // classes via reflection...
246
 
247
      }
248
 
249
      //--- Parse all files in explicitly specified package directories.
250
 
251
      for (Iterator it=specifiedPackageNames.iterator(); it.hasNext(); ) {
252
 
253
         String specifiedPackageName = (String)it.next();
254
         String displayPackageName = specifiedPackageName;
255
         if (null == displayPackageName || 0 == displayPackageName.length()) {
256
            displayPackageName = "<unnamed>";
257
         }
258
         printNotice("Loading classes for package "+displayPackageName+"...");
259
         String relPath;
260
         if (null != specifiedPackageName) {
261
            relPath = specifiedPackageName.replace('.',File.separatorChar);
262
         }
263
         else {
264
            relPath = "";
265
         }
266
         List sourceDirs = findSourceFiles(relPath);
267
         if (!sourceDirs.isEmpty()) {
268
            Iterator sourceDirIt = sourceDirs.iterator();
269
            while (sourceDirIt.hasNext()) {
270
               File sourceDir = (File)sourceDirIt.next();
271
               parser.processSourceDir(sourceDir, sourceEncoding, specifiedPackageName);
272
            }
273
         }
274
         else {
275
            printError("Package '"+specifiedPackageName+"' not found.");
276
         }
277
      }
278
 
279
      specifiedClasses = new LinkedList();
280
 
281
      //--- Parse all explicitly specified source files.
282
 
283
      for (Iterator it=specifiedSourceFiles.iterator(); it.hasNext(); ) {
284
 
285
         File specifiedSourceFile = (File)it.next();
286
         printNotice("Loading source file "+specifiedSourceFile+" ...");
287
         ClassDocImpl classDoc = parser.processSourceFile(specifiedSourceFile, true, sourceEncoding, null);
288
         if (null != classDoc) {
289
           specifiedClasses.add(classDoc);
290
           classesList.add(classDoc);
291
           classDoc.setIsIncluded(true);
292
           addPackageDoc(classDoc.containingPackage());
293
         }
294
      }
295
 
296
 
297
      //--- Let the user know that all specified classes are loaded.
298
 
299
      printNotice("Constructing Javadoc information...");
300
 
301
      //--- Load all classes implicitly referenced by explicitly specified classes.
302
 
303
      loadScheduledClasses(parser);
304
 
305
      printNotice("Resolving references in comments...");
306
 
307
      resolveComments();
308
 
309
      //--- Resolve pending references in all ClassDocImpls
310
 
311
      printNotice("Resolving references in classes...");
312
 
313
      for (Iterator it = classDocMap.values().iterator(); it.hasNext(); ) {
314
         ClassDoc cd=(ClassDoc)it.next();
315
         if (cd instanceof ClassDocImpl) {
316
            ((ClassDocImpl)cd).resolve();
317
         }
318
      }
319
 
320
      //--- Resolve pending references in all PackageDocImpls
321
 
322
      printNotice("Resolving references in packages...");
323
 
324
      for (Iterator it = packageDocMap.values().iterator(); it.hasNext(); ) {
325
         PackageDocImpl pd=(PackageDocImpl)it.next();
326
         pd.resolve();
327
      }
328
 
329
      //--- Assemble the array with all specified packages
330
 
331
      specifiedPackages = new LinkedHashSet();
332
      for (Iterator it = specifiedPackageNames.iterator(); it.hasNext(); ) {
333
         String specifiedPackageName = (String)it.next();
334
         PackageDoc specifiedPackageDoc = (PackageDoc)packageDocMap.get(specifiedPackageName);
335
         if (null!=specifiedPackageDoc) {
336
            ((PackageDocImpl)specifiedPackageDoc).setIsIncluded(true);
337
            specifiedPackages.add(specifiedPackageDoc);
338
 
339
            ClassDoc[] packageClassDocs=specifiedPackageDoc.allClasses();
340
            for (int i=0; i<packageClassDocs.length; ++i) {
341
               ClassDocImpl specifiedPackageClassDoc=(ClassDocImpl)packageClassDocs[i];
342
 
343
               specifiedPackageClassDoc.setIsIncluded(true);
344
               classesList.add(specifiedPackageClassDoc);
345
            }
346
         }
347
      }
348
 
349
      //--- Resolve pending references in comment data of all classes
350
 
351
      printNotice("Resolving references in class comments...");
352
 
353
      for (Iterator it=classDocMap.values().iterator(); it.hasNext(); ) {
354
         ClassDoc cd=(ClassDoc)it.next();
355
         if (cd instanceof ClassDocImpl) {
356
            ((ClassDocImpl)cd).resolveComments();
357
         }
358
      }
359
 
360
      //--- Resolve pending references in comment data of all packages
361
 
362
      printNotice("Resolving references in package comments...");
363
 
364
      for (Iterator it=packageDocMap.values().iterator(); it.hasNext(); ) {
365
         PackageDocImpl pd=(PackageDocImpl)it.next();
366
         pd.resolveComments();
367
      }
368
 
369
      //--- Create array with all loaded classes
370
 
371
      this.classes=(ClassDocImpl[])classesList.toArray(new ClassDocImpl[0]);
372
      Arrays.sort(this.classes);
373
 
374
      //--- Close comment cache
375
 
376
      parser = null;
377
      System.gc();
378
      System.gc();
379
   }
380
 
381
   public long writeRawComment(String rawComment) {
382
      try {
383
         long pos=rawCommentCache.getFilePointer();
384
         //rawCommentCache.writeUTF(rawComment);
385
         byte[] bytes = rawComment.getBytes("utf-8");
386
         rawCommentCache.writeInt(bytes.length);
387
         rawCommentCache.write(bytes);
388
         return pos;
389
      }
390
      catch (IOException e) {
391
         printFatal("Cannot write to comment cache: "+e.getMessage());
392
         return -1;
393
      }
394
   }
395
 
396
   public String readRawComment(long pos) {
397
      try {
398
         rawCommentCache.seek(pos);
399
         int sz = rawCommentCache.readInt();
400
         byte[] bytes = new byte[sz];
401
         rawCommentCache.read(bytes);
402
         return new String(bytes, "utf-8");
403
         //return rawCommentCache.readUTF();
404
      }
405
      catch (IOException e) {
406
         e.printStackTrace();
407
         printFatal("Cannot read from comment cache: "+e.getMessage());
408
         return null;
409
      }
410
   }
411
 
412
   List findSourceFiles(String relPath) {
413
 
414
      List result = new LinkedList();
415
      for (Iterator it = sourcePath.iterator(); it.hasNext(); ) {
416
         File path = (File)it.next();
417
         File file = new File(path, relPath);
418
         if (file.exists()) {
419
            result.add(file);
420
         }
421
      }
422
 
423
      return result;
424
   }
425
 
426
   PackageDocImpl findOrCreatePackageDoc(String packageName) {
427
      PackageDocImpl rc=(PackageDocImpl)getPackageDoc(packageName);
428
      if (null==rc) {
429
         rc=new PackageDocImpl(packageName);
430
         if (specifiedPackageNames.contains(packageName)) {
431
            String packageDirectoryName = packageName.replace('.', File.separatorChar);
432
            List packageDirectories = findSourceFiles(packageDirectoryName);
433
            Iterator it = packageDirectories.iterator();
434
            boolean packageDocFound = false;
435
            while (it.hasNext()) {
436
               File packageDirectory = (File)it.next();
437
               File packageDocFile = new File(packageDirectory, "package.html");
438
               rc.setPackageDirectory(packageDirectory);
439
               packageDocFound = true;
440
               if (null!=packageDocFile && packageDocFile.exists()) {
441
                  try {
442
                     rc.setRawCommentText(readHtmlBody(packageDocFile));
443
                  }
444
                  catch (IOException e) {
445
                     printWarning("Error while reading documentation for package "+packageName+": "+e.getMessage());
446
                  }
447
                  break;
448
               }
449
            }
450
            if (!packageDocFound) {
451
               printNotice("No description found for package "+packageName);
452
            }
453
         }
454
         addPackageDoc(rc);
455
      }
456
      return rc;
457
   }
458
 
459
   public void addClassDoc(ClassDoc cd) {
460
      classDocMap.put(cd.qualifiedName(), cd);
461
   }
462
 
463
   public void addClassDocRecursive(ClassDoc cd) {
464
      classDocMap.put(cd.qualifiedName(), cd);
465
      ClassDoc[] innerClasses = cd.innerClasses(false);
466
      for (int i=0; i<innerClasses.length; ++i) {
467
         addClassDocRecursive(innerClasses[i]);
468
      }
469
   }
470
 
471
   public void addPackageDoc(PackageDoc pd) {
472
      packageDocMap.put(pd.name(), pd);
473
   }
474
 
475
   public PackageDocImpl getPackageDoc(String name) {
476
      return (PackageDocImpl)packageDocMap.get(name);
477
   }
478
 
479
   public ClassDocImpl getClassDoc(String qualifiedName) {
480
      return (ClassDocImpl)classDocMap.get(qualifiedName);
481
   }
482
 
483
   class ScheduledClass {
484
 
485
      ClassDoc contextClass;
486
      String qualifiedName;
487
      ScheduledClass(ClassDoc contextClass, String qualifiedName) {
488
         this.contextClass=contextClass;
489
         this.qualifiedName=qualifiedName;
490
      }
491
 
492
      public String toString() { return "ScheduledClass{"+qualifiedName+"}"; }
493
   }
494
 
495
   public void scheduleClass(ClassDoc context, String qualifiedName) throws ParseException, IOException {
496
 
497
      if (classDocMap.get(qualifiedName)==null) {
498
 
499
         //Debug.log(9,"Scheduling "+qualifiedName+", context "+context+".");
500
         //System.err.println("Scheduling " + qualifiedName + ", context " + context);
501
 
502
         scheduledClasses.add(new ScheduledClass(context, qualifiedName));
503
      }
504
   }
505
 
506
   /**
507
    *  Load all classes that were implictly referenced by the classes
508
    *  (already loaded) that the user explicitly specified on the
509
    *  command line.
510
    *
511
    *  For example, if the user generates Documentation for his simple
512
    *  'class Test {}', which of course 'extends java.lang.Object',
513
    *  then 'java.lang.Object' is implicitly referenced because it is
514
    *  the base class of Test.
515
    *
516
    *  Gjdoc needs a ClassDocImpl representation of all classes
517
    *  implicitly referenced through derivation (base class),
518
    *  or implementation (interface), or field type, method argument
519
    *  type, or method return type.
520
    *
521
    *  The task of this method is to ensure that Gjdoc has all this
522
    *  information at hand when it exits.
523
    *
524
    *
525
    */
526
   public void loadScheduledClasses(Parser parser) throws ParseException, IOException {
527
 
528
      // Because the referenced classes could in turn reference other
529
      // classes, this method runs as long as there are still unloaded
530
      // classes.
531
 
532
      while (!scheduledClasses.isEmpty()) {
533
 
534
         // Make a copy of scheduledClasses and empty it. This
535
         // prevents any Concurrent Modification issues.
536
         // As the copy won't need to grow (as it won't change)
537
         // we make it an Array for performance reasons.
538
 
539
         ScheduledClass[] scheduledClassesArr = (ScheduledClass[])scheduledClasses.toArray(new ScheduledClass[0]);
540
         scheduledClasses.clear();
541
 
542
         // Load each class specified in our array copy
543
 
544
         for (int i=0; i<scheduledClassesArr.length; ++i) {
545
 
546
            // The name of the class we are looking for. This name
547
            // needs not be fully qualified.
548
 
549
            String scheduledClassName=scheduledClassesArr[i].qualifiedName;
550
 
551
            // The ClassDoc in whose context the scheduled class was looked for.
552
            // This is necessary in order to resolve non-fully qualified
553
            // class names.
554
            ClassDoc scheduledClassContext=scheduledClassesArr[i].contextClass;
555
 
556
            // If there already is a class doc with this name, skip. There's
557
            // nothing to do for us.
558
            if (classDocMap.get(scheduledClassName)!=null) {
559
               continue;
560
            }
561
 
562
            try {
563
               // Try to load the class
564
               //printNotice("Trying to load " + scheduledClassName);
565
               loadScheduledClass(parser, scheduledClassName, scheduledClassContext);
566
            }
567
            catch (ParseException e) {
568
 
569
               /**********************************************************
570
 
571
               // Check whether the following is necessary at all.
572
 
573
 
574
               if (scheduledClassName.indexOf('.')>0) {
575
 
576
               // Maybe the dotted notation doesn't mean a package
577
               // name but instead an inner class, as in 'Outer.Inner'.
578
               // so let's assume this and try to load the outer class.
579
 
580
                  String outerClass="";
581
                  for (StringTokenizer st=new StringTokenizer(scheduledClassName,"."); st.hasMoreTokens(); ) {
582
                     if (outerClass.length()>0) outerClass+=".";
583
                     outerClass+=st.nextToken();
584
                     if (!st.hasMoreTokens()) break;
585
                     try {
586
                        loadClass(outerClass);
587
                        //FIXME: shouldn't this be loadScheduledClass(outerClass, scheduledClassContext); ???
588
                        continue;
589
                     }
590
                     catch (Exception ee) {
591
                     // Ignore: try next level
592
                     }
593
                  }
594
               }
595
 
596
               **********************************************************/
597
 
598
               // If we arrive here, the class could not be found
599
 
600
               printWarning("Couldn't load class "+scheduledClassName+" referenced by "+scheduledClassContext);
601
 
602
               //FIXME: shouldn't this be throw new Error("cannot load: "+scheduledClassName);
603
            }
604
         }
605
      }
606
   }
607
 
608
   private void loadScheduledClass(Parser parser, String scheduledClassName, ClassDoc scheduledClassContext) throws ParseException, IOException {
609
 
610
      ClassDoc loadedClass=(ClassDoc)scheduledClassContext.findClass(scheduledClassName);
611
 
612
      if (loadedClass==null || loadedClass instanceof ClassDocProxy) {
613
 
614
         ClassDoc classDoc = findScheduledClassFile(scheduledClassName, scheduledClassContext);
615
         if (null != classDoc) {
616
 
617
            if (classDoc instanceof ClassDocReflectedImpl) {
618
               Main.getRootDoc().addClassDocRecursive(classDoc);
619
            }
620
 
621
            if (Main.DESCEND_SUPERCLASS
622
                && null != classDoc.superclass()
623
                && (classDoc.superclass() instanceof ClassDocProxy)) {
624
               scheduleClass(classDoc, classDoc.superclass().qualifiedName());
625
            }
626
         }
627
         else {
628
            // It might be an inner class of one of the outer/super classes.
629
            // But we can only check that when they are all fully loaded.
630
            boolean retryLater = false;
631
 
632
            int numberOfProcessedFilesBefore = parser.getNumberOfProcessedFiles();
633
 
634
            ClassDoc cc = scheduledClassContext.containingClass();
635
            while (cc != null && !retryLater) {
636
               ClassDoc sc = cc.superclass();
637
               while (sc != null && !retryLater) {
638
                  if (sc instanceof ClassDocProxy) {
639
                     ((ClassDocImpl)cc).resolve();
640
                     retryLater = true;
641
                  }
642
                  sc = sc.superclass();
643
               }
644
               cc = cc.containingClass();
645
            }
646
 
647
            // Now that outer/super references have been resolved, try again
648
            // to find the class.
649
 
650
            loadedClass = (ClassDoc)scheduledClassContext.findClass(scheduledClassName);
651
 
652
            int numberOfProcessedFilesAfter = parser.getNumberOfProcessedFiles();
653
 
654
            boolean filesWereProcessed = numberOfProcessedFilesAfter > numberOfProcessedFilesBefore;
655
 
656
            // Only re-schedule class if additional files have been processed
657
            // If there haven't, there's no point in re-scheduling.
658
            // Will avoid infinite loops of re-scheduling
659
            if (null == loadedClass && retryLater && filesWereProcessed)
660
               scheduleClass(scheduledClassContext, scheduledClassName);
661
 
662
            /* A warning needn't be emitted - this is normal, can happen
663
               if the scheduled class is in a package which is not
664
               included on the command line.
665
 
666
               else if (null == loadedClass)
667
               printWarning("Can't find scheduled class '"
668
               + scheduledClassName
669
               + "' in context '"
670
               + scheduledClassContext.qualifiedName()
671
               + "'");
672
            */
673
         }
674
      }
675
   }
676
 
677
   private static interface ResolvedImport
678
   {
679
      public String match(String name);
680
      public boolean mismatch(String name);
681
      public ClassDoc tryFetch(String name);
682
   }
683
 
684
   private class ResolvedImportNotFound
685
      implements ResolvedImport
686
   {
687
      private String importSpecifier;
688
      private String name;
689
 
690
      ResolvedImportNotFound(String importSpecifier)
691
      {
692
         this.importSpecifier = importSpecifier;
693
         int ndx = importSpecifier.lastIndexOf('.');
694
         if (ndx >= 0) {
695
            this.name = importSpecifier.substring(ndx + 1);
696
         }
697
         else {
698
            this.name = importSpecifier;
699
         }
700
      }
701
 
702
      public String toString()
703
      {
704
         return "ResolvedImportNotFound{" + importSpecifier + "}";
705
      }
706
 
707
      public String match(String name)
708
      {
709
         if ((name.equals(this.name)) || (importSpecifier.equals(name)))
710
            return this.name;
711
         // FIXME: note that we don't handle on-demand imports here.
712
         return null;
713
      }
714
 
715
      public boolean mismatch(String name)
716
      {
717
         return true; // FIXME!
718
      }
719
 
720
      public ClassDoc tryFetch(String name)
721
      {
722
         return null;
723
      }
724
   }
725
 
726
   private class ResolvedImportPackageFile
727
      implements ResolvedImport
728
   {
729
      private Set topLevelClassNames;
730
      private File packageFile;
731
      private String packageName;
732
      private Map cache = new HashMap();
733
 
734
      ResolvedImportPackageFile(File packageFile, String packageName)
735
      {
736
         this.packageFile = packageFile;
737
         this.packageName = packageName;
738
         topLevelClassNames = new HashSet();
739
         File[] files = packageFile.listFiles();
740
         for (int i=0; i<files.length; ++i) {
741
            if (!files[i].isDirectory() && files[i].getName().endsWith(".java")) {
742
               String topLevelClassName = files[i].getName();
743
               topLevelClassName
744
                  = topLevelClassName.substring(0, topLevelClassName.length() - 5);
745
               topLevelClassNames.add(topLevelClassName);
746
            }
747
         }
748
      }
749
 
750
      public String match(String name)
751
      {
752
         ClassDoc loadedClass = classNamed(packageName + "." + name);
753
         if (null != loadedClass) {
754
            return loadedClass.qualifiedName();
755
         }
756
         else {
757
            String topLevelName = name;
758
            int ndx = topLevelName.indexOf('.');
759
            String innerClassName = null;
760
            if (ndx > 0) {
761
               innerClassName = topLevelName.substring(ndx + 1);
762
               topLevelName = topLevelName.substring(0, ndx);
763
            }
764
 
765
            if (topLevelClassNames.contains(topLevelName)) {
766
               //System.err.println(this + ".match returns " + packageName + "." + name);
767
               return packageName + "." + name;
768
            }
769
            // FIXME: inner classes
770
            else {
771
               return null;
772
            }
773
         }
774
      }
775
 
776
      public boolean mismatch(String name)
777
      {
778
         return null == match(name);
779
      }
780
 
781
      public ClassDoc tryFetch(String name)
782
      {
783
         ClassDoc loadedClass = classNamed(packageName + "." + name);
784
         if (null != loadedClass) {
785
            return loadedClass;
786
         }
787
         else if (null != match(name)) {
788
 
789
            String topLevelName = name;
790
            int ndx = topLevelName.indexOf('.');
791
            String innerClassName = null;
792
            if (ndx > 0) {
793
               innerClassName = topLevelName.substring(ndx + 1);
794
               topLevelName = topLevelName.substring(0, ndx);
795
            }
796
 
797
            ClassDoc topLevelClass = (ClassDoc)cache.get(topLevelName);
798
            if (null == topLevelClass) {
799
               File classFile = new File(packageFile, topLevelName + ".java");
800
               try {
801
                  // FIXME: inner classes
802
                  topLevelClass = parser.processSourceFile(classFile, false, sourceEncoding, null);
803
               }
804
               catch (Exception ignore) {
805
                  printWarning("Could not parse source file " + classFile);
806
               }
807
               cache.put(topLevelName, topLevelClass);
808
            }
809
            if (null == innerClassName) {
810
               return topLevelClass;
811
            }
812
            else {
813
               return getInnerClass(topLevelClass, innerClassName);
814
            }
815
         }
816
         else {
817
            return null;
818
         }
819
      }
820
 
821
      public String toString()
822
      {
823
         return "ResolvedImportPackageFile{" + packageFile + "," + packageName + "}";
824
      }
825
   }
826
 
827
   private ClassDoc getInnerClass(ClassDoc topLevelClass, String innerClassName)
828
   {
829
      StringTokenizer st = new StringTokenizer(innerClassName, ".");
830
   outer:
831
 
832
      while (st.hasMoreTokens()) {
833
         String innerClassNameComponent = st.nextToken();
834
         ClassDoc[] innerClasses = topLevelClass.innerClasses();
835
         for (int i=0; i<innerClasses.length; ++i) {
836
            if (innerClasses[i].name().equals(innerClassNameComponent)) {
837
               topLevelClass = innerClasses[i];
838
               continue outer;
839
            }
840
         }
841
         printWarning("Could not find inner class " + innerClassName + " in class " + topLevelClass.qualifiedName());
842
         return null;
843
      }
844
      return topLevelClass;
845
   }
846
 
847
   private class ResolvedImportClassFile
848
      implements ResolvedImport
849
   {
850
      private File classFile;
851
      private String innerClassName;
852
      private String name;
853
      private ClassDoc classDoc;
854
      private boolean alreadyFetched;
855
      private String qualifiedName;
856
 
857
      ResolvedImportClassFile(File classFile, String innerClassName, String name, String qualifiedName)
858
      {
859
         this.classFile = classFile;
860
         this.innerClassName = innerClassName;
861
         this.name = name;
862
         this.qualifiedName = qualifiedName;
863
      }
864
 
865
      public String toString()
866
      {
867
         return "ResolvedImportClassFile{" + classFile + "," + innerClassName +  "}";
868
      }
869
 
870
      public String match(String name)
871
      {
872
         String topLevelName = name;
873
         int ndx = topLevelName.indexOf('.');
874
 
875
         String _innerClassName = null;
876
         if (ndx > 0) {
877
            _innerClassName = topLevelName.substring(ndx + 1);
878
            topLevelName = topLevelName.substring(0, ndx);
879
         }
880
 
881
         if (this.name.equals(topLevelName)) {
882
            if (null == _innerClassName) {
883
               return qualifiedName;
884
            }
885
            else {
886
               return qualifiedName + "." + _innerClassName;
887
            }
888
         }
889
         else {
890
            return null;
891
         }
892
      }
893
 
894
      public boolean mismatch(String name)
895
      {
896
         return null == match(name);
897
      }
898
 
899
      public ClassDoc tryFetch(String name)
900
      {
901
         if (null != match(name)) {
902
            ClassDoc topLevelClass = null;
903
            if (alreadyFetched) {
904
               topLevelClass = classDoc;
905
            }
906
            else {
907
               alreadyFetched = true;
908
               try {
909
                  topLevelClass = parser.processSourceFile(classFile, false, sourceEncoding, null);
910
               }
911
               catch (Exception ignore) {
912
                  printWarning("Could not parse source file " + classFile);
913
               }
914
            }
915
            if (null == topLevelClass) {
916
               return null;
917
            }
918
            else {
919
               return getInnerClass(topLevelClass, innerClassName);
920
            }
921
         }
922
         else {
923
            return null;
924
         }
925
      }
926
 
927
      public String getName()
928
      {
929
         if (innerClassName != null) {
930
            return name + innerClassName;
931
         }
932
         else {
933
            return name;
934
         }
935
      }
936
   }
937
 
938
   private class ResolvedImportReflectionClass
939
      implements ResolvedImport
940
   {
941
      private Class clazz;
942
      private String name;
943
 
944
      ResolvedImportReflectionClass(Class clazz)
945
      {
946
         this.clazz = clazz;
947
         String className = clazz.getName();
948
         int ndx = className.lastIndexOf('.');
949
         if (ndx >= 0) {
950
            this.name = className.substring(ndx + 1);
951
         }
952
         else {
953
            this.name = className;
954
         }
955
      }
956
 
957
      public String toString()
958
      {
959
         return "ResolvedImportReflectionClass{" + clazz.getName() + "}";
960
      }
961
 
962
      public String match(String name)
963
      {
964
         if ((this.name.equals(name)) || (clazz.getName().equals(name))) {
965
            return clazz.getName();
966
         }
967
         else {
968
            return null;
969
         }
970
      }
971
 
972
      public boolean mismatch(String name)
973
      {
974
         return null == match(name);
975
      }
976
 
977
      public ClassDoc tryFetch(String name)
978
      {
979
         if (null != match(name)) {
980
            return new ClassDocReflectedImpl(clazz);
981
         }
982
         // FIXME: inner classes?
983
         else {
984
            return null;
985
         }
986
      }
987
 
988
      public String getName()
989
      {
990
         return name;
991
      }
992
   }
993
 
994
   private class ResolvedImportReflectionPackage
995
      implements ResolvedImport
996
   {
997
      private String packagePrefix;
998
 
999
      ResolvedImportReflectionPackage(String packagePrefix)
1000
      {
1001
         this.packagePrefix = packagePrefix;
1002
      }
1003
 
1004
      public String toString()
1005
      {
1006
         return "ResolvedImportReflectionPackage{" + packagePrefix + ".*}";
1007
      }
1008
 
1009
      public String match(String name)
1010
      {
1011
         try {
1012
            Class clazz = Class.forName(packagePrefix + "." + name);
1013
            return clazz.getName();
1014
         }
1015
         catch (Exception e) {
1016
            return null;
1017
         }
1018
      }
1019
 
1020
      public boolean mismatch(String name)
1021
      {
1022
         return null == match(name);
1023
      }
1024
 
1025
      public ClassDoc tryFetch(String name)
1026
      {
1027
         try {
1028
            Class clazz = Class.forName(packagePrefix + name);
1029
            return ClassDocReflectedImpl.newInstance(clazz);
1030
         }
1031
         catch (Exception e) {
1032
            return null;
1033
         }
1034
      }
1035
 
1036
      public String getName()
1037
      {
1038
         return packagePrefix;
1039
      }
1040
   }
1041
 
1042
   private List unlocatablePrefixes = new LinkedList();
1043
 
1044
   private ResolvedImport resolveImport(String importSpecifier)
1045
   {
1046
      ResolvedImport result = resolveImportFileSystem(importSpecifier);
1047
      if (null == result && Main.getInstance().isReflectionEnabled()) {
1048
         result = resolveImportReflection(importSpecifier);
1049
      }
1050
      if (null == result) {
1051
         result = new ResolvedImportNotFound(importSpecifier);
1052
      }
1053
      return result;
1054
   }
1055
 
1056
   private ResolvedImport resolveImportReflection(String importSpecifier)
1057
   {
1058
      String importedPackageOrClass = importSpecifier;
1059
      if (importedPackageOrClass.endsWith(".*")) {
1060
         importedPackageOrClass = importedPackageOrClass.substring(0, importedPackageOrClass.length() - 2);
1061
 
1062
         return new ResolvedImportReflectionPackage(importedPackageOrClass);
1063
 
1064
         //return null;
1065
      }
1066
      else {
1067
         try {
1068
            Class importedClass = Class.forName(importSpecifier);
1069
            return new ResolvedImportReflectionClass(importedClass);
1070
         }
1071
         catch (Throwable ignore) {
1072
            return null;
1073
         }
1074
      }
1075
   }
1076
 
1077
   private ResolvedImport resolveImportFileSystem(String importSpecifier)
1078
   {
1079
      for (Iterator it = unlocatablePrefixes.iterator(); it.hasNext(); ) {
1080
         String unlocatablePrefix = (String)it.next();
1081
         if (importSpecifier.startsWith(unlocatablePrefix)) {
1082
            return null;
1083
         }
1084
      }
1085
 
1086
      String longestUnlocatablePrefix = "";
1087
 
1088
      for (Iterator it=sourcePath.iterator(); it.hasNext(); ) {
1089
 
1090
         File _sourcePath = (File)it.next();
1091
 
1092
         StringBuffer packageOrClassPrefix = new StringBuffer();
1093
         StringTokenizer st = new StringTokenizer(importSpecifier, ".");
1094
         while (st.hasMoreTokens() && _sourcePath.isDirectory()) {
1095
            String token = st.nextToken();
1096
            if ("*".equals(token)) {
1097
               return new ResolvedImportPackageFile(_sourcePath,
1098
                                                    packageOrClassPrefix.substring(0, packageOrClassPrefix.length() - 1));
1099
            }
1100
            else {
1101
               packageOrClassPrefix.append(token);
1102
               packageOrClassPrefix.append('.');
1103
               File classFile = new File(_sourcePath, token + ".java");
1104
               //System.err.println("  looking for file " + classFile);
1105
               if (classFile.exists()) {
1106
                  StringBuffer innerClassName = new StringBuffer();
1107
                  while (st.hasMoreTokens()) {
1108
                     token = st.nextToken();
1109
                     if (innerClassName.length() > 0) {
1110
                        innerClassName.append('.');
1111
                     }
1112
                     innerClassName.append(token);
1113
                  }
1114
                  return new ResolvedImportClassFile(classFile, innerClassName.toString(), token, importSpecifier);
1115
               }
1116
               else {
1117
                  _sourcePath = new File(_sourcePath, token);
1118
               }
1119
            }
1120
         }
1121
         if (st.hasMoreTokens()) {
1122
            if (packageOrClassPrefix.length() > longestUnlocatablePrefix.length()) {
1123
               longestUnlocatablePrefix = packageOrClassPrefix.toString();
1124
            }
1125
         }
1126
      }
1127
 
1128
      if (longestUnlocatablePrefix.length() > 0) {
1129
         unlocatablePrefixes.add(longestUnlocatablePrefix);
1130
      }
1131
 
1132
      return null;
1133
   }
1134
 
1135
   private Map resolvedImportCache = new HashMap();
1136
 
1137
   private ResolvedImport getResolvedImport(String importSpecifier)
1138
   {
1139
      ResolvedImport result
1140
         = (ResolvedImport)resolvedImportCache.get(importSpecifier);
1141
      if (null == result) {
1142
         result = resolveImport(importSpecifier);
1143
         resolvedImportCache.put(importSpecifier, result);
1144
      }
1145
      return result;
1146
   }
1147
 
1148
   public String resolveClassName(String className, ClassDocImpl context)
1149
   {
1150
      Iterator it = context.getImportSpecifierList().iterator();
1151
      while (it.hasNext()) {
1152
         String importSpecifier = (String)it.next();
1153
         ResolvedImport resolvedImport = getResolvedImport(importSpecifier);
1154
         String resolvedScheduledClassName = resolvedImport.match(className);
1155
 
1156
         if (null != resolvedScheduledClassName) {
1157
            return resolvedScheduledClassName;
1158
         }
1159
      }
1160
      return className;
1161
   }
1162
 
1163
   public ClassDoc findScheduledClassFile(String scheduledClassName,
1164
                                          ClassDoc scheduledClassContext)
1165
      throws ParseException, IOException
1166
   {
1167
      String resolvedScheduledClassName = null;
1168
 
1169
      if (scheduledClassContext instanceof ClassDocImpl) {
1170
 
1171
         //((ClassDocImpl)scheduledClassContext).resolveReferencedName(scheduledClassName);
1172
         Iterator it = ((ClassDocImpl)scheduledClassContext).getImportSpecifierList().iterator();
1173
         while (it.hasNext()) {
1174
            String importSpecifier = (String)it.next();
1175
            ResolvedImport resolvedImport = getResolvedImport(importSpecifier);
1176
            //System.err.println("  looking in import '" +  resolvedImport + "'");
1177
            resolvedScheduledClassName = resolvedImport.match(scheduledClassName);
1178
            if (null != resolvedScheduledClassName) {
1179
               ClassDoc result = resolvedImport.tryFetch(scheduledClassName);
1180
               if (null != result) {
1181
                  return result;
1182
               }
1183
               else {
1184
                  if (!inaccessibleReportedSet.contains(scheduledClassName)) {
1185
                     inaccessibleReportedSet.add(scheduledClassName);
1186
                     printWarning("Error while loading class " + scheduledClassName);
1187
                  }
1188
                  // FIXME: output resolved class name here
1189
                  return null;
1190
               }
1191
            }
1192
         }
1193
      }
1194
      else {
1195
         System.err.println("findScheduledClassFile for '" + scheduledClassName + "' in proxy for " + scheduledClassContext);
1196
      }
1197
 
1198
      // interpret as fully qualified name on file system
1199
 
1200
      ResolvedImport fqImport = resolveImportFileSystem(scheduledClassName);
1201
      if (null != fqImport && fqImport instanceof ResolvedImportClassFile) {
1202
         return fqImport.tryFetch(((ResolvedImportClassFile)fqImport).getName());
1203
      }
1204
 
1205
      // use reflection, assume fully qualified class name
1206
 
1207
      if (!unlocatableReflectedClassNames.contains(scheduledClassName)) {
1208
         if (Main.getInstance().isReflectionEnabled()) {
1209
            try {
1210
               Class clazz = Class.forName(scheduledClassName);
1211
               printWarning("Cannot locate class " + scheduledClassName + " on file system, falling back to reflection.");
1212
               ClassDoc result = new ClassDocReflectedImpl(clazz);
1213
               return result;
1214
            }
1215
            catch (Throwable ignore) {
1216
               unlocatableReflectedClassNames.add(scheduledClassName);
1217
            }
1218
         }
1219
         else {
1220
            unlocatableReflectedClassNames.add(scheduledClassName);
1221
         }
1222
      }
1223
 
1224
      if (null == resolvedScheduledClassName) {
1225
         resolvedScheduledClassName = scheduledClassName;
1226
      }
1227
      if (!unlocatableReportedSet.contains(resolvedScheduledClassName)) {
1228
         unlocatableReportedSet.add(resolvedScheduledClassName);
1229
         printWarning("Cannot locate class " + resolvedScheduledClassName + " referenced in class " + scheduledClassContext.qualifiedName());
1230
      }
1231
      return null;
1232
   }
1233
 
1234
   private Set unlocatableReflectedClassNames = new HashSet();
1235
 
1236
   public static boolean recursiveClasses = false;
1237
 
1238
   public void addSpecifiedPackageName(String packageName) {
1239
      specifiedPackageNames.add(packageName);
1240
   }
1241
 
1242
   public void addSpecifiedSourceFile(File sourceFile) {
1243
      specifiedSourceFiles.add(sourceFile);
1244
   }
1245
 
1246
   public boolean hasSpecifiedPackagesOrClasses() {
1247
      return !specifiedPackageNames.isEmpty()
1248
         ||  !specifiedSourceFiles.isEmpty();
1249
   }
1250
 
1251
   public void setOptions(String[][] customOptionArr) {
1252
      this.customOptionArr = customOptionArr;
1253
   }
1254
 
1255
   public void setSourcePath(List sourcePath) {
1256
      this.sourcePath = sourcePath;
1257
   }
1258
 
1259
   public void finalize() throws Throwable {
1260
      super.finalize();
1261
   }
1262
 
1263
   public void flush()
1264
   {
1265
      try {
1266
         rawCommentCache.close();
1267
      }
1268
      catch (IOException e) {
1269
         printError("Cannot close raw comment cache");
1270
      }
1271
 
1272
      rawCommentCache = null;
1273
      customOptionArr = null;
1274
      specifiedPackageNames = null;
1275
      classesList = null;
1276
      classDocMap = null;
1277
      packageDocMap = null;
1278
      classes = null;
1279
      specifiedClasses = null;
1280
      specifiedPackages = null;
1281
      scheduledClasses = null;
1282
      sourcePath = null;
1283
      parser = null;
1284
      unlocatableReportedSet = null;
1285
      inaccessibleReportedSet = null;
1286
   }
1287
 
1288
   public void setSourceEncoding(String sourceEncoding)
1289
   {
1290
      this.sourceEncoding = sourceEncoding;
1291
   }
1292
 
1293
   public RootDocImpl()
1294
   {
1295
      super(null);
1296
   }
1297
 
1298
   public static String readHtmlBody(File file)
1299
      throws IOException
1300
   {
1301
      FileReader fr=new FileReader(file);
1302
      long size = file.length();
1303
      char[] packageDocBuf=new char[(int)(size)];
1304
      int index = 0;
1305
      int i = fr.read(packageDocBuf, index, (int)size);
1306
      while (i > 0) {
1307
         index += i;
1308
         size -= i;
1309
         i = fr.read(packageDocBuf, index, (int)size);
1310
      }
1311
      fr.close();
1312
 
1313
      // We only need the part between the begin and end body tag.
1314
      String html = new String(packageDocBuf);
1315
      int start = html.indexOf("<body");
1316
      if (start == -1)
1317
         start = html.indexOf("<BODY");
1318
      int end = html.indexOf("</body>");
1319
      if (end == -1)
1320
         end = html.indexOf("</BODY>");
1321
      if (start != -1 && end != -1) {
1322
         // Start is end of body tag.
1323
         start = html.indexOf('>', start) + 1;
1324
         if (start != -1 && start < end)
1325
            html = html.substring(start, end);
1326
      }
1327
      return html.trim();
1328
   }
1329
 
1330
   public Parser getParser()
1331
   {
1332
      return parser;
1333
   }
1334
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.