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 JavaDoc {
729         DocletTag[] tags = entity.getTags();
730
731         boolean tagElementPassed = false;
732         for (int i=0; i<tags.length; i++) {
733             String JavaDoc tagName = tags[i].getName();
734             String JavaDoc value = tags[i].getValue();
735             if (!tagElementPassed && !tagName.equals("throws") && !tagName.equals("param")) {
736                 saxStartElement(handler, TAGS_ELEMENT);
737                 tagElementPassed = true;
738             }
739
740             if (tagName.equals("see")) {
741                 saxStartElement(handler, tagName);
742                 outputLink(handler, value, null);
743                 saxEndElement(handler, tagName);
744             } else if (!tagName.equals("throws") && !tagName.equals("param")) {
745                 // the 'throws' and 'param' tags are handled at method exception and method parameter level:
746
saxStartElement(handler, tagName);
747                 outputComment(handler, value);
748                 saxEndElement(handler, tagName);
749             }
750         }
751
752         if (tagElementPassed) {
753             saxEndElement(handler, TAGS_ELEMENT);
754         }
755     }
756
757     /**
758      * Outputs a Javadoc comment.
759      *
760      * @param handler SAX ContentHandler
761      * @param comment The Javadoc comment
762      * @throws SAXException if something goes wrong
763      */

764     private void outputComment(ContentHandler JavaDoc handler, String JavaDoc comment) throws SAXException JavaDoc {
765         if (comment != null && comment.length() > 0) {
766                 saxStartElement(handler, COMMENT_ELEMENT);
767             while (reLink.match(comment)) {
768                 String JavaDoc ref = null;
769                 String JavaDoc display = null;
770                 if (reLink.getParen(6) == null) {
771                     // {@link xxx yyy}
772
ref = reLink.getParen(2);
773                     display = reLink.getParen(5);
774                 } else {
775                     // {@link xxx}
776
ref = reLink.getParen(6);
777                     display = "";
778                 }
779                 // Output SAX:
780
saxCharacters(handler, comment.substring(0, reLink.getParenStart(0)));
781                 outputLink(handler, ref, display);
782                 // Cut from doc:
783
comment = comment.substring(reLink.getParenEnd(0));
784             }
785             saxCharacters(handler, comment);
786             saxEndElement(handler, COMMENT_ELEMENT);
787         }
788     }
789
790     /**
791      * Method outputLink.
792      *
793      * @param handler
794      * @param ref
795      * @param display
796      */

797     private void outputLink(ContentHandler JavaDoc handler, String JavaDoc ref, String JavaDoc display) throws SAXException JavaDoc {
798         String JavaDoc classPart = resolveClassNameFromLink(ref);
799         String JavaDoc memberPart = StringUtils.substringAfter(ref, "#");
800         String JavaDoc displayPart = display;
801
802         List JavaDoc attrs = new ArrayList JavaDoc();
803
804         if (StringUtils.isNotEmpty(classPart)) {
805             attrs.add(new String JavaDoc[] {LINK_CLASS_ATTRIBUTE, classPart});
806         }
807
808         if (StringUtils.isNotEmpty(memberPart)) {
809             attrs.add(new String JavaDoc[] {LINK_MEMBER_ATTRIBUTE, memberPart});
810         }
811
812         if (StringUtils.isEmpty(display) && !ref.equals(classPart + "#" + memberPart)) {
813             displayPart = ref.replace('#', '.');
814         }
815
816         saxStartElement(handler, LINK_ELEMENT, (String JavaDoc[][]) attrs.toArray(new String JavaDoc[][]{{}}));
817         saxCharacters(handler, displayPart);
818         saxEndElement(handler, LINK_ELEMENT);
819     }
820
821     /**
822      * Method outputInnerClasses.
823      *
824      * @param handler
825      * @param jClass
826      * @param detailed
827      */

