EMMA Coverage Report (generated Fri Jun 19 09:16:10 CEST 2009)
[all classes][org.ktc.rbutils.rb.generation]

COVERAGE SUMMARY FOR SOURCE FILE [FileGenerator.java]

nameclass, %method, %block, %line, %
FileGenerator.java100% (1/1)88%  (7/8)95%  (409/432)92%  (71/77)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class FileGenerator100% (1/1)88%  (7/8)95%  (409/432)92%  (71/77)
tab (int): String 0%   (0/1)0%   (0/19)0%   (0/4)
performGeneration (): void 100% (1/1)98%  (235/239)96%  (43/45)
<static initializer> 100% (1/1)100% (66/66)100% (1/1)
FileGenerator (File, File, File): void 100% (1/1)100% (59/59)100% (14/14)
escape (String): String 100% (1/1)100% (3/3)100% (1/1)
escapeKey (String): String 100% (1/1)100% (15/15)100% (5/5)
getJavaRbClassName (File): String 100% (1/1)100% (3/3)100% (1/1)
getJavaRbFile (File, File, File): File 100% (1/1)100% (28/28)100% (6/6)

1/*
2 * Copyright  2005-2006 The RbUtils Project
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *  Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 *
16 */
17 
18// $Id: FileGenerator.java,v 1.4 2008/07/01 07:43:45 moishi Exp $
19 
20package org.ktc.rbutils.rb.generation;
21 
22import java.io.BufferedWriter;
23import java.io.File;
24import java.io.FileNotFoundException;
25import java.io.FileOutputStream;
26import java.io.IOException;
27import java.io.OutputStreamWriter;
28import java.io.Writer;
29import java.text.MessageFormat;
30import java.util.ArrayList;
31import java.util.Collections;
32import java.util.Date;
33import java.util.Iterator;
34import java.util.List;
35import org.apache.commons.io.FilenameUtils;
36import org.apache.commons.lang.StringEscapeUtils;
37import org.apache.commons.lang.StringUtils;
38import org.ktc.rbutils.RbUtilsHelper;
39import org.ktc.rbutils.api.audit.AbstractFileProcessor;
40import org.ktc.rbutils.api.file.FileTools;
41import org.ktc.rbutils.api.file.ValidateFile;
42import org.ktc.rbutils.api.i18n.LocaleUtils;
43import org.ktc.rbutils.api.i18n.PropertiesRB;
44import org.ktc.rbutils.rb.check.messages;
45 
46/**
47 * Generates a Java RessourceBundle source class using a Properties file.
48 * <p>
49 * Package name resolution is proceeded using the relative path of the Properties file from a root
50 * directory.
51 * @see MainGenerator
52 * @since RbUtils 0.8.0
53 * @version $Revision: 1.4 $
54 * @author ktcguru
55 */
56public class FileGenerator extends AbstractFileProcessor {
57    // RFE Code - static parts of the code should be taken from a properties file
58 
59    /** String used for tabulation representation on code generation. */
60    protected static final String TAB = "    ";
61    /** Left padding for braces on code generation. */
62    private static final String BRACES_PAD_LEFT = " ";
63    /** Right padding for braces on code generation. */
64    private static final String BRACES_PAD_RIGHT = BRACES_PAD_LEFT;
65    /** Comma and 2 end of line characters. */
66    private static final String COMMA_DBLENDOFLINE = ";\n\n";
67 
68    // TODO Traduction - le message ne semble pas trop anglais
69    //TODO Traduction - ne pas mettre javatools en dur dans le code
70    /**
71     * String used for message formatting. This String represent the whole code of the generated
72     * class.
73     */
74    private static final String FORMAT = "/*\n" + " * DO NOT EDIT!\n"
75        + " * Automaticly generated with RbUtils " + RbUtilsHelper.getVersion() + " on "
76        + new Date()
77        + "\n * Original source:\n" + " * " + TAB + "{0}\n" + " *\n" + " * RbUtils Home Page: "
78        + RbUtilsHelper.getHomePage() + "\n */\n" + "{1}"
79        + "{5}"
80        + "public class {2} extends {6} '{'\n" + "{3}\n" + TAB
81        + "private static Object[][] contents = '{'\n" + "{4}\n" + TAB + "}" + COMMA_DBLENDOFLINE
82        + TAB + "protected Object[][] getContents() '{'\n " + TAB + TAB + "return contents;\n"
83        + TAB + "}\n}\n";
84 
85    /** Not compiled RB file. */
86    private PropertiesRB properties;
87    /** Full path to the properties file. */
88    private String propsFullFileName;
89    /** Package name of the generated ResourceBundle source class. */
90    private String packageName;
91    /** File of the generated ResourceBundle source class. */
92    private File javaRbFile;
93 
94    /**
95     * Instanciates a new <code>FileGenerator</code>.
96     * <p>
97     * <code>propsRootDir</code> and <code>genRootdir</code> must be directories that exist in
98     * the filesystem. <br>
99     * <code>propsFile</code> must be a file that exists in the filesystem.
100     * @param propsRootDir the root directory of the properties file used to resolve package name.
101     * @param propsFile the properties file used to generate the java file.
102     * @param genRootdir the target root directory where the java file will be put after package
103     *            name resolution and file generation.
104     * @throws org.apache.commons.lang.NullArgumentException if a parameter is <code>null</code>.
105     * @throws java.io.FileNotFoundException if a parameter is a <code>File</code> that does not
106     *             exist in the filesystem.
107     * @throws org.ktc.rbutils.api.file.NotDirectoryException if <code>propsRootDir</code> or
108     *             <code>genRootdir</code> is not a directory in the filesystem.
109     * @throws org.ktc.rbutils.api.file.NotFileException if <code>propsFile</code> is not a file
110     *             in the filesystem.
111     * @throws IOException if problems occured on Properties file load.
112     */
113    public FileGenerator(final File propsRootDir, final File propsFile, final File genRootdir)
114        throws IOException
115    {
116        // Validate arguments
117        ValidateFile.isDirectory(propsRootDir);
118        ValidateFile.isFile(propsFile);
119        ValidateFile.isDirectory(genRootdir);
120 
121        // Load RB file into PropertiesRB
122        properties = new PropertiesRB();
123        properties.load(propsFile);
124 
125        propsFullFileName = propsFile.getAbsolutePath();
126        packageName = FileTools.inferPackageName(propsRootDir, propsFile);
127        javaRbFile = getJavaRbFile(propsRootDir, propsFile, genRootdir);
128 
129        // AbstractFileAuditer field initialization
130        className = getJavaRbClassName(propsFile);
131        fileLocale = properties.getLocale();
132        fileName = FileTools.getStrippedFileName(propsRootDir, propsFile, true);
133 
134        // Set the resource class for messages
135        classResource = messages.class.getName();
136    }
137 
138    //TODO Code - performGeneration() should be refactored into several methods
139    /**
140     * Performs the generation of the Java File.
141     * <p>
142     * The contents of the properties file is used to create the data of the java file. Then, the
143     * java file is created in the filesystem.
144     */
145    protected void performGeneration() {
146        // Generation starts
147        fireProcessFileStarted();
148 
149        // Get package line if it is not the default package
150        String packageString = StringUtils.EMPTY;
151        // if (packageName != null && !StringUtils.EMPTY.equals(packageName)) {
152        // packageName is never null
153        if (!StringUtils.EMPTY.equals(packageName)) {
154//            packageString = "package " + packageName + ";\n\n";
155            packageString = "package " + packageName + COMMA_DBLENDOFLINE;
156        }
157 
158        // Is properties locale empty ?
159        final boolean isEmptyLocale = LocaleUtils.getEmptyLocale().equals(fileLocale);
160 
161        // Get the extended and the imported class
162        final String extendedClass;
163        final String importedClass;
164        if (isEmptyLocale) {
165            extendedClass = "ListResourceBundle";
166            importedClass = "java.util.ListResourceBundle";
167        }
168        else {
169            extendedClass = LocaleUtils.removeLocale(className);
170            importedClass = StringUtils.EMPTY;
171        }
172 
173        // TODO Code - should be done in the test above
174        // Get the import line
175        final String importLine;
176        if (StringUtils.EMPTY.equals(importedClass)) {
177            importLine = StringUtils.EMPTY;
178        }
179        else {
180//            importLine = "import " + importedClass + ";\n\n";
181            importLine = "import " + importedClass + COMMA_DBLENDOFLINE;
182        }
183 
184        // Get constant fields and data (keys and values)
185        final List sortedKeys = new ArrayList(properties.keySet());
186        Collections.sort(sortedKeys);
187 
188        final StringBuffer workingFields = new StringBuffer(200);
189        final StringBuffer workingData = new StringBuffer(200);
190        for (final Iterator iter = sortedKeys.iterator(); iter.hasNext();) {
191            final String key = (String) iter.next();
192            final String value = (String) properties.get(key);
193 
194            final String currentField = escapeKey(key);
195            // Append constant field if locale is empty
196            if (isEmptyLocale) {
197                workingFields.append(TAB + "public static final String " + currentField + " = \""
198                    + key + "\";\n");
199            }
200            // Append data
201            // Correction because of additionnal space after the BRACES_PAD_LEFT
202            // workingData.append(TAB + TAB + "{" + BRACES_PAD_RIGHT + currentField + ", \""
203            // + escape(value) + "\"" + BRACES_PAD_LEFT + " }, \n");
204            workingData.append(TAB + TAB + "{" + BRACES_PAD_RIGHT + currentField + ", \""
205                               + escape(value) + "\"" + BRACES_PAD_LEFT + "}, \n");
206        }
207 
208        // Get the fields String to be added to the file
209        final String fields;
210        if (workingFields.length() > 0) {
211            fields = workingFields.toString();
212        }
213        else {
214            fields = StringUtils.EMPTY;
215        }
216        // Suppress redondant coma on data and get the data String to be added to the file
217        // TODO Code - this is not necessary
218        // BUGS_2 Fix
219        // final String data = workingData.substring(0, workingData.lastIndexOf(","));
220        // if workingData is empty, throws exception (occurs for empty files). Test length as for
221        // workingFields
222        // final String data = workingData.substring(0, workingData.toString().lastIndexOf(','));
223        final String data;
224        if (workingData.length() > 0) {
225            data = workingData.substring(0, workingData.toString().lastIndexOf(','));
226        }
227        else {
228            data = StringUtils.EMPTY;
229        }
230 
231        // Create java resourcebundle file and its parent's directory
232        try {
233            javaRbFile.getParentFile().mkdirs();
234            javaRbFile.createNewFile();
235 
236            // Generate java resourcebundle file
237            // RFE encoding of the generated java file
238            final Writer oswriter = new OutputStreamWriter(new FileOutputStream(javaRbFile),
239                                                           "8859_1");
240            final Writer buffwriter = new BufferedWriter(oswriter);
241 
242            final MessageFormat messageformat = new MessageFormat(FORMAT);
243            final Object[] formatParams = new Object[] {propsFullFileName, packageString,
244                className, fields, data, importLine, extendedClass};
245            buffwriter.write(messageformat.format(formatParams));
246            buffwriter.flush();
247            buffwriter.close();
248        }
249        catch (final Exception e) {
250            fireException(e);
251        }
252 
253        // Generation ends
254        fireProcessFileEnded();
255    }
256 
257    // TODO Code - mettre la méthode private
258    /**
259     * Gets the name of the class generated from a Properties file.
260     * <p>
261     * This is the name of the file without extension.
262     * @param propsFile Properties file used for name resolution.
263     * @return the name of the class.
264     */
265    protected static String getJavaRbClassName(final File propsFile) {
266        return FileTools.getNameWithoutExtension(propsFile);
267    }
268 
269    // TODO Code - mettre la méthode private
270    /**
271     * Gets the <code>File</code> of the Java ResourceBundle according to the relative path of a
272     * properties file from its root directory.
273     * <p>
274     * The returned <code>File</code> will be in a parent directory of <code>genRootdir</code>.
275     * It will have the same relative path to <code>genRootdir</code> that <code>propsFile</code>
276     * to <code>propsRootDir</code>.
277     * @param propsRootDir the root directory of the properties file used to resolve relative path.
278     * @param propsFile the properties file used to resolve relative path.
279     * @param genRootdir the target root directory where the java file will be put.
280     * @return the java resourcebundle <code>File</code>.
281     * @throws FileNotFoundException if one of the argument represent a file that does not exist in
282     *             the filesystem.
283     */
284    protected static File getJavaRbFile(final File propsRootDir, final File propsFile,
285                                     final File genRootdir) throws FileNotFoundException
286    {
287        final String strippedProps = FileTools.getStrippedFileName(propsRootDir, propsFile);
288 
289        final StringBuffer fileName = new StringBuffer();
290        fileName.append(FilenameUtils.removeExtension(strippedProps));
291        fileName.append(FileTools.EXTENSION_SEPARATOR);
292        fileName.append(FileTools.JAVA_EXTENSION);
293 
294        return new File(genRootdir, fileName.toString());
295    }
296 
297    /**
298     * Escapes characters in order to get a <code>String</code> with only Unicode characters.
299     * @param theString the String to be escaped.
300     * @return the escaped String.
301     */
302    protected static String escape(final String theString) {
303        // documenter le cas de \ seul : ce caractère est supprimé, utiliser \\ ?
304        // NON car dans les fichiers de propriétés c'est un caractère d'échappement pour passer à la
305        // ligne suivante
306        return StringEscapeUtils.escapeJava(theString);
307        // TODO Design - unescape qu'il faudrait utiliser (cf sun et props2java) ??
308    }
309 
310    /**
311     * Escapes the dot character in the String argument into the underscore character.
312     * <p>
313     * This can be used on field generation in order to avoid compilation error (as the dot
314     * character is reserved for accessors).
315     * @param key the key to be escaped.
316     * @return the escape key; <code>null</code> if <code>key</code> is <code>null</code>.
317     */
318    protected static String escapeKey(final String key) {
319        String theString = null;
320        if (key != null) {
321            theString = key.toUpperCase(LocaleUtils.getEmptyLocale());
322            theString = theString.replace('.', '_');
323        }
324 
325        // voir si ok en traitant l'expression réguliere : \p{Punct}
326        // ie : tout les caractèes de ponctuation
327        // Attention : ds le jdk a partir de la 1.4!!!
328 
329        // RFE Generateur - empecher les caractères interdits pour les variables
330        return theString;
331    }
332 
333    /**
334     * Returns a String which contains the number of tabulations specified as argument.
335     * @param tabNumber number of tabulations
336     * @return the String which represents the number of tabulations; the empty String is tabNumber
337     *         is negative.
338     * @since RbUtils 0.9.2
339     */
340    protected static String tab(final int tabNumber) {
341        // TODO code - use this method
342        final StringBuffer tab = new StringBuffer(50);
343        for (int i = 0; i < tabNumber; i++) {
344            tab.append(TAB);
345        }
346        return tab.toString();
347    }
348}

[all classes][org.ktc.rbutils.rb.generation]
EMMA 2.0.5312 (C) Vladimir Roubtsov