/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ro.nextreports.designer.util; // // Created by IntelliJ IDEA. // User: mihai.panaitescu // Date: 16-Jun-2009 // Time: 10:05:40 import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; /** * MergeProperties provides functionality to merge two separate .properties * configuration files into one while preserving user comments. */ public class MergeProperties { /** source .properties file */ private File mergeFile; /** property override file */ private File importFile; /** file where final properties are saved */ private File destFile; /** * Configures the source input file to read the source properties. * * @param file A File object representing the source .properties file to read. */ public void setFile(final File file) { mergeFile = 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 setImportFile(final File file) { importFile = 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 setDestinationFile(final File file) { destFile = file; } /** * Method invoked by the ant framework to execute the action associated * with this task. * * @throws Exception if cannot read files */ public void execute() throws Exception { // validate provided parameters validate(); // read source .properties List<FileContents> newFile = new ArrayList<FileContents>(); List source = loadFile(mergeFile, newFile); List merge = loadFile(importFile, newFile); // iterate through source, and write to file with updated properties writeFile(newFile); } public void execute(Map<String, String> props) throws Exception { // validate provided parameters validate(); // read source .properties List<FileContents> newFile = new ArrayList<FileContents>(); List source = loadFile(mergeFile, newFile); List merge = loadProps(props, newFile); // iterate through source, and write to file with updated properties writeFile(newFile); } /** * Validate that the task parameters are valid. * * @throws Exception if parameters are invalid */ private void validate() throws Exception { if (importFile != null) { if (!importFile.canRead()) { final String message = "Unable to read from " + importFile + "."; throw new Exception(message); } } if (!mergeFile.canRead()) { final String message = "Unable to read from " + mergeFile + "."; throw new Exception(message); } if (!destFile.canWrite()) { try { destFile.createNewFile(); } catch (IOException e) { throw new Exception("Unable to write to " + 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. * @param fileContents list of file contents * @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 Exception An exception can occur if the version file is corrupted or the * process is in someway interrupted */ private List loadFile(File file, List<FileContents> fileContents) throws Exception { try { BufferedReader in = new BufferedReader(new FileReader(file)); String curLine; String property; String comment = ""; try { while ((curLine = in.readLine()) != null) { curLine = curLine.trim(); if (curLine.startsWith("#")) { comment += curLine + "\r\n"; } else if (curLine.indexOf("=") > 0) { while (curLine.endsWith("\\")) { curLine += "\r\n" + in.readLine().trim(); } FileContents fc = new FileContents(); fc.name = curLine.substring(0, curLine.indexOf("=")); fc.value = curLine; fc.comment = comment; comment = ""; if (fileContents.contains(fc)) { FileContents existing = getExistingElement(fileContents, fc.name); if (existing != null) { existing.value = fc.value; } else { fileContents.add(fc); } } else { fileContents.add(fc); } } } } catch (Exception e) { throw new Exception("Could not read file:" + file, e); } finally { in.close(); } } catch (IOException IOe) { // had an exception trying to open the file throw new Exception("Could not read file:" + file, IOe); } return fileContents; } private List loadProps(Map<String, String> props, List<FileContents> fileContents) throws Exception { String curLine; String property; String comment = ""; for (String key : props.keySet()) { FileContents fc = new FileContents(); fc.name = key; fc.value = key + "=" + props.get(key); fc.comment = comment; if (fileContents.contains(fc)) { FileContents existing = getExistingElement(fileContents, fc.name); if (existing != null) { existing.value = fc.value; } else { fileContents.add(fc); } } else { fileContents.add(fc); } } return fileContents; } private FileContents getExistingElement(List<FileContents> list, String name) { for (FileContents fc : list) { if (fc.getName().equals(name)) { return fc; } } return null; } /** * Writes the merged properties to a single file while preserving any * comments. * * @param fileContents list of file contents * @throws Exception if the destination file can't be created */ private void writeFile(List fileContents) throws Exception { Iterator iterate = fileContents.iterator(); try { FileOutputStream out = new FileOutputStream(destFile); PrintStream p = new PrintStream(out); try { // write original file with updated values while (iterate.hasNext()) { FileContents fc = (FileContents) iterate.next(); if (fc.comment != null && !fc.comment.equals("")) { p.println(); p.print(fc.comment); } p.println(fc.value); } } catch (Exception e) { throw new Exception("Could not write file: " + destFile, e); } finally { out.close(); } } catch (IOException IOe) { throw new Exception("Could not write file: " + destFile, IOe); } } protected class FileContents { public String name; public String comment; public int order; public String value; public String getName() { return name; } public boolean equals(Object obj) { if (obj instanceof FileContents) { FileContents fc = (FileContents) obj; if (fc.getName().equals(name)) { return true; } } return false; } } }