828     private void outputInnerClasses(ContentHandler JavaDoc handler, JavaClass jClass, boolean detailed) throws SAXException JavaDoc {
829         JavaClass[] innerClasses = jClass.getInnerClasses();
830         if (innerClasses.length > 0 || hasInheritance(jClass, INNERCLASS_INHERITANCE)) {
831             if (detailed) {
832                 saxStartElement(handler, INNERCLASSES_ELEMENT);
833             }
834
835             // Output inheritance:
836
outputSuperClassInheritance(handler, jClass, INNERCLASS_INHERITANCE);
837
838             for (int i=0; i<innerClasses.length; i++) {
839                 outputClassStartElement(handler, innerClasses[i]);
840                 if (detailed) {
841                     outputModifiers(handler, innerClasses[i]);
842                     outputComment(handler, innerClasses[i].getComment());
843                     outputTags(handler, innerClasses[i]);
844                 }
845                 outputClassEndElement(handler, innerClasses[i]);
846             }
847
848             if (detailed) {
849                 saxEndElement(handler, INNERCLASSES_ELEMENT);
850             }
851         }
852     }
853
854     /**
855      * Method outputImplements.
856      *
857      * @param handler
858      * @param jClass
859      */

860     private void outputImplements(ContentHandler JavaDoc handler, JavaClass jClass, boolean detailed) throws SAXException JavaDoc {
861         Type[] interfaces = jClass.getImplements();
862         if (interfaces.length > 0 || hasInheritance(jClass, INTERFACE_INHERITANCE)) {
863             if (detailed) {
864                 saxStartElement(handler, IMPLEMENTS_ELEMENT);
865             }
866
867             // Output inheritance:
868
outputSuperClassInheritance(handler, jClass, INTERFACE_INHERITANCE);
869
870             for (int i=0; i<interfaces.length; i++) {
871                 String JavaDoc name = interfaces[i].getValue();
872                 String JavaDoc pckg = name.substring(0, name.lastIndexOf('.'));
873                 name = name.substring(pckg.length() + 1);
874
875                 saxStartElement(handler, INTERFACE_ELEMENT,
876                     new String JavaDoc[][] {{CLASSNAME_ATTRIBUTE, name},
877                                     {PACKAGE_ATTRIBUTE, pckg},
878                                     {QNAME_ATTRIBUTE, pckg + '.' + name}});
879                 saxEndElement(handler, INTERFACE_ELEMENT);
880             }
881
882             if (detailed) {
883                 saxEndElement(handler, IMPLEMENTS_ELEMENT);
884             }
885         }
886     }
887
888     /**
889      * Method outputFields.
890      *
891      * @param handler
892      * @param jClass
893      * @param detailed
894      */

895     private void outputFields(ContentHandler JavaDoc handler, JavaClass jClass, boolean detailed) throws SAXException JavaDoc {
896         JavaField[] fields = jClass.getFields();
897
898         if (fields.length > 0 || hasInheritance(jClass, FIELD_INHERITANCE)) {
899             if (detailed) {
900                 saxStartElement(handler, FIELDS_ELEMENT);
901             }
902
903             // Output inheritance:
904
outputSuperClassInheritance(handler, jClass, FIELD_INHERITANCE);
905
906             for (int i=0; i<fields.length; i++) {
907                 saxStartElement(handler, FIELD_ELEMENT,
908                     new String JavaDoc[][] {{NAME_ATTRIBUTE, fields[i].getName()},
909                                     {TYPE_ATTRIBUTE, fields[i].getType().getValue()},
910                                     {DIMENSIONS_ATTRIBUTE, Integer.toString(fields[i].getType().getDimensions())}});
911                 if (detailed) {
912                     outputModifiers(handler, fields[i]);
913                     outputComment(handler, fields[i].getComment());
914                     outputTags(handler, fields[i]);
915                 }
916                 saxEndElement(handler, FIELD_ELEMENT);
917             }
918
919             if (detailed) {
920                 saxEndElement(handler, FIELDS_ELEMENT);
921             }
922         }
923     }
924
925     /**
926      * Method outputClassStartElement.
927      *
928      * @param handler
929      * @param jClass
930      */

931     private void outputInheritStartElement(ContentHandler JavaDoc handler, JavaClass jClass) throws SAXException JavaDoc {
932         saxStartElement(handler, INHERIT_ELEMENT,
933             new String JavaDoc[][] {{TYPE_ATTRIBUTE, jClass.isInterface() ? INTERFACE_ELEMENT : CLASS_ELEMENT},
934                             {CLASSNAME_ATTRIBUTE, jClass.getName()},
935                             {PACKAGE_ATTRIBUTE, jClass.getPackage()},
936                             {QNAME_ATTRIBUTE, jClass.getFullyQualifiedName()}});
937     }
938
939     /**
940      * Method outputClassStartElement.
941      *
942      * @param handler
943      * @param jClass
944      */

