KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > source > impl > QDoxSource


1 /*
2  * Copyright 1999-2002,2004-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.components.source.impl;
17
18 import java.io.BufferedReader JavaDoc;
19 import java.io.ByteArrayInputStream JavaDoc;
20 import java.io.ByteArrayOutputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.io.InputStreamReader JavaDoc;
24 import java.net.MalformedURLException JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Map JavaDoc;
29
30 import com.thoughtworks.qdox.JavaDocBuilder;
31 import com.thoughtworks.qdox.model.AbstractJavaEntity;
32 import com.thoughtworks.qdox.model.DocletTag;
33 import com.thoughtworks.qdox.model.JavaClass;
34 import com.thoughtworks.qdox.model.JavaField;
35 import com.thoughtworks.qdox.model.JavaMethod;
36 import com.thoughtworks.qdox.model.JavaParameter;
37 import com.thoughtworks.qdox.model.JavaSource;
38 import com.thoughtworks.qdox.model.Type;
39
40 import org.apache.avalon.excalibur.pool.Recyclable;
41 import org.apache.avalon.framework.logger.Logger;
42 import org.apache.avalon.framework.service.ServiceException;
43 import org.apache.avalon.framework.service.ServiceManager;
44 import org.apache.cocoon.serialization.XMLSerializer;
45 import org.apache.cocoon.xml.XMLUtils;
46
47 import org.apache.commons.lang.StringUtils;
48 import org.apache.excalibur.source.Source;
49 import org.apache.excalibur.source.SourceException;
50 import org.apache.excalibur.source.SourceResolver;
51 import org.apache.excalibur.source.SourceValidity;
52 import org.apache.excalibur.source.impl.AbstractSource;
53 import org.apache.excalibur.xml.sax.XMLizable;
54 import org.apache.regexp.RE;
55 import org.apache.regexp.RESyntaxException;
56 import org.xml.sax.ContentHandler JavaDoc;
57 import org.xml.sax.SAXException JavaDoc;
58 import org.xml.sax.helpers.AttributesImpl JavaDoc;
59
60 /**
61  * Source implementation for XML Javadoc.
62  *
63  * @author <a HREF="mailto:b.guijt1@chello.nl">Bart Guijt</a>
64  * @version $Id: QDoxSource.java 164808 2005-04-26 16:07:03Z vgritsenko $ $Date: 2004/04/30 22:50:39 $
65  */

