001 /*
002 @license.text@
003 */
004 package biz.hammurapi.codegen;
005
006 import java.io.File;
007 import java.io.FileWriter;
008 import java.io.IOException;
009 import java.io.Writer;
010 import java.util.HashMap;
011 import java.util.Iterator;
012 import java.util.Map;
013 import java.util.Properties;
014 import java.util.StringTokenizer;
015
016 import org.apache.bcel.classfile.JavaClass;
017 import org.apache.bcel.generic.ClassGen;
018
019 /**
020 * Stores generated class files in a specified directory and creates HTML documenation.
021 * @author Pavel Vlasov
022 * @version $Revision: 1.5 $
023 */
024 public class HtmlDocConsumer implements DocumentingConsumer {
025 private File classDir;
026 private File docDir;
027 private Writer indexWriter;
028
029 final Map writerMap=new HashMap();
030
031 /**
032 * Construcotor
033 * @param classDir Output directory for generated classes. Mandatory.
034 * @param docDir Output directory for HTML documentation. Optional (can be null).
035 * @param indexName Name of index file.
036 * @throws GenerationException
037 */
038 public HtmlDocConsumer(File classDir, File docDir, String indexName) throws GenerationException {
039 if (classDir==null) {
040 throw new GenerationException("Class directory is null");
041 }
042 if (!classDir.isDirectory()) {
043 throw new GenerationException(classDir.getAbsolutePath()+" is not a directory");
044 }
045 if (docDir!=null && !docDir.isDirectory()) {
046 throw new GenerationException(docDir.getAbsolutePath()+" is not a directory");
047 }
048 this.classDir=classDir;
049 this.docDir=docDir;
050
051 if (docDir!=null) {
052 try {
053 indexWriter = new FileWriter(new File(docDir, indexName));
054 indexWriter.write("<HTML><BODY><H1>Generated classes</H1><TABLE border='1'><TR><TH>Class</TH><TH>Description</TH></TR>");
055 } catch (IOException e) {
056 throw new GenerationException("Cannot write index.html: "+e, e);
057 }
058 }
059 }
060
061 private GenerationListener listener;
062
063 public void consume(JavaClass javaClass) throws GenerationException {
064 try {
065 javaClass.dump(new File(classDir, javaClass.getClassName().replace('.', File.separatorChar)+".class"));
066 closeWriter(javaClass.getClassName());
067 } catch (IOException e) {
068 throw new GenerationException("Cannot save generated file: "+e, e);
069 }
070 }
071
072 private void closeWriter(String className) {
073 Writer writer = (Writer) writerMap.remove(className);
074 if (writer!=null) {
075 try {
076 writer.write("</BODY></HTML>");
077 writer.close();
078 } catch (IOException e) {
079 throw new DocumentingException("Cannot close documentation for class "+className+": "+e, e);
080 }
081 }
082 }
083
084 public GenerationListener getListener() {
085 if (listener==null && docDir!=null) {
086 listener = new GenerationListener() {
087
088 public void onClass(ClassGen classGen, String description) {
089 String className=classGen.getClassName();
090 try {
091 indexWriter.write("<TR><TD><a href='");
092 indexWriter.write(className);
093 indexWriter.write(".html'>");
094 indexWriter.write(className);
095 indexWriter.write("</a></TD><TD>");
096 writeEscaped(description, indexWriter);
097 indexWriter.write("</TD></TR>");
098
099 Writer w=new FileWriter(new File(docDir, className+".html"));
100 writerMap.put(className, w);
101 w.write("<HTML><BODY><H1>");
102 w.write(className);
103 w.write("</H1>");
104 writeEscaped(description, w);
105 w.write("<H2>Methods</H2><TABLE border='1'><TR><TH>Signature</TH><TH>Description</TH></TR>");
106 } catch (IOException e) {
107 throw new DocumentingException("Cannot document class "+className+": "+e, e);
108 }
109 }
110
111 /**
112 * @param description
113 * @param indexWriter
114 * @throws IOException
115 */
116 private void writeEscaped(String description, final Writer indexWriter) throws IOException {
117 StringTokenizer st=new StringTokenizer(description, "<>", true);
118 while (st.hasMoreTokens()) {
119 String t=st.nextToken();
120 if ("<".equals(t)) {
121 indexWriter.write("<");
122 } else if (">".equals(t)) {
123 indexWriter.write(">");
124 } else {
125 indexWriter.write(t);
126 }
127 }
128 }
129
130 public void onMethod(String className, String signature, String description, Properties attributes) {
131 Writer w=selectWriter(className);
132 try {
133 w.write("<TR><TD>");
134 w.write(signature);
135 w.write("</TD><TD>");
136 writeEscaped(description, w);
137 w.write("</TD>");
138 // Attributes ignored
139 } catch (IOException e) {
140 throw new DocumentingException("Cannot document method "+signature+" in class "+className+": "+e, e);
141 }
142 }
143
144 public void onField(String className, String signature, String description, Properties attributes) {
145 Writer w=selectWriter(className);
146 try {
147 w.write("<TR><TD>");
148 w.write(signature);
149 w.write("</TD><TD>");
150 writeEscaped(description, w);
151 w.write("</TD>");
152 // Attributes ignored
153 } catch (IOException e) {
154 throw new DocumentingException("Cannot document method "+signature+" in class "+className+": "+e, e);
155 }
156 }
157
158 private Writer selectWriter(String className) {
159 return (Writer) writerMap.get(className);
160 }
161 };
162 }
163 return listener;
164 }
165
166 /**
167 * Closes all files.
168 *
169 */
170 public void close() {
171 Iterator it=writerMap.keySet().iterator();
172 while (it.hasNext()) {
173 closeWriter((String) it.next());
174 }
175
176 if (indexWriter!=null) {
177 try {
178 indexWriter.write("</TABLE></BODY></HTML>");
179 indexWriter.close();
180 } catch (IOException e) {
181 throw new DocumentingException("Cannot close index file: "+e, e);
182 }
183 }
184 }
185
186 }