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.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("<spring:bean/>"); 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 }