945     private void outputClassStartElement(ContentHandler JavaDoc handler, JavaClass jClass) throws SAXException JavaDoc {
946         saxStartElement(handler, jClass.isInterface() ? INTERFACE_ELEMENT : CLASS_ELEMENT,
947             new String JavaDoc[][] {{CLASSNAME_ATTRIBUTE, jClass.getName()},
948                             {PACKAGE_ATTRIBUTE, jClass.getPackage()},
949                             {QNAME_ATTRIBUTE, jClass.getFullyQualifiedName()}});
950     }
951
952     /**
953      * Method outputClassEndElement.
954      *
955      * @param handler
956      * @param jClass
957      */

958     private void outputClassEndElement(ContentHandler JavaDoc handler, JavaClass jClass) throws SAXException JavaDoc {
959         saxEndElement(handler, jClass.isInterface() ? INTERFACE_ELEMENT : CLASS_ELEMENT);
960     }
961
962     /**
963      * Method outputMethods.
964      *
965      * @param handler
966      * @param jClass
967      * @param mode
968      */

969     private void outputMethods(ContentHandler JavaDoc handler, JavaClass jClass, int mode) throws SAXException JavaDoc {
970         // Are there any methods in <mode>?
971
int size = 0;
972         String JavaDoc elementGroup, element;
973         JavaMethod[] methods = jClass.getMethods();
974
975         if (mode == CONSTRUCTOR_MODE) {
976             elementGroup = CONSTRUCTORS_ELEMENT;
977             element = CONSTRUCTOR_ELEMENT;
978             for (int i=0; i<methods.length; i++) {
979                 if (methods[i].getReturns() == null) {
980                     size++;
981                 }
982             }
983         } else {
984             elementGroup = METHODS_ELEMENT;
985             element = METHOD_ELEMENT;
986             for (int i=0; i<methods.length; i++) {
987                 if (methods[i].getReturns() != null) {
988                     size++;
989                 }
990             }
991         }
992
993         if (size > 0 || (mode == METHOD_MODE && hasInheritance(jClass, METHOD_INHERITANCE)) ||
994             (mode == CONSTRUCTOR_MODE && hasInheritance(jClass, CONSTRUCTOR_INHERITANCE))) {
995             saxStartElement(handler, elementGroup);
996
997             // Output inheritance:
998
if (mode == METHOD_MODE) {
999                 outputSuperClassInheritance(handler, jClass, METHOD_INHERITANCE);
1000            } else {
1001                outputSuperClassInheritance(handler, jClass, CONSTRUCTOR_INHERITANCE);
1002            }
1003
1004            for (int i=0; i<methods.length; i++) {
1005                if (mode == METHOD_MODE && methods[i].getReturns() != null) {
1006                    outputMethodStartElement(handler, methods[i]);
1007                } else if (mode == CONSTRUCTOR_MODE && methods[i].getReturns() == null) {
1008                    saxStartElement(handler, CONSTRUCTOR_ELEMENT,
1009                        new String JavaDoc[][] {{NAME_ATTRIBUTE, methods[i].getName()},
1010                                        {SIGNATURE_ATTRIBUTE, getSignature(methods[i])}});
1011                } else {
1012                    // Do not process this method or constructor:
1013
continue;
1014                }
1015
1016                JavaParameter[] params = methods[i].getParameters();
1017                DocletTag[] paramTags = methods[i].getTagsByName("param");
1018                DocletTag[] throwsTags = methods[i].getTagsByName("throws");
1019
1020                // Modifiers, comment, tags:
1021
outputModifiers(handler, methods[i]);
1022                outputComment(handler, methods[i].getComment());
1023                outputTags(handler, methods[i]);
1024
1025                // Parameters:
1026
if (params.length > 0) {
1027                    saxStartElement(handler, PARAMETERS_ELEMENT);
1028                    for (int j=0; j<params.length; j++) {
1029                        String JavaDoc paramName = params[j].getName();
1030                        saxStartElement(handler, PARAMETER_ELEMENT,
1031                            new String JavaDoc[][] {{NAME_ATTRIBUTE, paramName},
1032                                            {TYPE_ATTRIBUTE, params[j].getType().getValue()},
1033                                            {DIMENSIONS_ATTRIBUTE, Integer.toString(params[j].getType().getDimensions())}});
1034
1035                        // Is there any doc for this parameter?
1036
for (int k=0; k<paramTags.length; k++) {
1037                            String JavaDoc paramValue = paramTags[k].getValue();
1038                            int splitIndex = paramValue.indexOf(' ');
1039                            String JavaDoc paramValueName = splitIndex > 0 ? paramValue.substring(0, splitIndex) : paramValue;
1040                            if (paramName.equals(paramValueName)) {
1041                                outputComment(handler, splitIndex > 0 ? paramValue.substring(splitIndex + 1) : "");
1042                            }
1043                        }
1044
1045                        saxEndElement(handler, PARAMETER_ELEMENT);
1046                    }
1047                    saxEndElement(handler, PARAMETERS_ELEMENT);
1048                }
1049
1050                // Exceptions:
1051
Type[] exceptions = methods[i].getExceptions();
1052                if (exceptions.length + throwsTags.length > 0) {
1053                    saxStartElement(handler, THROWS_ELEMENT);
1054                    for (int j=0; j<exceptions.length; j++) {
1055                        // Iterate each exception which is declared in the throws clause:
1056
String JavaDoc exceptionName = exceptions[j].getValue();
1057                        saxStartElement(handler, EXCEPTION_ELEMENT, new String JavaDoc[][] {{NAME_ATTRIBUTE, exceptionName}});
1058
1059                        // Is there any doc for this exception?
1060
if (throwsTags.length > 0) {
1061                            String JavaDoc exceptionClassName = exceptionName.substring(exceptionName.lastIndexOf('.'));
1062                            for (int k=0; k<throwsTags.length; k++) {
1063                                String JavaDoc excValue = throwsTags[k].getValue();
1064                                int splitIndex = excValue.indexOf(' ');
1065                                String JavaDoc excValueName = splitIndex > 0 ? excValue.substring(0, splitIndex) : excValue;
1066                                if (exceptionClassName.equals(excValueName)) {
1067                                    outputComment(handler, splitIndex > 0 ? excValue.substring(splitIndex + 1) : "");
1068                                }
1069                            }
1070                        }
1071
1072                        saxEndElement(handler, EXCEPTION_ELEMENT);
1073                    }
1074
1075                    for (int j=0; j<throwsTags.length; j++) {
1076                        // Iterate each exception which is not declared in the throws clause but documented in javadoc:
1077
String JavaDoc content = throwsTags[j].getValue();
1078                        int splitIndex = content.indexOf(' ');
1079                        String JavaDoc exceptionName = content.substring(0, splitIndex);
1080                        String JavaDoc qualifiedExceptionName = getQualifiedClassName(exceptionName);
1081
1082                        // Does the exception *not* exist in the throws clause?
1083
boolean found = false;
1084                        for (int k=0; !found && k<exceptions.length; k++) {
1085                            found = qualifiedExceptionName.equals(exceptions[k].getValue());
1086                        }
1087
1088                        if (!found) {
1089                            saxStartElement(handler, EXCEPTION_ELEMENT, new String JavaDoc[][] {{NAME_ATTRIBUTE, qualifiedExceptionName}});
1090                            outputComment(handler, splitIndex > 0 ? content.substring(splitIndex + 1) : "");
1091                            saxEndElement(handler, EXCEPTION_ELEMENT);
1092                        }
1093                    }
1094
1095                    saxEndElement(handler, THROWS_ELEMENT);
1096                }
1097
1098                saxEndElement(handler, element);
1099            }
1100
1101            saxEndElement(handler, elementGroup);
1102        }
1103    }
1104
1105    /**
1106     * Method getSignature.
1107     *
1108     * @param javaMethod
1109     * @return String
1110     */

