001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.xbean.spring.generator;
018
019import java.io.File;
020import java.io.FileWriter;
021import java.io.IOException;
022import java.io.PrintWriter;
023import java.util.Iterator;
024import java.util.List;
025
026/**
027 * @author Dain Sundstrom
028 * @version $Id$
029 * @since 1.0
030 */
031public class DocumentationGenerator implements GeneratorPlugin {
032    private final File destFile;
033    private LogFacade log;
034
035    public DocumentationGenerator(File destFile) {
036        this.destFile = destFile;
037    }
038
039    public void generate(NamespaceMapping namespaceMapping) throws IOException {
040        String namespace = namespaceMapping.getNamespace();
041
042        // TODO can only handle 1 schema document so far...
043        File file = new File(destFile.getParentFile(), destFile.getName() + ".html");
044        log.log("Generating HTML documentation file: " + file + " for namespace: " + namespace);
045        PrintWriter out = new PrintWriter(new FileWriter(file));
046        try {
047            generateDocumentation(out, namespaceMapping);
048        } finally {
049            out.close();
050        }
051    }
052
053    private void generateDocumentation(PrintWriter out, NamespaceMapping namespaceMapping) {
054        String namespace = namespaceMapping.getNamespace();
055
056        out.println("<!-- NOTE: this file is autogenerated by Apache XBean -->");
057        out.println("<html>");
058        out.println("<head>");
059        out.println("<title>Schema for namespace: " + namespace + "</title>");
060        out.println("<link rel='stylesheet' href='style.css' type='text/css'>");
061        out.println("<link rel='stylesheet' href='http://activemq.org/style.css' type='text/css'>");
062        out.println("<link rel='stylesheet' href='http://activemq.org/style-xb.css' type='text/css'>");
063        out.println("</head>");
064        out.println();
065        out.println("<body>");
066        out.println();
067
068        generateRootElement(out, namespaceMapping);
069
070        generateElementsSummary(out, namespaceMapping);
071        out.println();
072        out.println();
073
074        generateElementsDetail(out, namespaceMapping);
075
076        out.println();
077        out.println("</body>");
078        out.println("</html>");
079    }
080
081    private void generateRootElement(PrintWriter out, NamespaceMapping namespaceMapping) {
082        ElementMapping rootElement = namespaceMapping.getRootElement();
083        if (rootElement != null) {
084            out.println("<h1>Root Element</h1>");
085            out.println("<table>");
086            out.println("  <tr><th>Element</th><th>Description</th><th>Class</th>");
087            generateElementSummary(out, rootElement);
088            out.println("</table>");
089            out.println();
090        }
091    }
092
093    private void generateElementsSummary(PrintWriter out, NamespaceMapping namespaceMapping) {
094        out.println("<h1>Element Summary</h1>");
095        out.println("<table>");
096        out.println("  <tr><th>Element</th><th>Description</th><th>Class</th>");
097        for (Iterator iter = namespaceMapping.getElements().iterator(); iter.hasNext();) {
098            ElementMapping element = (ElementMapping) iter.next();
099            generateElementSummary(out, element);
100        }
101        out.println("</table>");
102    }
103
104    private void generateElementSummary(PrintWriter out, ElementMapping element) {
105        out.println("  <tr>" +
106                "<td><a href='#" + element.getElementName() + "'>" + element.getElementName() + "</a></td>" +
107                "<td>" + element.getDescription() + "</td>" +
108                "<td>" + element.getClassName() + "</td></tr>");
109    }
110
111    private void generateElementsDetail(PrintWriter out, NamespaceMapping namespaceMapping) {
112        out.println("<h1>Element Detail</h1>");
113        for (Iterator iter = namespaceMapping.getElements().iterator(); iter.hasNext();) {
114            ElementMapping element = (ElementMapping) iter.next();
115            generateHtmlElementDetail(out, namespaceMapping, element);
116        }
117    }
118
119    private void generateHtmlElementDetail(PrintWriter out, NamespaceMapping namespaceMapping, ElementMapping element) {
120        out.println("<h2>Element: <a name='" + element.getElementName() + "'>" + element.getElementName() + "</a></h2>");
121
122        boolean hasAttributes = false;
123        boolean hasElements = false;
124        for (Iterator iterator = element.getAttributes().iterator(); iterator.hasNext() && (!hasAttributes || !hasElements);) {
125            AttributeMapping attributeMapping = (AttributeMapping) iterator.next();
126            Type type = attributeMapping.getType();
127            if (namespaceMapping.isSimpleType(type)) {
128                hasAttributes = true;
129            } else {
130                hasElements = true;
131            }
132        }
133
134        if (hasAttributes) {
135            out.println("<table>");
136            out.println("  <tr><th>Attribute</th><th>Type</th><th>Description</th>");
137            for (Iterator iterator = element.getAttributes().iterator(); iterator.hasNext();) {
138                AttributeMapping attributeMapping = (AttributeMapping) iterator.next();
139                Type type = attributeMapping.getPropertyEditor() != null ?  Type.newSimpleType(String.class.getName()) : attributeMapping.getType();
140                if (namespaceMapping.isSimpleType(type)) {
141                    out.println("  <tr><td>" + attributeMapping.getAttributeName() + "</td><td>" + Utils.getXsdType(type)
142                            + "</td><td>" + attributeMapping.getDescription() + "</td></tr>");
143                }
144
145            }
146            out.println("</table>");
147        }
148
149        if (hasElements) {
150            out.println("<table>");
151            out.println("  <tr><th>Element</th><th>Type</th><th>Description</th>");
152            for (Iterator iterator = element.getAttributes().iterator(); iterator.hasNext();) {
153                AttributeMapping attributeMapping = (AttributeMapping) iterator.next();
154                Type type = attributeMapping.getType();
155                if (!namespaceMapping.isSimpleType(type)) {
156                    out.print("  <tr><td>" + attributeMapping.getAttributeName() + "</td><td>");
157                    printComplexPropertyTypeDocumentation(out, namespaceMapping, type);
158                    out.println("</td><td>" + attributeMapping.getDescription() + "</td></tr>");
159                }
160            }
161            out.println("</table>");
162        }
163    }
164
165    private void printComplexPropertyTypeDocumentation(PrintWriter out, NamespaceMapping namespaceMapping, Type type) {
166        if (type.isCollection()) {
167            out.print("(");
168        }
169
170        List types;
171        if (type.isCollection()) {
172            types = Utils.findImplementationsOf(namespaceMapping, type.getNestedType());
173        } else {
174            types = Utils.findImplementationsOf(namespaceMapping, type);
175        }
176
177        for (Iterator iterator = types.iterator(); iterator.hasNext();) {
178            ElementMapping element = (ElementMapping) iterator.next();
179            out.print("<a href='#" + element.getElementName() + "'>" + element.getElementName() + "</a>");
180            if (iterator.hasNext()) {
181                out.print(" | ");
182            }
183        }
184        if (types.size() == 0) {
185            out.print("&lt;spring:bean/&gt;");
186        }
187
188        if (type.isCollection()) {
189            out.print(")*");
190        }
191    }
192
193    public LogFacade getLog() {
194        return log;
195    }
196
197    public void setLog(LogFacade log) {
198        this.log = log;
199    }
200}