1 /*
2 * $Header: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/Tag.java,v 1.6 2002/05/17 15:18:12 jstrachan Exp $
3 * $Revision: 1.6 $
4 * $Date: 2002/05/17 15:18:12 $
5 *
6 * ====================================================================
7 *
8 * The Apache Software License, Version 1.1
9 *
10 * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
11 * reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 *
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 *
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in
22 * the documentation and/or other materials provided with the
23 * distribution.
24 *
25 * 3. The end-user documentation included with the redistribution, if
26 * any, must include the following acknowlegement:
27 * "This product includes software developed by the
28 * Apache Software Foundation (http://www.apache.org/)."
29 * Alternately, this acknowlegement may appear in the software itself,
30 * if and wherever such third-party acknowlegements normally appear.
31 *
32 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
33 * Foundation" must not be used to endorse or promote products derived
34 * from this software without prior written permission. For written
35 * permission, please contact apache@apache.org.
36 *
37 * 5. Products derived from this software may not be called "Apache"
38 * nor may "Apache" appear in their names without prior written
39 * permission of the Apache Group.
40 *
41 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
45 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
48 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
49 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 * ====================================================================
54 *
55 * This software consists of voluntary contributions made by many
56 * individuals on behalf of the Apache Software Foundation. For more
57 * information on the Apache Software Foundation, please see
58 * <http://www.apache.org/>.
59 *
60 * $Id: Tag.java,v 1.6 2002/05/17 15:18:12 jstrachan Exp $
61 */
62
63 package org.apache.commons.jelly.util;
64
65 import com.sun.javadoc.*;
66
67 import java.beans.Introspector;
68 import java.io.*;
69 import java.util.*;
70
71 import org.cyberneko.html.parsers.SAXParser;
72
73 import org.dom4j.io.OutputFormat;
74 import org.dom4j.io.XMLWriter;
75
76 import org.xml.sax.*;
77 import org.xml.sax.helpers.*;
78
79 /***
80 * Main Doclet class to generate Tag Library ML.
81 *
82 * @author <a href="mailto:gopi@aztecsoft.com">Gopinath M.R.</a>
83 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
84 */
85
86 // #### somehow we need to handle taglib inheritence...
87
88 public class TagXMLDoclet extends Doclet {
89
90 private String xmlns = "jvx";
91 private String encodingFormat="UTF-8";
92 private String localName = "javadoc";
93 private ContentHandler cm = null;
94 private String targetFileName="target/taglib.xml";
95 private Attributes emptyAtts = new AttributesImpl();
96
97 public TagXMLDoclet (RootDoc root) throws Exception {
98 FileOutputStream writer = new FileOutputStream(targetFileName);
99 OutputFormat format = OutputFormat.createPrettyPrint();
100 XMLWriter xmlWriter = new XMLWriter(writer, format);
101 try {
102 cm = xmlWriter;
103 cm.startDocument();
104 javadocXML(root);
105 cm.endDocument();
106 xmlWriter.close();
107 }
108 catch (IOException e) {
109 xmlWriter.close();
110 throw e;
111 }
112 }
113
114 /***
115 * Generates the xml for the tag libraries
116 */
117 private void javadocXML(RootDoc root) throws SAXException {
118 cm.startElement(xmlns, localName, "tags", emptyAtts);
119 PackageDoc[] packageArray = root.specifiedPackages();
120
121 // Generate for packages.
122 for (int i = 0; i < packageArray.length; ++i) {
123 packageXML(packageArray[i]);
124 }
125
126 cm.endElement(xmlns, localName, "tags");
127 }
128
129 /***
130 * Generates doc for a tag library
131 */
132 private void packageXML(PackageDoc packageDoc) throws SAXException {
133 ClassDoc[] classArray = packageDoc.ordinaryClasses();
134
135 // lets see if we find a Tag
136 boolean foundTag = false;
137 for (int i = 0; i < classArray.length; ++i) {
138 ClassDoc classDoc = classArray[i];
139 if ( isTag( classArray[i] ) ) {
140 foundTag = true;
141 break;
142 }
143 }
144 if ( ! foundTag ) {
145 return;
146 }
147
148 AttributesImpl atts = new AttributesImpl();
149 atts.addAttribute(xmlns, localName, "name", "String", packageDoc.name());
150
151 String name = packageDoc.name();
152 int idx = name.lastIndexOf('.');
153 if ( idx > 0 ) {
154 name = name.substring(idx+1);
155 }
156 atts.addAttribute(xmlns, localName, "prefix", "String", name);
157
158 String uri = "jelly:" + name;
159
160 atts.addAttribute(xmlns, localName, "uri", "String", uri );
161 cm.startElement(xmlns, localName, "library", atts);
162
163 // generate Doc element.
164 docXML(packageDoc);
165
166 // generate tags
167 for (int i = 0; i < classArray.length; ++i) {
168 if ( isTag( classArray[i] ) ) {
169 tagXML(classArray[i]);
170 }
171 }
172 cm.endElement(xmlns, localName, "library");
173 }
174
175 /***
176 * @return true if this class is a Jelly Tag
177 */
178 private boolean isTag(ClassDoc classDoc) {
179 ClassDoc[] interfaceArray = classDoc.interfaces();
180 for (int i = 0; i < interfaceArray.length; ++i) {
181 String name = interfaceArray[i].qualifiedName();
182 if ("org.apache.commons.jelly.Tag".equals(name)) {
183 return true;
184 }
185 }
186 ClassDoc base = classDoc.superclass();
187 if ( base != null ) {
188 return isTag(base);
189 }
190 return false;
191 }
192
193 /***
194 * Generates doc for a tag
195 */
196 private void tagXML(ClassDoc classDoc) throws SAXException {
197 if (classDoc.isAbstract()) {
198 return;
199 }
200
201 AttributesImpl atts = new AttributesImpl();
202 atts.addAttribute(xmlns, localName, "className", "String", classDoc.name());
203 String name = classDoc.name();
204 if ( name.endsWith( "Tag" ) ) {
205 name = name.substring(0, name.length() - 3 );
206 }
207 name = Introspector.decapitalize(name);
208
209 atts.addAttribute(xmlns, localName, "name", "String", name);
210 cm.startElement(xmlns, localName, "tag", atts);
211
212 // generate "doc" sub-element
213 docXML(classDoc);
214
215 // generate the attributes
216 propertiesXML(classDoc);
217
218 // generate "method" sub-elements
219 cm.endElement(xmlns, localName, "tag");
220 }
221
222 /***
223 * Generates doc for a tag property
224 */
225 private void propertiesXML(ClassDoc classDoc) throws SAXException {
226 MethodDoc[] methodArray = classDoc.methods();
227 for (int i = 0; i < methodArray.length; ++i) {
228 propertyXML(methodArray[i]);
229 }
230 ClassDoc base = classDoc.superclass();
231 if ( base != null ) {
232 propertiesXML( base );
233 }
234 }
235
236
237 /***
238 * Generates doc for a tag property
239 */
240 private void propertyXML(MethodDoc methodDoc) throws SAXException {
241 if ( ! methodDoc.isPublic() || methodDoc.isStatic() ) {
242 return;
243 }
244 String name = methodDoc.name();
245 if ( ! name.startsWith( "set" ) ) {
246 return;
247 }
248 Parameter[] parameterArray = methodDoc.parameters();
249 if ( parameterArray == null || parameterArray.length != 1 ) {
250 return;
251 }
252 Parameter parameter = parameterArray[0];
253
254 name = name.substring(3);
255 name = Introspector.decapitalize(name);
256
257 if ( name.equals( "body") || name.equals( "context" ) || name.equals( "parent" ) ) {
258 return;
259 }
260 AttributesImpl atts = new AttributesImpl();
261 atts.addAttribute(xmlns, localName, "name", "String", name);
262 atts.addAttribute(xmlns, localName, "type", "String", parameter.typeName());
263
264 cm.startElement(xmlns, localName, "attribute", atts);
265
266 // maybe do more semantics, like use custom tags to denote if its required, optional etc.
267
268 // generate "doc" sub-element
269 docXML(methodDoc);
270
271 cm.endElement(xmlns, localName, "attribute");
272 }
273
274 /***
275 * Generates doc for element "doc"
276 */
277 private void docXML(Doc doc) throws SAXException {
278 cm.startElement(xmlns, localName, "doc", emptyAtts);
279 String commentText = doc.commentText();
280 if (! commentText.equals("")) {
281 parseHTML(commentText);
282 // cm.characters(commentText.toCharArray(), 0, commentText.length());
283 }
284 Tag[] tags = doc.tags();
285 for (int i = 0; i < tags.length; ++i) {
286 javadocTagXML(tags[i]);
287 }
288 cm.endElement(xmlns, localName, "doc");
289 /*
290 String commentText = "";
291 boolean createDoc = false;
292 commentText = doc.commentText();
293 if (! commentText.equals("")) {
294 createDoc = true;
295 }
296 Tag[] tags = doc.tags();
297 if (tags.length > 0) {
298 createDoc = true;
299 }
300 if (createDoc) {
301 cm.startElement(xmlns, localName, "doc", emptyAtts);
302 if (! commentText.equals("")) {
303 cm.characters(commentText.toCharArray(), 0, commentText.length());
304 }
305 for (int i = 0; i < tags.length; ++i) {
306 javadocTagXML(tags[i]);
307 }
308 cm.endElement(xmlns, localName, "doc");
309 }
310 */
311 }
312
313 protected void parseHTML(String text) throws SAXException {
314 SAXParser parser = new SAXParser();
315 parser.setProperty(
316 "http://cyberneko.org/html/properties/names/elems",
317 "lower"
318 );
319 parser.setProperty(
320 "http://cyberneko.org/html/properties/names/attrs",
321 "lower"
322 );
323 parser.setContentHandler(
324 new DefaultHandler() {
325 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
326 if ( validDocElementName( localName ) ) {
327 cm.startElement(namespaceURI, localName, qName, atts);
328 }
329 }
330 public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
331 if ( validDocElementName( localName ) ) {
332 cm.endElement(namespaceURI, localName, qName);
333 }
334 }
335 public void characters(char[] ch, int start, int length) throws SAXException {
336 cm.characters(ch, start, length);
337 }
338 }
339 );
340 try {
341 parser.parse( new InputSource(new StringReader( text )) );
342 }
343 catch (IOException e) {
344 System.err.println( "This should never happen!" + e );
345 }
346 }
347
348 /***
349 * @return true if the given name is a valid HTML markup element.
350 */
351 protected boolean validDocElementName(String name) {
352 return ! name.equalsIgnoreCase( "html" ) && ! name.equalsIgnoreCase( "body" );
353 }
354
355 /***
356 * Generates doc for all tag elements.
357 */
358 private void javadocTagXML(Tag tag) throws SAXException {
359 String name = tag.name().substring(1) + "tag";
360 if (! tag.text().equals("")) {
361 cm.startElement(xmlns, localName, name, emptyAtts);
362 cm.characters(tag.text().toCharArray(), 0, tag.text().length());
363 cm.endElement(xmlns, localName, name);
364 }
365 }
366
367 public static boolean start(RootDoc root) {
368 try {
369 new TagXMLDoclet(root);
370 return true;
371 } catch (Exception e) {
372 e.printStackTrace();
373 System.exit(1);
374 return false;
375 }
376 }
377 }
This page was automatically generated by Maven