1111    private String JavaDoc getSignature(JavaMethod javaMethod) {
1112        StringBuffer JavaDoc sb = new StringBuffer JavaDoc(javaMethod.getName());
1113        sb.append('(');
1114        JavaParameter[] params = javaMethod.getParameters();
1115        for (int j=0; j<params.length; j++) {
1116            if (j > 0) {
1117                sb.append(", ");
1118            }
1119            sb.append(params[j].getType().getValue());
1120            int dims = params[j].getType().getDimensions();
1121            for (int k=0; k<dims; k++) {
1122                sb.append("[]");
1123            }
1124        }
1125        sb.append(')');
1126
1127        return sb.toString();
1128    }
1129
1130    /**
1131     * Method outputMethodStartElement.
1132     *
1133     * @param handler
1134     * @param javaMethod
1135     */

1136    private void outputMethodStartElement(ContentHandler JavaDoc handler, JavaMethod javaMethod) throws SAXException JavaDoc {
1137        if (javaMethod.getReturns() != null) {
1138            saxStartElement(handler, METHOD_ELEMENT,
1139                new String JavaDoc[][] {{NAME_ATTRIBUTE, javaMethod.getName()},
1140                                {TYPE_ATTRIBUTE, javaMethod.getReturns().getValue()},
1141                                {DIMENSIONS_ATTRIBUTE, Integer.toString(javaMethod.getReturns().getDimensions())},
1142                                {SIGNATURE_ATTRIBUTE, getSignature(javaMethod)}});
1143        } else {
1144            saxStartElement(handler, CONSTRUCTOR_ELEMENT,
1145                new String JavaDoc[][] {{NAME_ATTRIBUTE, javaMethod.getName()},
1146                                {SIGNATURE_ATTRIBUTE, getSignature(javaMethod)}});
1147        }
1148    }
1149
1150    /**
1151     * Method outputMethodEndElement.
1152     *
1153     * @param handler
1154     */

