/** * Copyright 2010 ATG DUST Project * * Licensed 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 atg.test.util; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.nio.channels.FileChannel; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.log4j.Logger; import atg.applauncher.core.util.JarUtils; /** * A collection of utility methods for dealing with the filesystem. * @author robert * */ @SuppressWarnings("unchecked") public class FileUtil { private static Logger log = Logger.getLogger(FileUtil.class); private static boolean isDirty = false;; private static Map<String, Long> CONFIG_FILES_TIMESTAMPS, CONFIG_FILES_GLOBAL_FORCE; /** * * @param srcDir * @param dstDir * @param excludes * @throws IOException */ public static void copyDirectory(String srcDir, String dstDir, final List<String> excludes) throws IOException { if (new File(srcDir).exists()) { new File(dstDir).mkdirs(); for (final String file : new File(srcDir).list()) { final String source = srcDir + File.separator + file, destination = dstDir + File.separator + file; boolean dir = new File(source).isDirectory(); if (dir && !excludes.contains(file)) { copyDirectory(source, destination, excludes); } else { if (!excludes.contains(file)) { copyFile(source, destination); } } } } } /** * * @param src * @param dst * @throws IOException */ public static void copyFile(final String src, final String dst) throws IOException { final File srcFile = new File(src); final File dstFile = new File(dst); if (CONFIG_FILES_TIMESTAMPS != null && CONFIG_FILES_TIMESTAMPS.get(src) != null && CONFIG_FILES_TIMESTAMPS.get(src) == srcFile.lastModified() && dstFile.exists()) { if (log.isDebugEnabled()) { log.debug(String .format( "%s last modified hasn't changed and destination still exists", src)); } } else { if (log.isDebugEnabled()) { log.debug(String.format("Copy: src file %s ts %s : ", src, srcFile .lastModified())); log.debug(String.format("Copy: dest file %s ts %s : ", dst, dstFile .lastModified())); } final FileChannel srcChannel = new FileInputStream(src).getChannel(); final FileChannel dstChannel = new FileOutputStream(dst).getChannel(); dstChannel.transferFrom(srcChannel, 0, srcChannel.size()); dstChannel.close(); srcChannel.close(); } } /** * * @param componentName * The name of the nucleus component * @param configurationStagingLocation * A valid not <code>null</code> directory. * @param clazz * The class implementing the nucleus component * @param settings * An implementation of {@link Map} containing all needed properties * the component is depended on (eg key = username, value = test). * Can be <code>null</code> or empty. * @throws IOException */ public static void createPropertyFile(final String componentName, final File configurationStagingLocation, final Class<?> clazz, final Map<String, String> settings) throws IOException { configurationStagingLocation.mkdirs(); final File propertyFile = new File(configurationStagingLocation, componentName.replace("/", File.separator) + ".properties"); new File(propertyFile.getParent()).mkdirs(); propertyFile.createNewFile(); final BufferedWriter out = new BufferedWriter(new FileWriter(propertyFile)); try { if (clazz != null) { out.write("$class=" + clazz.getName()); out.newLine(); } if (settings != null) { for (final Iterator<Entry<String, String>> it = settings.entrySet() .iterator(); it.hasNext();) { final Entry<String, String> entry = it.next(); out.write(new StringBuilder(entry.getKey()).append("=").append( entry.getValue()).toString()); out.newLine(); } } } finally { out.close(); } } public static final String COULD_NOT_DELETE_TEMP_DIRECTORY = "Couldn't delete temp directory. "; public void searchAndReplace(final String originalValue, final String newValue, final File file) throws IOException { final File TMP_FILE = new File(System .getProperty("java.io.tmpdir") + File.separator + System.currentTimeMillis()+this+"-atg-dust-rh.tmp"); TMP_FILE.deleteOnExit(); if (CONFIG_FILES_GLOBAL_FORCE != null && CONFIG_FILES_GLOBAL_FORCE.get(file.getPath()) != null && CONFIG_FILES_GLOBAL_FORCE.get(file.getPath()) == file.lastModified() && file.exists()) { isDirty = false; if (log.isDebugEnabled()) { log.debug(String.format( "%s last modified hasn't changed and file still exists, no need for global scope force", file.getPath())); } } else { final BufferedWriter out = new BufferedWriter(new FileWriter(TMP_FILE)); final BufferedReader in = new BufferedReader(new FileReader(file)); String str; while ((str = in.readLine()) != null) { if (str.contains(originalValue)) { out.write(newValue); } else { out.write(str); out.newLine(); } } out.close(); in.close(); JarUtils.copy(TMP_FILE, file, true, false); CONFIG_FILES_GLOBAL_FORCE.put(file.getPath(), file.lastModified()); isDirty = true; } } /** * Deletes the given directory when the JVM exits. * This method does so by implementing a shutdown hook. * @param tmpDir */ public static void deleteDirectoryOnShutdown(final File tmpDir) { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { try { atg.core.io.FileUtils.deleteDir(tmpDir.getAbsolutePath()); } catch (IOException e) { log.error(FileUtil.COULD_NOT_DELETE_TEMP_DIRECTORY, e); } } }); } public static void serialize(final File file, final Object o) throws IOException { ObjectOutput out = null; try { out = new ObjectOutputStream(new FileOutputStream(file)); out.writeObject(o); } finally { if (out != null) { out.close(); } } } public static Map<String, Long> deserialize(final File file, final long serialTtl) { if (file.exists() && file.lastModified() < System.currentTimeMillis() - serialTtl) { if (log.isDebugEnabled()) { log.debug(String.format("Deleting previous serial %s " + "because it's older then %s m/s", file.getPath(), serialTtl)); } file.delete(); } Map<String, Long> o = null; try { if (file.exists()) { final ObjectInputStream in = new ObjectInputStream(new FileInputStream( file)); try { o = (Map<String, Long>) in.readObject(); } finally { if (in != null) { in.close(); } } } } catch (Exception e) { log.error("Error: ", e); } if (o == null) { o = new HashMap<String, Long>(); } return o; } public static void setConfigFilesTimestamps( Map<String, Long> config_files_timestamps) { CONFIG_FILES_TIMESTAMPS = config_files_timestamps; } public static void setConfigFilesGlobalForce( Map<String, Long> config_files_global_force) { CONFIG_FILES_GLOBAL_FORCE = config_files_global_force; } public static boolean isDirty() { return isDirty; } public static Map<String, Long> getConfigFilesTimestamps() { return CONFIG_FILES_GLOBAL_FORCE; } }