EMMA Coverage Report (generated Mon Mar 20 21:34:30 PST 2006)
[all classes][com.moesol.generator]

COVERAGE SUMMARY FOR SOURCE FILE [ClassGenerator.java]

nameclass, %method, %block, %line, %
ClassGenerator.java100% (1/1)8%   (2/26)2%   (11/711)1%   (2/153)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ClassGenerator100% (1/1)8%   (2/26)2%   (11/711)1%   (2/153)
ClassForName (String): Class 0%   (0/1)0%   (0/13)0%   (0/3)
ClassGenerator (Class, boolean, TranslationContext): void 0%   (0/1)0%   (0/23)0%   (0/9)
cni_forward (Writer): void 0%   (0/1)0%   (0/14)0%   (0/4)
commitTempFile (): void 0%   (0/1)0%   (0/24)0%   (0/6)
computeFullPath (String): void 0%   (0/1)0%   (0/33)0%   (0/8)
computeTempPath (): void 0%   (0/1)0%   (0/15)0%   (0/2)
createClassOutput (String): Writer 0%   (0/1)0%   (0/17)0%   (0/4)
createClassProperties (): Properties 0%   (0/1)0%   (0/49)0%   (0/7)
createClassTemplate (): Template 0%   (0/1)0%   (0/50)0%   (0/7)
extendClassProperties (Properties): void 0%   (0/1)0%   (0/1)0%   (0/1)
findClassTemplate (String, String): String 0%   (0/1)0%   (0/106)0%   (0/8)
generate (String): void 0%   (0/1)0%   (0/66)0%   (0/20)
getClassDirectory (): String 0%   (0/1)0%   (0/5)0%   (0/1)
getClassDirectory (Class): String 0%   (0/1)0%   (0/26)0%   (0/5)
getLookupString (String, String, String): String 0%   (0/1)0%   (0/31)0%   (0/9)
getTransProperty (String): String 0%   (0/1)0%   (0/4)0%   (0/1)
getTranslationContext (): TranslationContext 0%   (0/1)0%   (0/2)0%   (0/1)
isGeneratedSame (): boolean 0%   (0/1)0%   (0/75)0%   (0/12)
makeClassDirectory (String): void 0%   (0/1)0%   (0/17)0%   (0/6)
merge (Writer): void 0%   (0/1)0%   (0/34)0%   (0/11)
merge_import (Writer): void 0%   (0/1)0%   (0/36)0%   (0/11)
shouldGenerate (): boolean 0%   (0/1)0%   (0/29)0%   (0/7)
visit (Writer): void 0%   (0/1)0%   (0/18)0%   (0/4)
visit (Writer, String): void 0%   (0/1)0%   (0/12)0%   (0/4)
<static initializer> 100% (1/1)100% (3/3)100% (1/1)
stripPackageName (String): String 100% (1/1)100% (8/8)100% (1/1)