66 public final class QDoxSource extends AbstractSource
67                               implements XMLizable, Recyclable {
68
69     protected final static String JavaDoc ROOT_CLASSNAME = "java.lang.Object";
70
71     protected final static String JavaDoc PROTOCOL = "qdox:";
72     protected final static String JavaDoc NS_URI = "http://apache.org/cocoon/javadoc/1.0";
73     protected final static String JavaDoc NS_PREFIX = "jd";
74     protected final static String JavaDoc ATTR_TYPE = "NMTOKEN";
75
76     protected final static String JavaDoc CLASS_ELEMENT = "class";
77     protected final static String JavaDoc CLASSNAME_ATTRIBUTE = "name";
78     protected final static String JavaDoc PACKAGE_ATTRIBUTE = "package";
79     protected final static String JavaDoc QNAME_ATTRIBUTE = "qname";
80     protected final static String JavaDoc INHERIT_ELEMENT = "inherit";
81     protected final static String JavaDoc INNERCLASSES_ELEMENT = "innerclasses";
82     protected final static String JavaDoc NESTED_IN_ELEMENT = "nested-in";
83     protected final static String JavaDoc IMPORTS_ELEMENT = "imports";
84     protected final static String JavaDoc IMPORT_ELEMENT = "import";
85     protected final static String JavaDoc IMPORT_ATTRIBUTE = "type";
86     protected final static String JavaDoc IMPLEMENTS_ELEMENT = "implements";
87     protected final static String JavaDoc INTERFACE_ELEMENT = "interface";
88     protected final static String JavaDoc MODIFIERS_ELEMENT = "modifiers";
89     protected final static String JavaDoc COMMENT_ELEMENT = "comment";
90     protected final static String JavaDoc LINK_ELEMENT = "link";
91     protected final static String JavaDoc LINK_CLASS_ATTRIBUTE = "class";
92     protected final static String JavaDoc LINK_MEMBER_ATTRIBUTE = "member";
93     protected final static String JavaDoc HREF_ATTRIBUTE = "uri";
94     protected final static String JavaDoc TAGS_ELEMENT = "tags";
95     protected final static String JavaDoc FIELDS_ELEMENT = "fields";
96     protected final static String JavaDoc FIELD_ELEMENT = "field";
97     protected final static String JavaDoc CONSTRUCTORS_ELEMENT = "constructors";
98     protected final static String JavaDoc CONSTRUCTOR_ELEMENT = "constructor";
99     protected final static String JavaDoc METHODS_ELEMENT = "methods";
100     protected final static String JavaDoc METHOD_ELEMENT = "method";
101     protected final static String JavaDoc NAME_ATTRIBUTE = "name";
102     protected final static String JavaDoc TYPE_ATTRIBUTE = "type";
103     protected final static String JavaDoc DIMENSIONS_ATTRIBUTE = "dimensions";
104     protected final static String JavaDoc SIGNATURE_ATTRIBUTE = "signature";
105     protected final static String JavaDoc PARAMETERS_ELEMENT = "parameters";
106     protected final static String JavaDoc PARAMETER_ELEMENT = "parameter";
107     protected final static String JavaDoc THROWS_ELEMENT = "throws";
108     protected final static String JavaDoc EXCEPTION_ELEMENT = "exception";
109
110     protected final static int CONSTRUCTOR_MODE = 1;
111     protected final static int METHOD_MODE = 2;
112
113     protected final static int CLASS_INHERITANCE = 1;
114     protected final static int INTERFACE_INHERITANCE = 2;
115     protected final static int INNERCLASS_INHERITANCE = 3;
116     protected final static int FIELD_INHERITANCE = 4;
117     protected final static int CONSTRUCTOR_INHERITANCE = 5;
118     protected final static int METHOD_INHERITANCE = 6;
119
120     protected ServiceManager manager;
121     protected Logger logger;
122
123     protected Source javaSource;
124     protected String JavaDoc javadocUri;
125     protected String JavaDoc javadocClassName;
126     protected JavaClass javadocClass;
127     protected JavaClass containingJavadocClass; // in case javadocClass is an inner class
128
protected Map JavaDoc classMap;
129
130     /**
131      * This RegExp matches the <code>{</code><code>@link &hellip;}</code> occurrances in
132      * Javadoc comments.
133      */

134     protected RE reLink;
135
136     /**
137      * Contains a regular expression to match the <code>{</code><code>@link &hellip;}</code> occurrances.
138      *
139      * <p>The following <code>{</code><code>@link &hellip;}</code> literals are recognized:</p>
140      *
141      * <ul>
142      * <li><code>{</code><code>@link HashMap}</code> - returns 'Hashmap' with <code>reLink.getParen(6)</code>;</li>
143      * <li><code>{</code><code>@link #equals(java.lang.Object) equals(&hellip;)}</code> - returns '#equals(java.lang.Object)' with <code>reLink.getParen(2)</code>
144      * and 'equals(&hellip;)' with <code>reLink.getParen(5)</code>;</li>
145      * <li><code>{</code><code>@link #indexOf(char, int) indexOf(&hellip;)}</code> - returns '#indexOf(char, int)' with <code>reLink.getParen(2)</code>
146      * and 'indexOf(&hellip;)' with <code>reLink.getParen(5)</code>.</li>
147      * </ul>
148      * <p>The regexp is as follows:</p>
149      * <code>\{\@link\s+((([\w.#,$&amp;;\s]+)|([\w.#,$&amp;;(\s]+[\w.#,$&amp;;)\s]+))\s+([\w()#.,$&amp;;\s]+)|([\w.#,$&amp;;\s()]+))\s*\}</code>
150      *
151      * @see #reLink
152      */

153     protected final static String JavaDoc RE_LINK = "\\{@link\\s+((([\\w.#,$&;\\s]+)|([\\w.#,$&;(\\s]+[\\w.#,$&;)\\s]+))\\s+([\\w()#.,$&;\\s]+)|([\\w.#,$&;\\s()]+))\\s*\\}";
154
155     /**
156      * Constructor for QDoxSource.
157      *
158      * @param location
159      * @param javaSource
160      * @param logger
161      * @param manager
162      */

163     public QDoxSource(String JavaDoc location, Source javaSource, Logger logger, ServiceManager manager) {
164         this.javadocUri = location;
165         this.javaSource = javaSource;
166         this.logger = logger;
167         this.manager = manager;
168         this.javadocClassName = javadocUri.substring(javadocUri.indexOf(':') + 1);
169         try {
170             createJavadocXml();
171         } catch (SourceException se) {
172             logger.error("Error reading source!", se);
173         } catch (IOException JavaDoc ioe) {
174             logger.error("Error reading source!", ioe);
175         }
176         // Initialize regular expression:
177
try {
178             reLink = new RE(RE_LINK);
179         } catch (RESyntaxException rse) {
180             logger.error("Regular Expression syntax error!", rse);
181         }
182     }
183
184     /**
185      * Returns the parsed Java class.
186      *
187      * @return JavaClass
188      */

189     public JavaClass getJavadocClass() {
190         return javadocClass;
191     }
192
193     /**
194      * @see XMLizable#toSAX(org.xml.sax.ContentHandler)
195      * @throws SAXException if any error occurs during SAX outputting.
196      */

197     public void toSAX(ContentHandler JavaDoc handler) throws SAXException JavaDoc {
198         if (javadocClass == null) {
199             logger.error("No classfile loaded! Cannot output SAX events.");
200             return;
201         }
202
203         if (logger.isDebugEnabled()) {
204             logger.debug("Outputting SAX events for class " + javadocClass.getFullyQualifiedName());
205             logger.debug(" #fields: " + javadocClass.getFields().length);
206             logger.debug(" #methods and constructors: " + javadocClass.getMethods().length);
207         }
208
209         // Output SAX 'header':
210
handler.startDocument();
211         handler.startPrefixMapping(NS_PREFIX, NS_URI);
212
213         // Output class-level element:
214
outputClassStartElement(handler, javadocClass);
215
216         // Modifiers:
217
outputModifiers(handler, javadocClass);
218
219         // Imports:
220
JavaSource parent = javadocClass.getParentSource();
221         // Add two implicit imports:
222
parent.addImport("java.lang.*");
223         if (parent.getPackage() != null) {
224             parent.addImport(parent.getPackage() + ".*");
225         } else {
226             parent.addImport("*");
227         }
228         String JavaDoc[] imports = parent.getImports();
229
230         saxStartElement(handler, IMPORTS_ELEMENT);
231         for (int i = 0; i < imports.length; i++) {
232             if (imports[i].endsWith("*")) {
233                 // package import:
234
saxStartElement(handler, IMPORT_ELEMENT, new String JavaDoc[][] {{IMPORT_ATTRIBUTE, "package"}});
235                 String JavaDoc imp = StringUtils.substringBeforeLast(imports[i], ".*");
236                 saxCharacters(handler, imp);
237             } else {
238                 saxStartElement(handler, IMPORT_ELEMENT, new String JavaDoc[][] {{IMPORT_ATTRIBUTE, "class"}});
239                 saxCharacters(handler, imports[i]);
240             }
241             saxEndElement(handler, IMPORT_ELEMENT);
242         }
243         saxEndElement(handler, IMPORTS_ELEMENT);
244
245         // Superclass:
246
if (!javadocClass.isInterface()) {
247             outputSuperClassInheritance(handler, javadocClass, CLASS_INHERITANCE);
248         }
249
250         // Implements:
251
outputImplements(handler, javadocClass, true);
252
253         // Containing class in case this is an inner class:
254
if (containingJavadocClass != null) {
255             saxStartElement(handler, NESTED_IN_ELEMENT);
256             outputClassStartElement(handler, containingJavadocClass);
257             outputModifiers(handler, containingJavadocClass);
258             outputComment(handler, containingJavadocClass.getComment());
259             outputTags(handler, containingJavadocClass);
260             outputClassEndElement(handler, containingJavadocClass);
261             saxEndElement(handler, NESTED_IN_ELEMENT);
262         }
263
264         // Comment:
265
outputComment(handler, javadocClass.getComment());
266
267         // Tags:
268
outputTags(handler, javadocClass);
269
270         // Inner classes:
271
outputInnerClasses(handler, javadocClass, true);
272
273         // Fields:
274
outputFields(handler, javadocClass, true);
275
276         // Constructors:
277
outputMethods(handler, javadocClass, CONSTRUCTOR_MODE);
278
279         // Methods:
280
outputMethods(handler, javadocClass, METHOD_MODE);
281
282         // Close class-level element:
283
outputClassEndElement(handler, javadocClass);
284
285         // Output SAX 'footer':
286
handler.endPrefixMapping(NS_PREFIX);
287         handler.endDocument();
288     }
289
290     /**
291      * @see Recyclable#recycle()
292      */

293     public void recycle() {
294         if (logger != null && logger.isDebugEnabled()) {
295             logger.debug("Recycling QDoxSource '" + javadocClassName + "'...");
296         }
297
298         manager = null;
299         javaSource = null;
300         javadocUri = null;
301         javadocClassName = null;
302         javadocClass = null;
303         containingJavadocClass = null;
304         classMap = null;
305         logger = null;
306     }
307
308     /**
309      * Get the content length of the source or -1 if it
310      * is not possible to determine the length.
311      */

312     public long getContentLength() {
313         return -1L;
314     }
315
316     /**
317      * @see org.apache.excalibur.source.Source#getLastModified()
318      */

319     public long getLastModified() {
320         return javaSource.getLastModified();
321     }
322
323     /**
324      * @see org.apache.excalibur.source.Source#getMimeType()
325      */

326     public String JavaDoc getMimeType() {
327         return "text/xml";
328     }
329
330     /**
331      * Return the unique identifer for this source
332      */

333     public String JavaDoc getURI() {
334         return javadocUri;
335     }
336
337     /**
338      * @see org.apache.excalibur.source.Source#getValidity()
339      */

340     public SourceValidity getValidity() {
341         return javaSource.getValidity();
342     }
343
344     /**
345      * @see org.apache.excalibur.source.Source#getInputStream()
346      */

347     public InputStream JavaDoc getInputStream() throws IOException JavaDoc, SourceException {
348         if (logger.isDebugEnabled()) {
349             logger.debug("Getting InputStream for class " + javadocClass.getFullyQualifiedName());
350         }
351         XMLSerializer serializer = new XMLSerializer();
352         ByteArrayInputStream JavaDoc inputStream = null;
353
354         try {
355             ByteArrayOutputStream JavaDoc outputStream = new ByteArrayOutputStream JavaDoc(2048);
356             serializer.setOutputStream(outputStream);
357             toSAX(serializer);
358             inputStream = new ByteArrayInputStream JavaDoc(outputStream.toByteArray());
359         } catch (SAXException JavaDoc se) {
360             logger.error("SAX exception!", se);
361             throw new SourceException("Serializing SAX to a ByteArray failed!", se);
362         }
363         return inputStream;
364     }
365
366     protected void createJavadocXml() throws SourceException, IOException JavaDoc {
367         if (logger.isDebugEnabled()) {
368             logger.debug("Reading Java source " + javaSource.getURI());
369         }
370         JavaDocBuilder builder = new JavaDocBuilder();
371         builder.addSource(new BufferedReader JavaDoc(new InputStreamReader JavaDoc(javaSource.getInputStream())));
372
373         javadocClass = builder.getClassByName(javadocClassName);
374         if (javadocClass.getPackage() == null) {
375             // An inner class is specified - let's find it:
376
int index = javadocClassName.lastIndexOf('.');
377             String JavaDoc containingClassName = javadocClassName.substring(0, index);
378             String JavaDoc innerClassName = javadocClassName.substring(index + 1);
379             containingJavadocClass = builder.getClassByName(containingClassName);
380             javadocClass = containingJavadocClass.getInnerClassByName(innerClassName);
381         }
382     }
383
384     /**
385      * Method resolveClassNameFromLink.
386      *
387      * @param ref
388      * @return String
389      */

390     private String JavaDoc resolveClassNameFromLink(String JavaDoc ref) {
391         String JavaDoc classPart = null;
392         int hashIndex = ref.indexOf('#');
393         if (hashIndex < 0) {
394             classPart = ref;
395         } else {
396             classPart = ref.substring(0, hashIndex);
397         }
398         return getQualifiedClassName(classPart);
399     }
400
401     private String JavaDoc getQualifiedClassName(String JavaDoc classPart) {
402         if (classPart.length() == 0) {
403             // No classname specified:
404
classPart = javadocClass.getFullyQualifiedName();
405         } else if (classPart.equals("Object")) {
406             // Fastest way to identify the root object - otherwise the next, *expensive* 'if' block is executed!
407
classPart = ROOT_CLASSNAME;
408         } else if (classPart.indexOf('.') < 0) {
409             // No qualified name specified:
410
String JavaDoc[] imports = javadocClass.getParentSource().getImports();
411             List JavaDoc classImports = new ArrayList JavaDoc();
412             List JavaDoc packageImports = new ArrayList JavaDoc();
413             packageImports.add(javadocClass.getPackage()); // Most likely to find sources here, I guess...
414
packageImports.add("java.lang"); // 2nd most likely place to find sources?
415
for (int i=0; i<imports.length; i++) {
416                 if (imports[i].endsWith(".*")) {
417                     packageImports.add(imports[i].substring(0, imports[i].length() - 2));
418                 } else if (imports[i].endsWith("*")) {
419                     packageImports.add(imports[i].substring(0, imports[i].length() - 1));
420                 } else {
421                     classImports.add(imports[i]);
422                 }
423             }
424
425             boolean found = false;
426             for (int i = 0; !found && i < classImports.size(); i++) {
427                 String JavaDoc name = (String JavaDoc) classImports.get(i);
428                 if (name.endsWith(classPart)) {
429                     classPart = name;
430                     found = true;
431                 }
432             }
433
434             if (!found) {
435                 SourceResolver resolver = null;
436                 try {
437                     resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
438                     for (int i=0; !found && i<packageImports.size(); i++) {
439                         String JavaDoc name = (String JavaDoc) packageImports.get(i);
440                         if (name.length() == 0) {
441                             name = classPart;
442                         } else {
443                             name += '.' + classPart;
444                         }
445
446                         // Test whether the classname 'name' is valid:
447
Source source = resolver.resolveURI(PROTOCOL + name);
448                         found = source != null && source instanceof QDoxSource;
449                         if (found) {
450                             classPart = name;
451                         }
452
453                         resolver.release(source);
454                     }
455                 } catch (ServiceException se) {
456                     logger.error("Could not find a SourceResolver!", se);
457                 } catch (MalformedURLException JavaDoc e) {
458                     // ignore - invalid URI (is subject of test)
459
} catch (SourceException e) {
460                     // ignore
461
} catch (IOException JavaDoc e) {
462                     // ignore
463
} finally {
464                     if (resolver != null) {
465                         manager.release(resolver);
466                     }
467                 }
468             }
469         }
470         return classPart;
471     }
472
473     /**
474      * Method outputClassInheritance.
475      *
476      * @param handler
477      * @param jClass
478      */

479     private void outputSuperClassInheritance(ContentHandler JavaDoc handler, JavaClass jClass, int mode) throws SAXException JavaDoc {
480         JavaClass superClass = getJavadocSuperClass(jClass);
481         if (superClass != null && hasInheritance(jClass, mode)) {
482             outputClassInheritance(handler, superClass, mode);
483         }
484     }
485
486     private void outputClassInheritance(ContentHandler JavaDoc handler, JavaClass jClass, int mode) throws SAXException JavaDoc {
487         outputInheritStartElement(handler, jClass);
488
489         switch (mode) {
490             case CLASS_INHERITANCE :
491                 // Already there!
492
outputSuperClassInheritance(handler, jClass, mode);
493                 break;
494
495             case INTERFACE_INHERITANCE :
496                 // Output interface inheritance summary:
497
outputImplements(handler, jClass, false);
498                 break;
499
500             case INNERCLASS_INHERITANCE :
501                 // Output nested inheritance summary:
502
outputInnerClasses(handler, jClass, false);
503                 break;
504
505             case FIELD_INHERITANCE :
506                 // Output field inheritance summary:
507
outputFields(handler, jClass, false);
508                 break;
509
510             case METHOD_INHERITANCE :
511                 // Output method inheritance summary from implemented interfaces:
512
Type[] interfaces = jClass.getImplements();
513                 for (int i=0; i<interfaces.length; i++) {
514                     logger.debug("inherit from " + interfaces[i].getValue());
515                     outputClassInheritance(handler, getJavaClass(interfaces[i].getValue()), mode);
516                 }
517
518             case CONSTRUCTOR_INHERITANCE :
519                 // Output method/constructor inheritance summary from superclass:
520
if (!(mode == METHOD_INHERITANCE && jClass.isInterface())) {
521                     outputSuperClassInheritance(handler, jClass, mode);
522                 }
523                 JavaMethod[] methods = jClass.getMethods();
524                 for (int i = 0; i < methods.length; i++) {
525                     if ((mode == METHOD_INHERITANCE && methods[i].getReturns() != null) ||
526                         (mode == CONSTRUCTOR_INHERITANCE && methods[i].getReturns() == null)) {
527                         outputMethodStartElement(handler, methods[i]);
528                         outputMethodEndElement(handler, methods[i]);
529                     }
530                 }
531                 break;
532             default :
533                 break;
534         }
535         saxEndElement(handler, INHERIT_ELEMENT);
536     }
537
538     private boolean hasInheritance(JavaClass jClass, int mode) {
539         JavaClass superClass = getJavadocSuperClass(jClass);
540         boolean result = false;
541
542         if (superClass != null) {
543             switch (mode) {
544                 case CLASS_INHERITANCE :
545                     // Already there!
546
result = true;
547                     break;
548
549                 case INTERFACE_INHERITANCE :
550                     result = superClass.getImplements().length > 0;
551                     break;
552
553                 case INNERCLASS_INHERITANCE :
554                     result = superClass.getInnerClasses().length > 0;
555                     break;
556
557                 case FIELD_INHERITANCE :
558                     result = superClass.getFields().length > 0;
559                     break;
560
561                 case METHOD_INHERITANCE :
562                     Type[] interfaces = jClass.getImplements();
563                     for (int i=0; i<interfaces.length && !result; i++) {
564                         JavaClass iface = getJavaClass(interfaces[i].getValue());
565                         result = iface != null && iface.getMethods().length > 0;
566                     }
567
568                 case CONSTRUCTOR_INHERITANCE :
569                     JavaMethod[] methods = superClass.getMethods();
570                     for (int i=0; i<methods.length && !result; i++) {
571                         result = ((mode == METHOD_INHERITANCE && methods[i].getReturns() != null) ||
572                             (mode == CONSTRUCTOR_INHERITANCE && methods[i].getReturns() == null));
573                     }
574                     break;
575
576                 default :
577                     break;
578             }
579
580             if (!result) {
581                 result = hasInheritance(superClass, mode);
582             }
583         }
584
585         return result;
586     }
587
588     /**
589      * Method getJavadocSuperClass.
590      *
591      * @param jClass
592      * @return JavaClass
593      */

594     private JavaClass getJavadocSuperClass(JavaClass jClass) {
595         if (jClass == null) {
596             // May not happen, of course ;-)
597
throw new IllegalArgumentException JavaDoc("Argument 'jClass' must not be <null>!");
598         }
599
600         if (jClass.getFullyQualifiedName().equals(ROOT_CLASSNAME)) {
601             // jClass is root class:
602
return null;
603         }
604
605         JavaClass superClass = null;
606
607         if (!jClass.isInterface()) {
608             try {
609                 // Use QDocx operation to retrieve class:
610
superClass = jClass.getSuperJavaClass();
611             } catch (UnsupportedOperationException JavaDoc uoe) {
612                 // No Cache built (yet)... ignore!
613
}
614         }
615
616         if (superClass == null) {
617             String JavaDoc superJavadocClassName = null;
618
619             if (jClass.isInterface()) {
620                 Type[] interfaces = jClass.getImplements();
621                 if (interfaces.length == 1) {
622                     superJavadocClassName = interfaces[0].getValue();
623                 }
624             } else {
625                 superJavadocClassName = jClass.getSuperClass().getValue();
626
627                 // Is the superClass itself an inner class?
628
if (superJavadocClassName.indexOf('.') == -1 && containingJavadocClass.getInnerClassByName(superJavadocClassName) != null) {
629                     superJavadocClassName = containingJavadocClass.getFullyQualifiedName() + '.' + superJavadocClassName;
630                 }
631             }
632
633             if (superJavadocClassName != null) {
634                 superClass = getJavaClass(superJavadocClassName);
635             }
636         }
637
638         return superClass;
639     }
640
641     /**
642      * Method getInnerClass.
643      *
644      * @param jClass
645      * @param className
646      * @return JavaClass
647      */

648 /* private JavaClass getJavadocInnerClass(JavaClass jClass, String className) {
649         if (jClass != null) {
650             JavaClass[] classes = jClass.getInnerClasses();
651
652             for (int i=0; i<classes.length; i++) {
653                 if (classes[i].getName().equals(className)) {
654                     return classes[i];
655                 }
656             }
657         }
658         return null;
659     }*/

660
661     /**
662      * Get the meta class for the specified classname. The result is cached internally.
663      *
664      * @param className
665      * @return JavaClass
666      */

667     private JavaClass getJavaClass(String JavaDoc className) {
668         if (classMap != null && classMap.containsKey(className)) {
669             return (JavaClass) classMap.get(className);
670         }
671
672         JavaClass jClass = null;
673         SourceResolver resolver = null;
674
675         try {
676             resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
677             Source source = resolver.resolveURI(PROTOCOL + className);
678             if (source instanceof QDoxSource) {
679                 QDoxSource javadocSource = (QDoxSource) source;
680                 jClass = javadocSource.getJavadocClass();
681                 if (classMap == null) {
682                     classMap = new HashMap JavaDoc();
683                 }
684                 classMap.put(className, jClass);
685             }
686             resolver.release(source);
687         } catch (ServiceException se) {
688             logger.error("Couldn't return JavaClass!", se);
689         } catch (MalformedURLException JavaDoc mue) {
690             logger.error("Couldn't return JavaClass!", mue);
691         } catch (SourceException se) {
692             logger.error("Couldn't return JavaClass!", se);
693         } catch (IOException JavaDoc ioe) {
694             logger.error("Couldn't return JavaClass!", ioe);
695         } finally {
696             if (resolver != null) {
697                 manager.release(resolver);
698             }
699         }
700
701         return jClass;
702     }
703
704     /**
705      * Method outputModifiers.
706      *
707      * @param handler
708      * @param entity
709      */

710     private void outputModifiers(ContentHandler JavaDoc handler, AbstractJavaEntity entity) throws SAXException JavaDoc {
711         String JavaDoc[] modifiers = entity.getModifiers();
712         if (modifiers.length > 0) {
713             saxStartElement(handler, MODIFIERS_ELEMENT);
714             for (int i=0; i<modifiers.length; i++) {
715                 saxStartElement(handler, modifiers[i]);
716                 saxEndElement(handler, modifiers[i]);
717             }
718             saxEndElement(handler, MODIFIERS_ELEMENT);
719         }
720     }
721
722     /**
723      * Method outputCommentAndTags.
724      *
725      * @param handler
726      * @param entity
727      */

728     private void outputTags(ContentHandler JavaDoc handler, AbstractJavaEntity entity) throws SAXException