View Javadoc
1   package org.codehaus.mojo.jaxb2.schemageneration.postprocessing.javadoc;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.codehaus.mojo.jaxb2.schemageneration.postprocessing.NodeProcessor;
23  import org.codehaus.mojo.jaxb2.schemageneration.postprocessing.javadoc.location.ClassLocation;
24  import org.codehaus.mojo.jaxb2.schemageneration.postprocessing.javadoc.location.FieldLocation;
25  import org.codehaus.mojo.jaxb2.schemageneration.postprocessing.javadoc.location.MethodLocation;
26  import org.codehaus.mojo.jaxb2.shared.Validate;
27  import org.w3c.dom.Node;
28  
29  import java.util.SortedMap;
30  
31  /**
32   * <p>Node processor that injects XSD documentation annotations consisting of JavaDoc harvested Java source code
33   * into ComplexTypes, Elements and Attributes. The documentation is injected as follows:</p>
34   * <ol>
35   * <li><strong>ComplexType</strong>: Class-level JavaDoc from the corresponding type is injected as an
36   * annotation directly inside the complexType.</li>
37   * <li><strong>Element</strong>: Field-level JavaDoc (or getter Method-level JavaDoc, in case the Field does
38   * not contain a JavaDoc annotation) from the corresponding member is injected as an
39   * annotation directly inside the element.</li>
40   * <li><strong>Attribute</strong>: Field-level JavaDoc (or getter Method-level JavaDoc, in case the Field does
41   * not contain a JavaDoc annotation) from the corresponding member is injected as an
42   * annotation directly inside the element.</li>
43   * </ol>
44   * <p>Thus, the following 'vanilla'-generated XSD:</p>
45   * <pre>
46   *     <code>
47   *         &lt;xs:complexType name="somewhatNamedPerson"&gt;
48   *             &lt;xs:sequence&gt;
49   *                 &lt;xs:element name="firstName" type="xs:string" nillable="true" minOccurs="0"/&gt;
50   *                 &lt;xs:element name="lastName" type="xs:string"/&gt;
51   *             &lt;/xs:sequence&gt;
52   *             &lt;xs:attribute name="age" type="xs:int" use="required"/&gt;
53   *         &lt;/xs:complexType&gt;
54   *     </code>
55   * </pre>
56   * <p>... would be converted to the following annotated XSD, given a DefaultJavaDocRenderer:</p>
57   * <pre>
58   *     <code>
59   *         &lt;xs:complexType name="somewhatNamedPerson"&gt;
60   *             &lt;xs:annotation&gt;
61   *                 &lt;xs:documentation&gt;&lt;![CDATA[Definition of a person with lastName and age, and optionally a firstName as well...
62   *
63   *                 (author): &lt;a href="mailto:lj@jguru.se"&gt;Lennart J&ouml;relid&lt;/a&gt;, jGuru Europe AB
64   *                 (custom): A custom JavaDoc annotation.]]&gt;&lt;/xs:documentation&gt;
65   *             &lt;/xs:annotation&gt;
66   *             &lt;xs:sequence&gt;
67   *                 &lt;xs:element minOccurs="0" name="firstName" nillable="true" type="xs:string"&gt;
68   *                     &lt;xs:annotation&gt;
69   *                         &lt;xs:documentation&gt;&lt;![CDATA[The first name of the SomewhatNamedPerson.]]&gt;&lt;/xs:documentation&gt;
70   *                     &lt;/xs:annotation&gt;
71   *                 &lt;/xs:element&gt;
72   *                 &lt;xs:element name="lastName" type="xs:string"&gt;
73   *                     &lt;xs:annotation&gt;
74   *                         &lt;xs:documentation&gt;&lt;![CDATA[The last name of the SomewhatNamedPerson.]]&gt;&lt;/xs:documentation&gt;
75   *                     &lt;/xs:annotation&gt;
76   *                 &lt;/xs:element&gt;
77   *            &lt;/xs:sequence&gt;
78   *            &lt;xs:attribute name="age" type="xs:int" use="required"&gt;
79   *                &lt;xs:annotation&gt;
80   *                    &lt;xs:documentation&gt;&lt;![CDATA[The age of the SomewhatNamedPerson. Must be positive.]]&gt;&lt;/xs:documentation&gt;
81   *                &lt;/xs:annotation&gt;
82   *            &lt;/xs:attribute&gt;
83   *          &lt;/xs:complexType&gt;
84   *     </code>
85   * </pre>
86   * <p>... given that the Java class <code>SomewhatNamedPerson</code> has JavaDoc on its class and fields
87   * corresponding to the injected XSD annotation/documentation elements.</p>
88   *
89   * @author <a href="mailto:lj@jguru.se">Lennart J&ouml;relid</a>, jGuru Europe AB
90   * @see org.codehaus.mojo.jaxb2.schemageneration.postprocessing.javadoc.JavaDocRenderer
91   * @since 2.0
92   */
93  public class XsdAnnotationProcessor implements NodeProcessor {
94  
95      // Internal state
96      private SortedMap<ClassLocation, JavaDocData> classJavaDocs;
97      private SortedMap<FieldLocation, JavaDocData> fieldJavaDocs;
98      private SortedMap<MethodLocation, JavaDocData> methodJavaDocs;
99      private JavaDocRenderer renderer;
100 
101     /**
102      * Creates an XsdAnnotationProcessor that uses the supplied/generated SearchableDocumentation to read all
103      * JavaDoc structures and the supplied JavaDocRenderer to render JavaDocs into XSD documentation annotations.
104      *
105      * @param docs     A non-null SearchableDocumentation, produced from the source code of the JAXB compilation unit.
106      * @param renderer A non-null JavaDocRenderer, used to render the JavaDocData within the SearchableDocumentation.
107      */
108     public XsdAnnotationProcessor(final SearchableDocumentation docs, final JavaDocRenderer renderer) {
109 
110         // Check sanity
111         Validate.notNull(docs, "docs");
112         Validate.notNull(renderer, "renderer");
113 
114         // Assign internal state
115         this.classJavaDocs = docs.getAll(ClassLocation.class);
116         this.fieldJavaDocs = docs.getAll(FieldLocation.class);
117         this.methodJavaDocs = docs.getAll(MethodLocation.class);
118         this.renderer = renderer;
119     }
120 
121     /**
122      * {@inheritDoc}
123      */
124     @Override
125     public boolean accept(final Node aNode) {
126 
127         // Only deal with Element nodes with "name" attributes.
128         if(!DomHelper.isNamedElement(aNode)) {
129             return false;
130         }
131 
132         /*
133         <xs:complexType name="somewhatNamedPerson">
134             <!-- ClassLocation JavaDocData insertion point -->
135 
136             <xs:sequence>
137 
138                 <!-- FieldLocation or MethodLocation JavaDocData insertion point (within child) -->
139                 <xs:element name="firstName" type="xs:string" nillable="true" minOccurs="0"/>
140 
141                 <!-- FieldLocation or MethodLocation JavaDocData insertion point (within child) -->
142                 <xs:element name="lastName" type="xs:string"/>
143             </xs:sequence>
144 
145             <!-- FieldLocation or MethodLocation JavaDocData insertion point (within child) -->
146             <xs:attribute name="age" type="xs:int" use="required"/>
147         </xs:complexType>
148         */
149 
150         // Only process nodes corresponding to Types we have any JavaDoc for.
151         // TODO: How should we handle PackageLocations and package documentation.
152         boolean toReturn = false;
153         if (DomHelper.getMethodLocation(aNode, methodJavaDocs.keySet()) != null) {
154             toReturn = true;
155         } else if (DomHelper.getFieldLocation(aNode, fieldJavaDocs.keySet()) != null) {
156             toReturn = true;
157         } else if (DomHelper.getClassLocation(aNode, classJavaDocs.keySet()) != null) {
158             toReturn = true;
159         }
160 
161         // All done.
162         return toReturn;
163     }
164 
165     /**
166      * {@inheritDoc}
167      */
168     @Override
169     public void process(final Node aNode) {
170         DomHelper.insertXmlDocumentationAnnotationsFor(aNode, classJavaDocs, fieldJavaDocs, methodJavaDocs, renderer);
171     }
172 }