1/*
2 * $Id: ClassGenerator.java,v 1.4 2004/06/16 19:23:57 hastings Exp $
3 *
4 * (c) Copyright, Moebius Solutions, Inc., 2004
5 *
6 *                       All Rights Reserved
7 *
8 * This material may be reproduced by or for the U. S. Government
9 * pursuant to the copyright license under the clause at
10 * DFARS 252.227-7014 (OCT 2001).
11 */
12 
13package com.moesol.generator;
14 
15import java.io.BufferedReader;
16import java.io.BufferedWriter;
17import java.io.File;
18import java.io.FileNotFoundException;
19import java.io.FileReader;
20import java.io.FileWriter;
21import java.io.IOException;
22import java.io.InputStream;
23import java.io.Reader;
24import java.io.Writer;
25import java.lang.reflect.Modifier;
26import java.util.Properties;
27 
28import com.moesol.generator.core.ApplyException;
29import com.moesol.generator.core.MergeException;
30import com.moesol.generator.core.MergeTagGroker;
31import com.moesol.generator.core.Template;
32import com.moesol.generator.core.VisitClass;
33 
34/**
35 * Abstract base class for code generators
36 */
37public abstract class ClassGenerator {
38    public ClassGenerator(Class clazz, boolean quiet, TranslationContext map) {
39        m_class = clazz;
40        m_quiet = quiet;
41        m_trans_ctx = map;
42    }
43 
44    /**
45     * Template method, default implementation returns true for
46     * public classes and interfaces.
47     * @return true if the generation should happen for this class.
48     */
49    protected boolean shouldGenerate() {
50        if (Modifier.isPublic(m_class.getModifiers())) {
51            return true;
52        }
53        if (Modifier.isProtected(m_class.getModifiers())) {
54            return getTranslationContext().genIncludesProtected();
55        }
56        if (Modifier.isPrivate(m_class.getModifiers())) {
57            return getTranslationContext().genIncludesPrivate();
58        }
59        return getTranslationContext().genIncludesPackage();
60    }
61    /** Template method */
62    protected void extendClassProperties(Properties p) throws ApplyException{ }
63    /** Template method */
64    protected abstract String getTemplateName() throws ApplyException;
65    /** Template method */
66    protected abstract ClassGeneratorVisitor createClassVisitor(Writer out) throws ApplyException;
67    /** Template method */
68    protected abstract String getFileSuffix();
69 
70    /** Helper */
71    public static Class ClassForName(String className) throws ApplyException {
72        try {
73            return Class.forName(className, false, className.getClass().getClassLoader());
74        } catch (Exception e) {
75            throw new ApplyException(e);
76        }
77    }
78    public void generate(String output_directory) throws ApplyException {
79        if (!shouldGenerate()) {
80            if (!m_quiet) {
81                System.out.print("skipping: ");
82                System.out.println(m_class.getName());
83            }
84            return;
85        }
86        Writer out = null;
87        try {
88            m_trans_ctx.setMapForClass(m_class);
89            out = createClassOutput(output_directory);
90            Properties p = createClassProperties();
91            extendClassProperties(p);
92            Template t = createClassTemplate();
93            t.apply(p, out);
94            out.close();
95            commitTempFile();
96        } catch (IOException e) {
97            throw new ApplyException(e);
98        } finally {
99            try { out.close(); } catch (Exception e) { }
100            try { m_trans_ctx.setMapForClass(null); } catch (Exception e) { }
101        }
102    }
103    
104    /**
105     * Create an output file suitable for return from createClassOutput.
106     * The output file created will be based on the fully qualified
107     * class name replacing each '.' with '/'.  For example
108     * java.lang.System will create
109     * <output_directory>/java.lang.System<suffix>.
110     *
111     * <p> If the <code>output_directory</code> does not exist then this
112     * method will throw a java.io.IOException.
113     *
114     * @param output_directory a string defining which directory to create
115     * the output file in.
116     * @returns file writer created 
117     * used to be createClassOuputFile
118     */
119    protected Writer createClassOutput(String output_directory)
120        throws IOException
121    {
122        computeFullPath(output_directory);
123        makeClassDirectory(output_directory);
124        computeTempPath();
125        return new BufferedWriter(new FileWriter(m_temp_path));
126    }
127    private void computeFullPath(String output_directory) {
128        String path = getClassDirectory();
129        String suffix = m_trans_ctx.getSuffix();
130        if (suffix == null) {
131            suffix = getFileSuffix();
132        }
133 
134        m_full_path = new File(output_directory, path + suffix);
135        if (!m_quiet) {
136            System.out.println(m_full_path);
137        }
138    }
139    /** depends on m_full_path */
140    private void computeTempPath() {
141        m_temp_path = new File(m_full_path + ".new");
142    }
143    private void makeClassDirectory(String output_directory) {
144        File dir_path = new File(output_directory);
145        if (!dir_path.exists()) {
146            return;
147        }
148 
149        File parent_path = m_full_path.getParentFile();
150        parent_path.mkdirs();
151    }
152    /**
153     * @return the filesystem path for m_class.
154     */
155    protected String getClassDirectory() {
156        return getClassDirectory(m_class);
157    }
158    /**
159     * @return the filesystem path for the <code>a_class</code>
160     * parameter.
161     */
162    protected String getClassDirectory(Class a_class) {
163        StringBuffer path = new StringBuffer(a_class.getName());
164        for (int i = 0; i < path.length(); i++) {
165            if ('.' == path.charAt(i)) {
166                path.setCharAt(i, '/');
167            }
168        }
169        return path.toString();
170    }
171    
172    /**
173     * Finds the translation template using a standard search.  The
174     * search starts with the prefix plus the full class name, then
175     * prefix plus the string "super" plus the full super class name.
176     * If neither of the above find a translation, then if the class
177     * is an interface search for prefix plus "interface", otherwise
178     * just search for prefix by itself.
179     *
180     * <P>For example, if the prefix is "java.class" and the class
181     * being generated is "com.moebiussolutions.test.Test" that
182     * extends from "com.moebiussolutions.test.TestSuper", then the
183     * search is: <BR>
184     * "java.class.com.moebiussolutions.test.Test",<BR>
185     * "java.class.super.com.moebiussolutions.test.TestSuper",<BR>
186     * "java.class"
187     */
188    protected String findClassTemplate(String prefix, String type) throws ApplyException {
189        String suffixes[] = {
190            m_class.getName(),
191            stripPackageName(m_class.getName()),
192            "super." + (m_class.getSuperclass() != null ? m_class.getSuperclass().getName() : "<none>"),
193            m_class.isInterface() ? "interface.*" : "*",
194        };
195        
196        String tmpl_name;
197        for (int i = 0; i < suffixes.length; i++) {
198            // System.out.println(prefix + suffixes[i]);
199            tmpl_name = getTransProperty(getLookupString(prefix, type, suffixes[i]));
200            if (tmpl_name != null) {
201                return tmpl_name;
202            }
203        }
204        // We are about to fail, dump all the searches
205        for (int i = 0; i < suffixes.length; i++) {
206            System.out.println(getLookupString(prefix, type, suffixes[i]));
207        }
208        throw new ApplyException("No " + prefix + "." + type + " template for " + m_class.getName());
209    }
210    private String getLookupString(String default_prefix, String type, String suffix) {
211        String prefix = m_trans_ctx.getPrefix();
212        if (prefix == null) {
213            prefix = default_prefix;
214        }
215        StringBuffer result = new StringBuffer(prefix);
216        result.append('.');
217        result.append(type);
218        result.append('.');
219        result.append(suffix);
220        return result.toString();
221    }
222    
223    /**
224     * Create an instance of Template that is configured to callback
225     * onto this.
226     */
227    protected Template createClassTemplate() throws ApplyException {
228        InputStream tmpl_strm = getTranslationContext().getTmplAsStream(getTemplateName());
229        if (tmpl_strm == null) {
230            throw new ApplyException("Template "
231                                     + getTemplateName() + " for "
232                                     + m_class.getName() + " not found");
233        }
234        Template t = new Template(tmpl_strm);
235        t.setObject(this);
236        t.setErrorPrefix(getTemplateName() + ": ");
237        return t;
238    }
239    
240    /** Helper */
241    protected static String getTransProperty(String key) throws ApplyException {
242        return m_trans_ctx.getProperty(key);
243    }
244    /* Helper */
245    public TranslationContext getTranslationContext() {
246        return m_trans_ctx;
247    }
248 
249    /** Impl */
250    private Properties createClassProperties() throws ApplyException {
251        Properties p = new Properties();
252        p.setProperty("automatic", "Automatically generated from " + getTemplateName());
253        p.setProperty("package", m_class.getPackage().getName());
254        p.setProperty("modifiers", Modifier.toString(m_class.getModifiers()));
255        p.setProperty("name", stripPackageName(m_class.getName()));
256        p.setProperty("jni_class", getClassDirectory());
257        return p;
258    }
259    /** Impl */
260    static String stripPackageName(String full_name) {
261        return full_name.substring(full_name.lastIndexOf('.') + 1);
262    }
263 
264    /**
265     * Called from class templates
266     */
267    public void cni_forward(Writer out) throws ApplyException {
268        JavaForwardVisitor v = new JavaForwardVisitor(out, getTranslationContext());
269        VisitClass.visitReflect(m_class, v);
270        v.visitDone();
271    }
272    
273    /**
274     * Called from class templates
275     */
276    public void visit(Writer out) throws ApplyException {
277        ClassGeneratorVisitor v = createClassVisitor(out);
278        v.setPassNumber(m_n_visit++);
279        v.visit(m_class);
280    }
281    public void visit(Writer out, String arg) throws ApplyException {
282        ClassGeneratorVisitor v = createClassVisitor(out);
283        v.setPassAppend(arg);
284        v.visit(m_class);
285    }
286 
287    /**
288     * Called from class templats
289     */
290    public void merge(Writer out) throws ApplyException {
291        try {
292            if (m_full_path.exists()) {
293                FileReader fr = new FileReader(m_full_path);
294                MergeTagGroker mtg = new MergeTagGroker(fr);
295                mtg.grokeTagsOnto(out);
296                fr.close();
297            }
298        }
299        catch (MergeException me) {
300            throw new ApplyException(me);
301        }
302        catch (IOException ioe) {
303            throw new ApplyException(ioe);
304        }
305    }
306    /**
307     * Called from class templats
308     */
309    public void merge_import(Writer out) throws ApplyException {
310        try {
311            if (m_full_path.exists()) {
312                FileReader fr = new FileReader(m_full_path);
313                MergeTagGroker mtg = new MergeTagGroker(
314                    "BEGIN_IMPORT", "END_IMPORT", fr);
315                mtg.grokeTagsOnto(out);
316                fr.close();
317            }
318        }
319        catch (MergeException me) {
320            throw new ApplyException(me);
321        }
322        catch (IOException ioe) {
323            throw new ApplyException(ioe);
324        }
325    }
326 
327    private void commitTempFile() throws IOException {
328        if (isGeneratedSame()) {
329            m_temp_path.delete();
330        } else {
331            m_full_path.delete();
332            if (!m_temp_path.renameTo(m_full_path)) {
333                throw new IOException("renameTo failed");
334            }
335        }
336    }
337    private boolean isGeneratedSame() throws IOException {
338        Reader org;
339        try {
340            org = new BufferedReader(new FileReader(m_full_path));
341        } catch (FileNotFoundException e) {
342            // orig did not exist
343            return false;
344        }
345        
346        Reader gen = new BufferedReader(new FileReader(m_temp_path));
347        try {
348            int c_gen;
349            int c_org;
350            while ((c_gen = gen.read()) != -1) {
351                c_org = org.read();
352                if (c_gen != c_org) {
353                    return false;
354                }
355            }
356            return -1 == org.read();
357        } finally {
358            try { org.close(); } catch (IOException e) { }
359            try { gen.close(); } catch (IOException e) { }
360        }
361    }
362 
363    Class m_class;
364    boolean m_quiet = false;
365    static TranslationContext m_trans_ctx = null;
366    File m_full_path = null;
367    File m_temp_path = null;
368    private int m_n_visit = 0;
369 
370}

[all classes][com.moesol.generator]
EMMA 2.0.5312 (C) Vladimir Roubtsov