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 }