/*******************************************************************************
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.apache.kato.anttasks.xmlgen;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.Writer;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.lang.StringEscapeUtils;
import org.cyberneko.html.parsers.DOMFragmentParser;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.ConstructorDoc;
import com.sun.javadoc.FieldDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.javadoc.ParamTag;
import com.sun.javadoc.Parameter;
import com.sun.javadoc.SeeTag;
import com.sun.javadoc.Tag;
import com.sun.javadoc.ThrowsTag;
import com.sun.javadoc.Type;
public class XMLWriter {
private static String url="http://java.sun.com/javase/6/docs/api";
private Writer model=null;
private PrintWriter out=null;
private DocumentBuilder builder=null;
public XMLWriter(Writer model) {
this.model=model;
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
try {
builder=factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public XMLWriter() {
this(null);
}
public void close() {
write("</javadoc>");
out.close();
}
private void write(String data) {
out.print(data);
//System.out.println(data);
}
public void open() throws IOException {
out=new PrintWriter(model);
//write("<javadoc>");
write("<javadoc xmlns:html=\"http://www.w3.org/1999/xhtml\" xmlns:db=\"http://docbook.org/ns/docbook\" xmlns=\"http://apache.org/javadoc\">");
}
public void writeClass(ClassDoc c) throws IOException {
write("<class name=\""+c.name()+"\">");
Tag[] tags=c.firstSentenceTags();
writeSummary(tags);
writeComment(c.commentText());
FieldDoc[] fields = c.fields();
for(int i=0; i < fields.length; i++) {
writeField(fields[i]);
}
ConstructorDoc[] constructors = c.constructors();
for(int i=0; i < constructors.length; i++) {
writeConstructor(constructors[i]);
}
MethodDoc[] methods = c.methods();
for(int i=0; i < methods.length; i++) {
writeMethod(methods[i]);
}
SeeTag[] seetags=c.seeTags();
writeSeeTags(seetags);
writeModifiers(c.modifiers());
writeElement("extends",c.superclass().qualifiedName());
write("</class>");
}
private void writeModifiers(String modifiers) {
write("<modifiers>"+modifiers+"</modifiers>");
}
private void writeElement(String elementName, String text) {
write("<"+elementName+">"+text+"</"+elementName+">");
}
private void writeField(FieldDoc f) throws IOException {
write("<field name=\""+f.name()+"\" value=\""+StringEscapeUtils.escapeXml(f.constantValueExpression())
+"\" >");
writeComment(f.commentText());
write("</field>");
}
private void writeMethod(MethodDoc m) throws IOException {
write("<method name=\""+m.name()+"\" signature=\""+m.signature()+"\" >");
Parameter[] parameters=m.parameters();
write(parameters);
ParamTag[] ptags=m.paramTags();
write(ptags);
Type t=m.returnType();
writeType("returntype",t);
writeModifiers(m.modifiers());
writeSummary(m.firstSentenceTags());
writeComment(m.commentText());
Tag[] returnTags=m.tags("return");
writeReturnTags(returnTags);
ThrowsTag[] throwsTags=m.throwsTags();
writeThrowsTags(throwsTags);
SeeTag[] seetags=m.seeTags();
writeSeeTags(seetags);
write("</method>");
}
private void writeThrowsTags(ThrowsTag[] throwsTags) throws IOException {
if(throwsTags==null || throwsTags.length==0) return; // nothing to do
write("<throws>");
for(int i=0; i < throwsTags.length; i++) {
ThrowsTag t = throwsTags[i];
String name=t.exceptionName();
String comment=t.exceptionComment();
write("<throw name=\""+name+"\">");
writeHTMLFormattedText(comment);
write("</throw>");
}
write("</throws>");
}
private void writeReturnTags(Tag[] returnTags) throws IOException {
if(returnTags==null || returnTags.length==0) return; // nothing to do
write("<returns>");
for(int i=0; i < returnTags.length; i++) {
writeHTMLText("return",returnTags[i].text());
}
write("</returns>");
}
private void writeSeeTags(SeeTag[] seetags) {
if(seetags==null || seetags.length==0) return;
write("<seerefs>");
for(int i=0; i < seetags.length; i++) {
write(seetags[i]);
}
write("</seerefs>");
}
private void write(SeeTag seetag) {
write("<see>"+seetag.text()+"</see>");
}
private void write(ParamTag[] parameters) throws IOException {
if(parameters==null || parameters.length==0) return;
write("<paramdescs>");
for(int i=0; i < parameters.length; i++) {
write(parameters[i]);
}
write("</paramdescs>");
}
private void write(ParamTag p) throws IOException {
String name=p.parameterName();
write("<paramdesc name=\""+name+"\">");
String comment=p.parameterComment();
if(comment!=null ) {
writeHTMLFormattedText(comment);
}
write("</paramdesc>");
}
private void write(Parameter[] parameters) {
if(parameters==null || parameters.length==0) return;
write("<parameters>");
for(int i=0; i<parameters.length; i++) {
write(parameters[i]);
}
write("</parameters>");
}
private void write(Parameter p) {
write("<parameter type=\""+p.typeName()+"\" name=\""+p.name() + "\">");
Type t=p.type();
writeType("type",t);
write("</parameter>");
}
private void writeType(String tag,Type t) {
write("<"+tag+">");
write("<name>"+t.typeName()+"</name>");
write("<simple>"+t.simpleTypeName()+"</simple>");
write("<qualified>"+t.qualifiedTypeName()+"</qualified>");
write("</"+tag+">");
}
private void writeConstructor(ConstructorDoc r) throws IOException {
write("<constructor signature=\""+r.signature()+"\" >");
Parameter[] parameters=r.parameters();
write(parameters);
ParamTag[] ptags=r.paramTags();
write(ptags);
ThrowsTag[] throwsTags=r.throwsTags();
writeThrowsTags(throwsTags);
SeeTag[] seetags=r.seeTags();
writeSeeTags(seetags);
writeModifiers(r.modifiers());
writeComment(r.commentText());
write("</constructor>");
}
private void writeComment(String text) throws IOException {
writeHTMLText("comment",text);
}
private void writeHTMLText(String tag,String commentText) throws IOException {
if(commentText==null) return;
commentText=commentText.trim();
if(commentText.equals("")) return;
write("<"+tag+">");
writeHTMLFormattedText(commentText);
write("</"+tag+">");
}
private void writeHTMLFormattedText(String commentText) throws IOException {
if(commentText==null) return;
commentText=commentText.trim();
if(commentText.equals("")) return;
if(commentText.startsWith("<p>")==false) {
commentText="<p>"+commentText;
}
commentText=replaceLinks(commentText);
DOMFragmentParser parser = new DOMFragmentParser();
Document doc=builder.newDocument();
DocumentFragment fragment = doc.createDocumentFragment();
try {
parser.parse(new InputSource(new StringReader(commentText)), fragment);
} catch (SAXException e) {
IOException ioe = new IOException();
ioe.initCause(e);
throw ioe;
}
write(fragment);
}
/**
* Replaces @links with doc references
*
* @param commentText
* @return
*/
private String replaceLinks(String commentText) {
while(true) {
int start=commentText.indexOf("{@link ");
if(start<0) break;
int end=commentText.indexOf('}',start);
if(end<0) break;
String left=commentText.substring(0,start);
String right=commentText.substring(end+1);
String middle=commentText.substring(start+7,end).trim();
if(middle.startsWith("#")) {
// local ref
commentText=left+" "+middle.substring(1)+" "+right;
}
else {
// long ref.
// same package?
if(middle.startsWith("java.")) {
commentText=left+"<ulink url=\""+url+middle.replace('.','/')+".html\">"+middle+"</ulink>"+right;
}
else {
commentText=left+middle+right;
}
}
}
return commentText;
}
private void write(DocumentFragment fragment) {
NodeList list=fragment.getChildNodes();
write(list);
}
private void write(NodeList list) {
if(list==null) return;
int length=list.getLength();
for(int i=0;i<length;i++) {
Node n=list.item(i);
switch (n.getNodeType()) {
case Node.TEXT_NODE :
String text=n.getNodeValue(); // Changed from getTextValue()
if(text!=null) write(text);
break;
case Node.ELEMENT_NODE :
String name=n.getNodeName();
name=mapNameToDocBook(name);
write("<"+name+">");
if(n.hasChildNodes()) {
NodeList kids=n.getChildNodes();
write(kids);
}
write("</"+name+">");
break;
default :
write("<node id=\""+n.getNodeName()+"\"/>");
}
}
}
private String mapNameToDocBook(String name) {
name=name.toUpperCase();
if(name.equals("H1")) name="db:sect2";
if(name.equals("H2")) name="db:sect3";
if(name.equals("H3")) name="db:sect4";
if(name.equals("H4")) name="db:sect5";
if(name.equals("P")) name="db:para";
if(name.equals("I")) name="db:emphasis";
if(name.equals("TABLE")) name="db:informaltable";
if(name.equals("TR")) name="db:row";
if(name.equals("TD")) name="db:entry";
if(name.equals("TH")) name="db:thead";
if(name.equals("UL")) name="db:itemizedlist";
if(name.equals("DL")) name="db:itemizedlist";
if(name.equals("OL")) name="db:orderedlist";
if(name.equals("LI")) name="db:listitem";
if(name.equals("DD")) name="db:listitem";
if(name.equals("DT")) name="db:listitem";
if(name.equals("A")) name="db:link";
if(name.equals("LINK")) name="db:link";
if(name.equals("ULINK")) name="db:ulink";
if(name.equals("PRE")) name="db:programlisting";
if(name.equals("CODE")) name="db:programlisting";
if(name.equals("BR")) name="db:para";
return name;
}
public void writeInterface(ClassDoc c) throws IOException {
write("<interface name=\""+c.name()+"\">");
Tag[] tags=c.firstSentenceTags();
writeSummary(tags);
writeComment(c.commentText());
MethodDoc[] methods = c.methods();
for(int i=0; i<methods.length; i++) {
writeMethod(methods[i]);
}
ClassDoc parent=c.superclass();
if(parent!=null) {
writeElement("extends",parent.qualifiedName());
}
writeModifiers(c.modifiers());
write("</interface>");
}
public void addPackageContents(PackageDoc p) throws IOException {
write("<package name=\""+p.name()+"\">");
Tag[] tags=p.firstSentenceTags();
writeSummary(tags);
writeComment(p.commentText());
ClassDoc[] allClasses = p.allClasses();
for (int i=0; i < allClasses.length; i++ ) {
ClassDoc c = allClasses[i];
if(c.isInterface()) {
writeInterface(c);
}
else {
writeClass(c);
}
}
write("</package>");
}
private void writeSummary(Tag[] tags) throws IOException {
if(tags!=null && tags.length>0) {
StringBuffer sb=new StringBuffer();
for(int i=0; i < tags.length; i++) {
Tag t = tags[i];
String kind=t.kind();
if(kind.equals("Text")) {
sb.append(t.text()+" ");
}
else {
//System.out.println("tag="+t.getClass());
}
}
writeSummary(sb.toString());
}
}
private void writeSummary(String text) throws IOException {
writeHTMLText("summary",text);
}
}