1 /*** 2 * 3 */ 4 package atg.test.util; 5 6 import java.io.BufferedReader; 7 import java.io.BufferedWriter; 8 import java.io.File; 9 import java.io.FileInputStream; 10 import java.io.FileOutputStream; 11 import java.io.FileReader; 12 import java.io.FileWriter; 13 import java.io.IOException; 14 import java.io.ObjectInputStream; 15 import java.io.ObjectOutput; 16 import java.io.ObjectOutputStream; 17 import java.nio.channels.FileChannel; 18 import java.util.HashMap; 19 import java.util.Iterator; 20 import java.util.List; 21 import java.util.Map; 22 import java.util.Map.Entry; 23 24 import org.apache.log4j.Logger; 25 26 import atg.applauncher.core.util.JarUtils; 27 28 29 30 /*** 31 * A collection of utility methods for dealing with the filesystem. 32 * @author robert 33 * 34 */ 35 @SuppressWarnings("unchecked") 36 public class FileUtil { 37 38 private static Logger log = Logger.getLogger(FileUtil.class); 39 40 private static boolean isDirty = false;; 41 42 private static Map<String, Long> CONFIG_FILES_TIMESTAMPS, 43 CONFIG_FILES_GLOBAL_FORCE; 44 45 /*** 46 * 47 * @param srcDir 48 * @param dstDir 49 * @param excludes 50 * @throws IOException 51 */ 52 public static void copyDirectory(String srcDir, String dstDir, 53 final List<String> excludes) throws IOException { 54 if (new File(srcDir).exists()) { 55 new File(dstDir).mkdirs(); 56 for (final String file : new File(srcDir).list()) { 57 final String source = srcDir + File.separator + file, destination = dstDir 58 + File.separator + file; 59 boolean dir = new File(source).isDirectory(); 60 if (dir && !excludes.contains(file)) { 61 copyDirectory(source, destination, excludes); 62 } 63 else { 64 if (!excludes.contains(file)) { 65 copyFile(source, destination); 66 } 67 } 68 } 69 } 70 } 71 72 /*** 73 * 74 * @param src 75 * @param dst 76 * @throws IOException 77 */ 78 public static void copyFile(final String src, final String dst) 79 throws IOException { 80 final File srcFile = new File(src); 81 final File dstFile = new File(dst); 82 83 if (CONFIG_FILES_TIMESTAMPS != null 84 && CONFIG_FILES_TIMESTAMPS.get(src) != null 85 && CONFIG_FILES_TIMESTAMPS.get(src) == srcFile.lastModified() 86 && dstFile.exists()) { 87 if (log.isDebugEnabled()) { 88 log.debug(String 89 .format( 90 "%s last modified hasn't changed and destination still exists", 91 src)); 92 } 93 } 94 else { 95 if (log.isDebugEnabled()) { 96 log.debug(String.format("Copy: src file %s ts %s : ", src, srcFile 97 .lastModified())); 98 log.debug(String.format("Copy: dest file %s ts %s : ", dst, dstFile 99 .lastModified())); 100 } 101 102 final FileChannel srcChannel = new FileInputStream(src).getChannel(); 103 final FileChannel dstChannel = new FileOutputStream(dst).getChannel(); 104 dstChannel.transferFrom(srcChannel, 0, srcChannel.size()); 105 dstChannel.close(); 106 srcChannel.close(); 107 } 108 109 } 110 111 /*** 112 * 113 * @param componentName 114 * The name of the nucleus component 115 * @param configurationStagingLocation 116 * A valid not <code>null</code> directory. 117 * @param clazz 118 * The class implementing the nucleus component 119 * @param settings 120 * An implementation of {@link Map} containing all needed properties 121 * the component is depended on (eg key = username, value = test). 122 * Can be <code>null</code> or empty. 123 * @throws IOException 124 */ 125 public static void createPropertyFile(final String componentName, 126 final File configurationStagingLocation, final Class<?> clazz, 127 final Map<String, String> settings) throws IOException { 128 129 configurationStagingLocation.mkdirs(); 130 final File propertyFile = new File(configurationStagingLocation, 131 componentName.replace("/", File.separator) + ".properties"); 132 new File(propertyFile.getParent()).mkdirs(); 133 propertyFile.createNewFile(); 134 final BufferedWriter out = new BufferedWriter(new FileWriter(propertyFile)); 135 136 try { 137 if (clazz != null) { 138 out.write("$class=" + clazz.getName()); 139 out.newLine(); 140 } 141 if (settings != null) { 142 for (final Iterator<Entry<String, String>> it = settings.entrySet() 143 .iterator(); it.hasNext();) { 144 final Entry<String, String> entry = it.next(); 145 out.write(new StringBuilder(entry.getKey()).append("=").append( 146 entry.getValue()).toString()); 147 out.newLine(); 148 } 149 } 150 } 151 finally { 152 out.close(); 153 } 154 } 155 156 public static final String COULD_NOT_DELETE_TEMP_DIRECTORY = "Couldn't delete temp directory. "; 157 158 public void searchAndReplace(final String originalValue, 159 final String newValue, final File file) throws IOException { 160 161 final File TMP_FILE = new File(System 162 .getProperty("java.io.tmpdir") 163 + File.separator + System.currentTimeMillis()+this+"-atg-dust-rh.tmp"); 164 TMP_FILE.deleteOnExit(); 165 166 if (CONFIG_FILES_GLOBAL_FORCE != null 167 && CONFIG_FILES_GLOBAL_FORCE.get(file.getPath()) != null 168 && CONFIG_FILES_GLOBAL_FORCE.get(file.getPath()) == file.lastModified() 169 && file.exists()) { 170 isDirty = false; 171 if (log.isDebugEnabled()) { 172 log.debug(String.format( 173 "%s last modified hasn't changed and file still exists, no need for global scope force", 174 file.getPath())); 175 } 176 } 177 else { 178 final BufferedWriter out = new BufferedWriter(new FileWriter(TMP_FILE)); 179 final BufferedReader in = new BufferedReader(new FileReader(file)); 180 String str; 181 while ((str = in.readLine()) != null) { 182 if (str.contains(originalValue)) { 183 out.write(newValue); 184 } 185 else { 186 out.write(str); 187 out.newLine(); 188 } 189 } 190 out.close(); 191 in.close(); 192 JarUtils.copy(TMP_FILE, file, true, false); 193 CONFIG_FILES_GLOBAL_FORCE.put(file.getPath(), file.lastModified()); 194 isDirty = true; 195 } 196 197 } 198 199 /*** 200 * Deletes the given directory when the JVM exits. 201 * This method does so by implementing a shutdown hook. 202 * @param tmpDir 203 */ 204 public static void deleteDirectoryOnShutdown(final File tmpDir) { 205 Runtime.getRuntime().addShutdownHook(new Thread() { 206 public void run() { 207 try { 208 atg.core.io.FileUtils.deleteDir(tmpDir.getAbsolutePath()); 209 } catch (IOException e) { 210 log.error(FileUtil.COULD_NOT_DELETE_TEMP_DIRECTORY, e); 211 } 212 } 213 }); 214 } 215 216 public static void serialize(final File file, final Object o) 217 throws IOException { 218 219 ObjectOutput out = null; 220 try { 221 out = new ObjectOutputStream(new FileOutputStream(file)); 222 out.writeObject(o); 223 } 224 finally { 225 if (out != null) { 226 out.close(); 227 } 228 } 229 } 230 231 public static Map<String, Long> deserialize(final File file, 232 final long serialTtl) { 233 234 if (file.exists() 235 && file.lastModified() < System.currentTimeMillis() - serialTtl) { 236 if (log.isDebugEnabled()) { 237 log.debug(String.format("Deleting previous serial %s " 238 + "because it's older then %s m/s", file.getPath(), serialTtl)); 239 } 240 file.delete(); 241 } 242 243 Map<String, Long> o = null; 244 try { 245 if (file.exists()) { 246 final ObjectInputStream in = new ObjectInputStream(new FileInputStream( 247 file)); 248 try { 249 o = (Map<String, Long>) in.readObject(); 250 } 251 finally { 252 if (in != null) { 253 in.close(); 254 } 255 } 256 } 257 } 258 catch (Exception e) { 259 log.error("Error: ", e); 260 } 261 if (o == null) { 262 o = new HashMap<String, Long>(); 263 } 264 return o; 265 } 266 267 public static void setConfigFilesTimestamps( 268 Map<String, Long> config_files_timestamps) { 269 CONFIG_FILES_TIMESTAMPS = config_files_timestamps; 270 } 271 272 public static void setConfigFilesGlobalForce( 273 Map<String, Long> config_files_global_force) { 274 CONFIG_FILES_GLOBAL_FORCE = config_files_global_force; 275 } 276 277 public static boolean isDirty() { 278 return isDirty; 279 } 280 281 public static Map<String, Long> getConfigFilesTimestamps() { 282 return CONFIG_FILES_GLOBAL_FORCE; 283 } 284 285 }