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    }