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     */
017    package org.apache.xbean.spring.generator;
018    
019    import java.io.File;
020    import java.io.FileWriter;
021    import java.io.IOException;
022    import java.io.PrintWriter;
023    import java.util.Iterator;
024    import java.util.List;
025    
026    /**
027     * @author Dain Sundstrom
028     * @version $Id$
029     * @since 1.0
030     */
031    public 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.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    }