1155    private void outputMethodEndElement(ContentHandler JavaDoc handler, JavaMethod javaMethod) throws SAXException JavaDoc {
1156        if (javaMethod.getReturns() != null) {
1157            saxEndElement(handler, METHOD_ELEMENT);
1158        } else {
1159            saxEndElement(handler, CONSTRUCTOR_ELEMENT);
1160        }
1161    }
1162
1163    /**
1164     * Method saxStartElement.
1165     *
1166     * @param handler
1167     * @param localName
1168     */

1169    private void saxStartElement(ContentHandler JavaDoc handler, String JavaDoc localName) throws SAXException JavaDoc {
1170        handler.startElement(NS_URI, localName, NS_PREFIX + ':' + localName, XMLUtils.EMPTY_ATTRIBUTES);
1171    }
1172
1173    /**
1174     * Method saxStartElement.
1175     *
1176     * @param handler
1177     * @param localName
1178     * @param attrs
1179     */

1180    private void saxStartElement(ContentHandler JavaDoc handler, String JavaDoc localName, String JavaDoc[][] attrs) throws SAXException JavaDoc {
1181        AttributesImpl JavaDoc saxAttrs = new AttributesImpl JavaDoc();
1182        for (int i=0; i<attrs.length; i++) {
1183            if (attrs[i].length == 2) {
1184                saxAttrs.addAttribute("", attrs[i][0], attrs[i][0], ATTR_TYPE, attrs[i][1]);
1185            } else if (attrs[i].length == 5) {
1186                saxAttrs.addAttribute(attrs[i][0], attrs[i][1], attrs[i][2], attrs[i][3], attrs[i][4]);
1187            }
1188        }
1189
1190        handler.startElement(NS_URI, localName, NS_PREFIX + ':' + localName, saxAttrs);
1191    }
1192
1193    /**
1194     * Method saxEndElement.
1195     *
1196     * @param handler
1197     * @param localName
1198     */

1199    private void saxEndElement(ContentHandler JavaDoc handler, String JavaDoc localName) throws SAXException JavaDoc {
1200        handler.endElement(NS_URI, localName, NS_PREFIX + ':' + localName);
1201    }
1202
1203    /**
1204     * Method saxCharacters.
1205     *
1206     * @param handler
1207     * @param text
1208     */

1209    private void saxCharacters(ContentHandler JavaDoc handler, String JavaDoc text) throws SAXException JavaDoc {
1210        if (text != null && text.length() > 0) {
1211            handler.characters(text.toCharArray(), 0, text.length());
1212        }
1213    }
1214
1215    /**
1216      * @see org.apache.excalibur.source.Source#exists()
1217      */

1218     public boolean exists() {
1219         return true;
1220     }
1221}
1222
Popular Tags