Ant task to merge properties files
January 08, 2010 03:53:37 Last update: January 08, 2010 03:54:56
This is an Ant custom task to merge Properties files I lifted from http://marc.info/?l=ant-user&m=106442688632164&w=2, with some minor bug fixes.
Example usage:
Implementation:
Example usage:
<taskdef name="mergeProperty" classname="ant.task.addon.MergeProperties"/> <mergeProperty baseFile="${src.config}/config.properties" overrideFile="${src.config}/${target.env}.properties" destFile="${dest.config}/config.properties"/>
Implementation:
package ant.task.addon; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.InputStream; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Properties; import org.apache.tools.ant.Task; import org.apache.tools.ant.BuildException; /** * MergeProperties provides functionality to merge two separate .properties * configuration files into one while preserving user comments. */ public class MergeProperties extends Task { /** determines source .properties file */ private File baseFile; /** determines property override file */ private File overrideFile; /** determines where final properties are saved */ private File destFile; /** stores a collection of properties added to merged file */ private HashMap map = new HashMap(); /** * Configures the source input file to read the source properties. * * @param file * A File object representing the source .properties file to read. */ public void setBaseFile(final File file) { baseFile = file; } /** * Configures the destination file to overwrite the properties provided * in the source file. * * @param file * A File object representing the destination file to merge the * combined properties into. */ public void setOverrideFile(final File file) { overrideFile = file; } /** * Configures the destination file to write the combined properties. * * @param file * A File object representing the destination file to merge the * combined properties into. */ public void setDestFile(final File file) { destFile = file; } /** * Method invoked by the ant framework to execute the action associated * with this task. * * @throws BuildException * Any fatal exception that occurs while processing the task */ public void execute() throws BuildException { // validate provided parameters validate(); // read source .properties List source = loadFile(baseFile); List merge = loadFile(overrideFile); // get merged property collection Properties props = loadProperties(source, merge); // iterate through source, and write to file with updated properties writeFile(source, merge, props); } /** * Validate that the task parameters are valid. * * @throws BuildException * if parameters are invalid */ private void validate() throws BuildException { map.clear(); if (!overrideFile.canRead()) { final String message = "Unable to read from " + overrideFile + "."; throw new BuildException(message); } if (!baseFile.canRead()) { final String message = "Unable to read from " + baseFile + "."; throw new BuildException(message); } if (!destFile.exists()) { try { destFile.createNewFile(); } catch (IOException e) { throw new BuildException("Could not create " + destFile + "."); } } } /** * Reads the contents of the selected file and returns them in a List that * contains String objects that represent each line of the file in the * order that they were read. * * @param file * The file to load the contents into a List. * @return a List of the contents of the file where each line of the file * is stored as an individual String object in the List in the same * physical order it appears in the file. * @throws BuildException * An exception can occur if the version file is corrupted or the * process is in someway interrupted */ private List loadFile(File file) throws BuildException { List list = new ArrayList(); try { BufferedReader in = new BufferedReader(new FileReader(file)); String record; try { while ((record = in.readLine()) != null) { record = record.trim(); list.add(record); } } catch (Exception e) { throw new BuildException("Could not read file:" + file, e); } finally { in.close(); } } catch (IOException IOe) { // had an exception trying to open the file throw new BuildException("Could not read file:" + file, IOe); } return list; } /** * Loads the properties from the source .properties file specified and * over-rides them with those found in the merge file. * * @return a collection of merged properties from both specified * .properties files * @throws BuildException * If either of the .properties files cannot be loaded */ private Properties loadProperties(List source, List merge) throws BuildException { Properties props = new Properties(); Properties newProps = new Properties(); for (Iterator i = source.iterator(); i.hasNext(); ) { String line = (String) i.next(); processLine(props, line); } for (Iterator i = merge.iterator(); i.hasNext(); ) { String line = (String) i.next(); processLine(newProps, line); } for (Enumeration e = newProps.propertyNames(); e.hasMoreElements(); ) { String key = (String) e.nextElement(); props.setProperty(key, newProps.getProperty(key)); } return props; } /** * Writes the merged properties to a single file while preserving any * comments. * * @param source * A list containing the contents of the original source file * @param merge * A list containing the contents of the file to merge * @param props * A collection of properties with their values merged from both files * @throws BuildException * if the destination file can't be created */ private void writeFile(List source, List merge, Properties props) throws BuildException { Iterator iterate = source.iterator(); try { FileOutputStream out = new FileOutputStream(destFile); PrintStream p = new PrintStream(out); try { // write original file with updated values while (iterate.hasNext()) { String line = (String) iterate.next(); p.println(updateProperty(line, props)); } // add new properties to file Properties newProps = getNewProperties(props); writeNewProperties(merge, newProps, p); } catch (Exception e) { throw new BuildException("Could not write file: " + destFile, e); } finally { out.close(); } } catch (IOException IOe) { throw new BuildException("Could not write file: " + destFile, IOe); } } /** * Determines whether the specified line has a corresponding property in * the props collection and updates the value accordingly. * * @param line * The original content of the line * @param props * A collection of merged property values * @return an updated string matching the correct property value */ private String updateProperty(String line, Properties props) { if (!line.startsWith("#")) { if (line.indexOf("=") > 0) { int index = line.indexOf("="); String propName = line.substring(0, index).trim(); String propValue = props.getProperty(propName); if (propValue != null) { map.put(propName, propValue); return (propName + "=" + propValue); } } } return line; } /** * Returns a collection of properties that have not yet been added to the * destination .properties file. * * @param allProps * A collection of all properties found between the source and merge * property files. * @return a collection of properties that have not yet been added to the * destination .properties files including their final values */ private Properties getNewProperties(Properties allProps) { Properties newProps = new Properties(); Enumeration enumProps = allProps.propertyNames(); while (enumProps.hasMoreElements()) { String key = (String) enumProps.nextElement(); if (!map.containsKey(key)) { newProps.setProperty(key, allProps.getProperty(key)); } } return newProps; } /** * Writes the elements from the list that have not yet been written. * * @param list * A list containing each line of the file to merge * @param props * A collection of the new properties to add to the file * @param p * A stream to print to the destination .properties file * @throws IOException * can occur if an exception occurs while writing to the file */ private void writeNewProperties(List list, Properties props, PrintStream p) throws IOException { List tempList = new ArrayList(); for (Iterator i = list.iterator(); i.hasNext(); ) { String line = (String) i.next(); if (line.startsWith("#")) { tempList.add(line); } else { int idx = line.indexOf("="); if (idx > 0) { String newKey = line.substring(0, idx).trim(); String newValue = props.getProperty(newKey); if (newValue != null) { Iterator iterateTemp = tempList.iterator(); while (iterateTemp.hasNext()) { p.println((String) iterateTemp.next()); } p.println(newKey + "=" + newValue); } tempList.clear(); } else { tempList.add(line); } } } } private void processLine(Properties props, String line) { if (! line.startsWith("#")) { int idx = line.indexOf("="); if (idx > 0) { String key = line.substring(0, idx).trim(); String value = line.substring(idx + 1).trim(); props.setProperty(key, value); } } } }
1 comment 