root/trunk/src/java/org/jcoderz/commons/doclet/XmlDoclet.java

Revision 1011, 24.8 kB (checked in by amandel, 4 years ago)

Aligned svn keyword settings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 *
4 * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *    * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    * Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials
15 *      provided with the distribution.
16 *    * Neither the name of the jCoderZ.org Project nor the names of
17 *      its contributors may be used to endorse or promote products
18 *      derived from this software without specific prior written
19 *      permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33package org.jcoderz.commons.doclet;
34
35import java.io.File;
36import java.io.FileOutputStream;
37import java.io.IOException;
38import java.io.OutputStreamWriter;
39import java.io.Writer;
40import java.util.Arrays;
41import java.util.HashMap;
42import java.util.HashSet;
43import java.util.Iterator;
44import java.util.Map;
45import java.util.Set;
46import java.util.logging.Level;
47import java.util.logging.Logger;
48
49import org.jcoderz.commons.ArgumentMalformedException;
50import org.jcoderz.commons.util.ArraysUtil;
51import org.jcoderz.commons.util.IoUtil;
52import org.jcoderz.commons.util.StringUtil;
53import org.jcoderz.commons.util.XmlUtil;
54
55import com.sun.javadoc.ClassDoc;
56import com.sun.javadoc.ConstructorDoc;
57import com.sun.javadoc.Doc;
58import com.sun.javadoc.DocErrorReporter;
59import com.sun.javadoc.Doclet;
60import com.sun.javadoc.ExecutableMemberDoc;
61import com.sun.javadoc.FieldDoc;
62import com.sun.javadoc.MemberDoc;
63import com.sun.javadoc.MethodDoc;
64import com.sun.javadoc.PackageDoc;
65import com.sun.javadoc.ParamTag;
66import com.sun.javadoc.Parameter;
67import com.sun.javadoc.ProgramElementDoc;
68import com.sun.javadoc.RootDoc;
69import com.sun.javadoc.SeeTag;
70import com.sun.javadoc.SourcePosition;
71import com.sun.javadoc.Tag;
72import com.sun.javadoc.ThrowsTag;
73
74/**
75 * A generic doclet that writes out all javadoc information as XML.
76 *
77 * @author Andreas Mandel
78 */
79public class XmlDoclet
80      extends Doclet
81{
82   /** The full qualified name of this class. */
83   private static final String CLASSNAME = XmlDoclet.class.getName();
84
85   /** The logger to use. */
86   private static final Logger logger = Logger.getLogger(CLASSNAME);
87
88   /** Static collector for doclet configuration. */
89   private static XmlDocletConfig sConfig = new XmlDocletConfig();
90
91   /** Concrete configuration for this xml doclet instance. */
92   private final XmlDocletConfig mConfig;
93
94   /** Output writer for current doclet. */
95   private Writer mOut = null;
96
97   private RootDoc mRootDoc;
98
99   /**
100    * Creates a new XmlDoclet with the given (fix) configuration.
101    * @param config the config to use.
102    */
103   public XmlDoclet (XmlDocletConfig config)
104   {
105      try
106      {
107         mConfig = (XmlDocletConfig) config.clone();
108      }
109      catch (CloneNotSupportedException e)
110      {
111         throw new RuntimeException("Clone must be supported by config.", e);
112      }
113   }
114
115   /** {@inheritDoc} */
116   public static boolean start (RootDoc root)
117   {
118      if (logger.isLoggable(Level.FINER))
119      {
120         logger.entering(CLASSNAME, "start(RootDoc)", root);
121      }
122      boolean result = true;
123      try
124      {
125         final XmlDoclet handler = new XmlDoclet(sConfig);
126         handler.handle(root);
127      }
128      catch (Exception ex)
129      {
130         // CHECKME:
131         result = false;
132         root.printError(ex.getMessage());
133         throw new RuntimeException("Internal processing error.", ex);
134      }
135      if (logger.isLoggable(Level.FINER))
136      {
137         logger.exiting(CLASSNAME, "start(RootDoc)", Boolean.valueOf(result));
138      }
139      return result;
140   }
141
142   /** @see XmlDocletConfig#optionLength(String) */
143   public static int optionLength (String option)
144   {
145      if (logger.isLoggable(Level.FINER))
146      {
147         logger.entering(CLASSNAME, "optionLength(String)", option);
148      }
149      final int result = sConfig.optionLength(option);
150      if (logger.isLoggable(Level.FINER))
151      {
152         logger.exiting(CLASSNAME, "optionLength(String)",
153               new Integer(result));
154      }
155      return result;
156   }
157
158   public static boolean validOptions (String[][] arguments,
159         DocErrorReporter reporter)
160   {
161      if (logger.isLoggable(Level.FINER))
162      {
163         logger.entering(CLASSNAME,
164               "validOptions(String[][], DocErrorReporter)",
165               new Object[] {ArraysUtil.toString(arguments), reporter});
166      }
167      boolean result = true;
168      final Iterator i = Arrays.asList(arguments).iterator();
169      while (i.hasNext())
170      {
171         final String[] arg = (String[]) i.next();
172         if (logger.isLoggable(Level.FINER))
173         {
174            logger.finest("About to parse argument: "
175                  + ArraysUtil.toString(arg));
176         }
177         final String[] options = new String[arg.length - 1];
178         System.arraycopy(arg, 1, options, 0, options.length);
179         try
180         {
181            sConfig.parseOption(arg[0], options);
182         }
183         catch (ArgumentMalformedException ex)
184         {
185            reporter.printError(ex.getMessage());
186            result = false;
187         }
188      }
189      if (logger.isLoggable(Level.FINER))
190      {
191         logger.exiting(CLASSNAME,
192               "validOptions(String[][], DocErrorReporter)",
193               Boolean.valueOf(result));
194      }
195      return result;
196   }
197
198
199   private void handle (RootDoc root)
200         throws IOException
201   {
202      // create XML file
203      FileOutputStream streamOut = null;
204      mRootDoc = root;
205      try
206      {
207         streamOut = new FileOutputStream(
208               new File(mConfig.getOutputDirectory(), "javadoc.xml"), false);
209
210         mOut = new OutputStreamWriter(streamOut, "utf-8");
211
212         mOut.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
213         mOut.write("<javadoc>\n");
214
215         final Set handledPackages = new HashSet();
216
217         final PackageDoc[] packages = root.specifiedPackages();
218         for (int i = 0; i < packages.length; ++i)
219         {
220            generatePackageElement(packages[i]);
221            handledPackages.add(packages[i].name());
222         }
223         final ClassDoc[] classes = root.specifiedClasses();
224         for (int i = 0; i < classes.length; ++i)
225         {
226            if (!handledPackages.contains(
227                  classes[i].containingPackage().name()))
228            {
229               generatePackageElement(classes[i].containingPackage());
230               handledPackages.add(classes[i].containingPackage().name());
231            }
232         }
233         mOut.write("</javadoc>");
234
235
236      }
237      finally
238      {
239         IoUtil.close(mOut);
240         IoUtil.close(streamOut);
241         mOut = null;
242      }
243   }
244
245   private void generatePackageElement (PackageDoc pkg)
246         throws IOException
247   {
248      mOut.write("<package");
249      generateDocHeader(pkg);
250      mOut.write(">");
251      generateDocBody(pkg);
252      final ClassDoc[] classes = pkg.allClasses();
253      for (int i = 0; i < classes.length; ++i)
254      {
255         generateClassElement(classes[i]);
256      }
257      mOut.write("</package>");
258   }
259
260   private void generateClassElement (ClassDoc cd)
261         throws IOException
262   {
263      mOut.write("<class");
264      generateClassHeader(cd);
265      mOut.write(">\n");
266      generateClassBody(cd);
267      mOut.write("</class>\n");
268   }
269
270   private void generateClassBody (ClassDoc cd)
271         throws IOException
272   {
273      generateProgramElementBody(cd);
274
275      // Interfaces
276      final ClassDoc[] interfaces = cd.interfaces();
277      for (int i = 0; i < interfaces.length; ++i)
278      {
279         mOut.write("<interface");
280         addAttribute("name", interfaces[i].qualifiedName());
281         mOut.write("/>\n");
282      }
283
284      // InnerClasses
285      final ClassDoc[] innerClass = cd.innerClasses();
286      for (int i = 0; i < innerClass.length; ++i)
287      {
288         mOut.write("<inner");
289         addAttribute("name", innerClass[i].qualifiedName());
290         mOut.write("/>\n");
291      }
292
293
294      // Fields
295      final FieldDoc[] fields = cd.fields();
296      for (int i = 0; i < fields.length; ++i)
297      {
298         final FieldDoc field = fields[i];
299         generateFieldHeader(field);
300         generateFieldBody(field);
301         mOut.write("</field>\n");
302      }
303
304      // Constructors
305      final ConstructorDoc[] constructors = cd.constructors();
306      for (int i = 0; i < constructors.length; ++i)
307      {
308         final ConstructorDoc constructor = constructors[i];
309         generateConstructorHeader(constructor);
310         generateConstructorBody(constructor);
311         mOut.write("</constructor>\n");
312      }
313
314      // Methods.
315      final MethodDoc[] methods = cd.methods();
316      for (int i = 0; i < methods.length; ++i)
317      {
318         final MethodDoc method = methods[i];
319         generateMethodHeader(method);
320         generateMethodBody(method);
321         mOut.write("</method>\n");
322      }
323   }
324
325   private void generateMethodHeader (MethodDoc method)
326         throws IOException
327   {
328      mOut.write("<method");
329
330      addAttribute("abstract", method.isAbstract());
331      if (method.overriddenClass() != null)
332      {
333         addAttribute("overridden-class",
334               method.overriddenClass().qualifiedName());
335      }
336
337      if (method.overriddenMethod() != null)
338      {
339         addAttribute("overridden-method",
340               method.overriddenMethod().qualifiedName());
341      }
342
343      generateExecutableMemberHeader(method);
344      mOut.write(">\n");
345   }
346
347   private void generateMethodBody (MethodDoc method)
348         throws IOException
349   {
350      if (method.returnType() != null
351            && !method.returnType().qualifiedTypeName().equals("void"))
352      {
353         mOut.write("<return");
354         addAttribute("type",
355               method.returnType().qualifiedTypeName()
356                  + method.returnType().dimension());
357         mOut.write(">");
358         final Tag[] returnTag = method.tags("return");
359         if (returnTag != null && returnTag.length > 0)
360         {
361            generatedTagedTextElement(returnTag[0].inlineTags());
362         }
363         mOut.write("</return>\n");
364      }
365      generateExecutableMemberDocBody(method);
366   }
367
368   private void generatedTagedTextElement (final Tag[] tags)
369         throws IOException
370   {
371      mOut.write("<doc>");
372      generateTagedDoc(tags);
373      mOut.write("</doc>\n");
374   }
375
376   private void generateConstructorBody (ConstructorDoc constructor)
377         throws IOException
378   {
379      generateExecutableMemberDocBody(constructor);
380   }
381
382   private void generateExecutableMemberDocBody (
383         ExecutableMemberDoc executableMemberDoc)
384         throws IOException
385   {
386      generateMemberBody(executableMemberDoc);
387
388      // Parameter
389      final ParamTag[] tags = executableMemberDoc.paramTags();
390      final Map parameterTags = new HashMap();
391      for (int i = 0; i < tags.length; ++i)
392      {
393         if (parameterTags.containsKey(tags[i].parameterName()))
394         {
395            warn(tags[i].position(),
396                  "Duplicate parameter ignored. " + tags[i],
397                  executableMemberDoc);
398         }
399         else
400         {
401            // ONLY on tag per parametername
402            parameterTags.put(tags[i].parameterName(), tags[i]);
403         }
404      }
405
406      final Parameter[] parameters = executableMemberDoc.parameters();
407      for (int i = 0; i < parameters.length; ++i)
408      {
409         final ParamTag parameterTag
410               = (ParamTag) parameterTags.get(parameters[i].name());
411//         if (parameterTag == null)
412//         {
413//            warn("No tag for parameter " + parameters[i].hashCode(),
414//                  executableMemberDoc);
415//         }
416         generateParameterHeader(parameters[i], parameterTag);
417         generateParameterBody(parameters[i], parameterTag);
418         mOut.write("</parameter>\n");
419         parameterTags.remove(parameters[i].name());
420      }
421
422      if (!parameterTags.isEmpty())
423      {
424         warn(executableMemberDoc.position(),
425               "Unused parameter tags: " + parameterTags, executableMemberDoc);
426      }
427
428      // Exceptions
429      final ThrowsTag[] tTags = executableMemberDoc.throwsTags();
430      final Map throwsTags = new HashMap();
431      for (int i = 0; i < tTags.length; ++i)
432      {
433         if (throwsTags.containsKey(tTags[i].exceptionName()))
434         {
435            warn(tTags[i].position(),
436                  "Duplicate throws Tags ignored." + tTags[i].exceptionName(),
437                  executableMemberDoc);
438         }
439         else
440         {
441            throwsTags.put(tTags[i].exceptionName(), tTags[i]);
442         }
443      }
444
445      final ClassDoc[] exceptions = executableMemberDoc.thrownExceptions();
446      for (int i = 0; i < exceptions.length; ++i)
447      {
448         ThrowsTag exceptionTag
449               = (ThrowsTag) throwsTags.remove(exceptions[i].qualifiedName());
450         if (exceptionTag == null)
451         {
452            exceptionTag = (ThrowsTag) throwsTags.remove(exceptions[i].name());
453         }
454         if (exceptionTag == null)
455         {
456//            warn(executableMemberDoc.position(),
457//                  "No tag for exception " + exceptions[i].name(),
458//                  executableMemberDoc);
459         }
460         generateThrowsHeader(exceptions[i], exceptionTag);
461         generateThrowsBody(exceptions[i], exceptionTag);
462         mOut.write("</throws>\n");
463      }
464
465      if (!throwsTags.isEmpty())
466      {
467         warn(executableMemberDoc.position(),
468               "Unused throws tags: " + throwsTags, executableMemberDoc);
469      }
470   }
471
472   private void generateMemberBody (MemberDoc member)
473         throws IOException
474   {
475      generateProgramElementBody(member);
476   }
477
478   private void generateProgramElementBody (ProgramElementDoc programElement)
479         throws IOException
480   {
481      generateDocBody(programElement);
482   }
483
484   private void generateThrowsHeader (ClassDoc parameter,
485         ThrowsTag exceptionTag)
486         throws IOException
487   {
488      mOut.write("<throws");
489      addAttribute("type", parameter.qualifiedName());
490      generateTagHeader(exceptionTag);
491      mOut.write(">");
492   }
493
494   private void generateThrowsBody (ClassDoc parameter,
495         ThrowsTag exceptionTag)
496         throws IOException
497   {
498      if (exceptionTag != null)
499      {
500         generateTagBody(exceptionTag);
501      }
502   }
503
504   private void generateParameterBody (Parameter parameter,
505         ParamTag parameterTag)
506         throws IOException
507   {
508      if (parameterTag != null)
509      {
510         generateTagBody(parameterTag);
511      }
512   }
513
514   private void generateParameterHeader (Parameter parameter,
515         ParamTag parameterTag)
516         throws IOException
517   {
518      mOut.write("<parameter");
519      addAttribute("name", parameter.name());
520      addAttribute("type",
521            parameter.type().qualifiedTypeName()
522               + parameter.type().dimension());
523      mOut.write(">");
524   }
525
526   private void generateConstructorHeader (ConstructorDoc cd)
527         throws IOException
528   {
529      mOut.write("<constructor");
530      generateExecutableMemberHeader(cd);
531      mOut.write(">");
532   }
533
534   private void generateExecutableMemberHeader (ExecutableMemberDoc emd)
535         throws IOException
536   {
537      addAttribute("flat-signature", emd.flatSignature());
538      addAttribute("signature", emd.signature());
539      addAttribute("native", emd.isNative());
540      addAttribute("synchronized", emd.isSynchronized());
541      generateMemberHeader(emd);
542   }
543
544   private void generateMemberHeader (MemberDoc md)
545         throws IOException
546   {
547      addAttribute("synthetic", md.isSynthetic());
548      generateProgramElementHeader(md);
549   }
550
551   private void generateFieldBody (FieldDoc fd)
552         throws IOException
553   {
554      generateMemberBody(fd);
555      // TODO: cd.serialFieldTags()
556   }
557
558   private void generateFieldHeader (FieldDoc cd)
559         throws IOException
560   {
561      mOut.write("<field");
562      addAttribute("type",
563            cd.type().qualifiedTypeName() + cd.type().dimension());
564
565      final String constant = cd.constantValueExpression();
566      if (constant != null)
567      {
568         addAttribute("constant", true);
569         addAttribute("value", constant);
570      }
571      addAttribute("volatile", cd.isVolatile());
572      addAttribute("transient", cd.isTransient());
573      generateMemberHeader(cd);
574      mOut.write(">");
575   }
576
577   private void generateDocBody (Doc doc)
578         throws IOException
579   {
580      mOut.write("<doc>");
581      generateTagedDoc(doc.inlineTags());
582      mOut.write("</doc>");
583
584      final Tag[] tags = doc.tags();
585      for (int i = 0; i < tags.length; i++)
586      {
587         final Tag tag = tags[i];
588         // these tags are handled directly
589         if (!tag.kind().equals("@param")
590               && !tag.kind().equals("@return")
591               && !tag.kind().equals("@throws"))
592         {
593            generateTagElement(tag);
594         }
595      }
596   }
597
598   private void generateTagHeader (Tag tag)
599         throws IOException
600   {
601      if (tag != null)
602      {
603         if (tag.position() != null)
604         {
605            generateSourcePositionHeader(tag.position());
606         }
607         addAttribute("name", tag.name());
608
609         if (tag instanceof SeeTag)
610         {
611            final SeeTag seeTag = (SeeTag) tag;
612            addAttribute("label", seeTag.label());
613            addAttribute("referenced-class", seeTag.referencedClassName());
614            addAttribute("referenced-member", seeTag.referencedMemberName());
615            if (seeTag.referencedPackage() != null)
616            {
617               addAttribute("referenced-package",
618                     seeTag.referencedPackage().name());
619            }
620         }
621         else
622         {
623            addAttribute("kind", tag.kind());
624         }
625      }
626   }
627
628   private void generateTagElement (Tag tag)
629         throws IOException
630   {
631      if (tag instanceof SeeTag)
632      {
633         generateSeeElement((SeeTag) tag);
634      }
635      else if (tag != null)
636      {
637         mOut.write("<tag");
638         generateTagHeader(tag);
639         mOut.write(">");
640         generateTagBody(tag);
641         mOut.write("</tag>");
642      }
643   }
644
645   private void generateTagBody (Tag tag)
646         throws IOException
647   {
648      mOut.write("<doc>");
649      generateTagedDoc(tag.inlineTags());
650      mOut.write("</doc>");
651   }
652
653   private void generateTagedDoc (Tag[] tags)
654         throws IOException
655   {
656      // build string to be tidied up
657      final StringBuffer data = new StringBuffer();
658      for (int i = 0; i < tags.length; i++)
659      {
660         final Tag inlineTag = tags[i];
661         if (inlineTag instanceof SeeTag)
662         {
663            data.append("<a id='SEE_TAG_");
664            data.append(Integer.toString(i));
665            data.append("'></a>");
666         }
667         else
668         {
669            data.append(inlineTag.text());
670         }
671      }
672      final String input = data.toString();
673      final String clean;
674      if (input.indexOf('<') != -1 || input.indexOf('&') != -1)
675      {
676         final HtmlCleaner cleaner = new HtmlCleaner();
677         clean = cleaner.clean(data);
678         final String warnings = cleaner.getWarnings();
679         if (!StringUtil.isEmptyOrNull(warnings))
680         {
681            mRootDoc.printWarning("Input:" + input);
682            mRootDoc.printWarning("Clean:" + clean);
683            if (cleaner.hasErrors())
684            {
685               mRootDoc.printWarning(tags[0].position(), warnings);
686               // mRootDoc.printError(tags[0].position(), warnings);
687            }
688            else
689            {
690               mRootDoc.printWarning(tags[0].position(), warnings);
691            }
692         }
693      }
694      else
695      {
696         clean = input;
697      }
698      data.setLength(0);
699      data.append(clean);
700
701      // now replace the a tag back...
702      int pos;
703      while ((pos = data.indexOf("<a id='SEE_TAG_")) != -1)
704      {
705         mOut.write(data.substring(0, pos));
706         final int i = Integer.parseInt(data.substring(pos
707               + "<a id='SEE_TAG_".length(), data.indexOf("'></a>", pos)));
708         generateSeeElement((SeeTag) tags[i]);
709         data.delete(0, data.indexOf("'></a>", pos) + "'></a>".length());
710      }
711      mOut.write(data.toString());
712   }
713
714   private void generateSeeElement (SeeTag tag)
715         throws IOException
716   {
717      mOut.write("<see ");
718      generateTagHeader(tag);
719      mOut.write(">");
720      final String label;
721      if (!StringUtil.isNullOrEmpty(tag.label()))
722      {
723         label = tag.label();
724      }
725      else if (tag.referencedClassName() != null
726            && tag.referencedMemberName() != null)
727      {
728         label = tag.referencedClassName() + "#" + tag.referencedMemberName();
729      }
730      else if (tag.referencedClassName() != null)
731      {
732         label = tag.referencedClassName();
733      }
734      else if (tag.referencedPackage() != null)
735      {
736         label = tag.referencedPackage().name();
737      }
738      else if (tag.referencedMemberName() != null)
739      {
740         label = tag.referencedMemberName();
741      }
742      else
743      {
744         label = "";
745      }
746      mOut.write(XmlUtil.escape(label));
747      mOut.write("</see>");
748   }
749
750   private void generateSourcePositionHeader (SourcePosition position)
751         throws IOException
752   {
753      if (position.file() != null)
754      {
755         addAttribute("file", position.file().getPath());
756      }
757      addAttribute("line", position.line());
758      addAttribute("column", position.column());
759   }
760
761   private void generateClassHeader (ClassDoc cd)
762         throws IOException
763   {
764      generateProgramElementHeader(cd);
765      addAttribute("abstract", cd.isAbstract());
766      addAttribute("externalizable", cd.isExternalizable());
767      addAttribute("serializable", cd.isSerializable());
768      if (cd.superclass() != null)
769      {
770         addAttribute("superclass", cd.superclass().qualifiedName());
771      }
772   }
773
774   private void generateProgramElementHeader (ProgramElementDoc pe)
775         throws IOException
776   {
777      addAttribute("qualified-name", pe.qualifiedName());
778
779      if (pe.containingClass() != null)
780      {
781         addAttribute("containing-class",
782               pe.containingClass().qualifiedName());
783      }
784
785      final String visibility;
786      if (pe.isPrivate())
787      {
788         visibility = "private";
789      }
790      else if (pe.isProtected())
791      {
792         visibility = "protected";
793      }
794      else if (pe.isPackagePrivate())
795      {
796         visibility = "package private";
797      }
798      else if (pe.isPublic())
799      {
800         visibility = "public";
801      }
802      else
803      {
804         throw new RuntimeException("Could not detect access right " + pe);
805      }
806      addAttribute("visibility", visibility);
807      addAttribute("static", pe.isStatic());
808      addAttribute("final", pe.isFinal());
809      addAttribute("modifiers", pe.modifiers());
810      addAttribute("modifier-specifier",
811            String.valueOf(pe.modifierSpecifier()));
812
813      generateDocHeader(pe);
814   }
815
816   private void generateDocHeader (Doc doc)
817         throws IOException
818   {
819      addAttribute("name", doc.name());
820      addAttribute("exception", doc.isException());
821      addAttribute("error", doc.isError());
822      addAttribute("ordinary-class", doc.isOrdinaryClass());
823      if (doc.position() != null)
824      {
825         generateSourcePositionHeader(doc.position());
826      }
827      if (doc.isInterface())
828      {
829         addAttribute("type", "interface");
830      }
831      else if (doc.isClass())
832      {
833         addAttribute("type", "class");
834      }
835   }
836
837   private void addAttribute (String name, boolean value)
838         throws IOException
839   {
840      if (value)
841      {
842         mOut.write(" ");
843         mOut.write(name);
844         mOut.write("='");
845         mOut.write(name);
846         mOut.write("'");
847      }
848   }
849
850   private void addAttribute (String name, int value)
851         throws IOException
852   {
853      addAttribute(name, Integer.toString(value));
854   }
855
856   private void addAttribute (String name, String value)
857         throws IOException
858   {
859      if (!StringUtil.isEmptyOrNull(value))
860      {
861         mOut.write(" ");
862         mOut.write(name);
863         mOut.write("='");
864         mOut.write(XmlUtil.attributeEscape(value));
865         mOut.write("'");
866      }
867   }
868
869   private void warn (SourcePosition pos, String string, Object parameter)
870   {
871      mRootDoc.printWarning(pos, string + " at " + parameter);
872   }
873
874}
Note: See TracBrowser for help on using the browser.