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 * <xs:complexType name="somewhatNamedPerson">
48 * <xs:sequence>
49 * <xs:element name="firstName" type="xs:string" nillable="true" minOccurs="0"/>
50 * <xs:element name="lastName" type="xs:string"/>
51 * </xs:sequence>
52 * <xs:attribute name="age" type="xs:int" use="required"/>
53 * </xs:complexType>
54 * </code>
55 * </pre>
56 * <p>... would be converted to the following annotated XSD, given a DefaultJavaDocRenderer:</p>
57 * <pre>
58 * <code>
59 * <xs:complexType name="somewhatNamedPerson">
60 * <xs:annotation>
61 * <xs:documentation><![CDATA[Definition of a person with lastName and age, and optionally a firstName as well...
62 *
63 * (author): <a href="mailto:lj@jguru.se">Lennart Jörelid</a>, jGuru Europe AB
64 * (custom): A custom JavaDoc annotation.]]></xs:documentation>
65 * </xs:annotation>
66 * <xs:sequence>
67 * <xs:element minOccurs="0" name="firstName" nillable="true" type="xs:string">
68 * <xs:annotation>
69 * <xs:documentation><![CDATA[The first name of the SomewhatNamedPerson.]]></xs:documentation>
70 * </xs:annotation>
71 * </xs:element>
72 * <xs:element name="lastName" type="xs:string">
73 * <xs:annotation>
74 * <xs:documentation><![CDATA[The last name of the SomewhatNamedPerson.]]></xs:documentation>
75 * </xs:annotation>
76 * </xs:element>
77 * </xs:sequence>
78 * <xs:attribute name="age" type="xs:int" use="required">
79 * <xs:annotation>
80 * <xs:documentation><![CDATA[The age of the SomewhatNamedPerson. Must be positive.]]></xs:documentation>
81 * </xs:annotation>
82 * </xs:attribute>
83 * </xs:complexType>
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ö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 }