/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.server.core.plugin; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.persistence.NoResultException; import javax.persistence.Query; import javax.transaction.TransactionManager; import org.testng.annotations.Test; import org.rhq.core.clientapi.descriptor.AgentPluginDescriptorUtil; import org.rhq.core.clientapi.descriptor.plugin.PluginDescriptor; import org.rhq.core.domain.plugin.Plugin; import org.rhq.core.util.MessageDigestGenerator; import org.rhq.core.util.stream.StreamUtil; import org.rhq.enterprise.server.auth.SubjectManagerLocal; import org.rhq.enterprise.server.resource.metadata.PluginManagerLocal; import org.rhq.enterprise.server.test.AbstractEJB3Test; import org.rhq.enterprise.server.util.LookupUtil; //make sure we run this after the plugins.metadata tests are done so that //the db contents don't interfere //@Test(dependsOnGroups = "plugin.metadata") public class DatabaseAndFilePluginDeploymentTest extends AbstractEJB3Test { private static final String PLUGIN_NAME = "DeployTest"; // as defined in our test descriptors private static final String DESCRIPTORS_LOCATION = "test/deployment/"; private static final String TEST_DIR = tmpdirRoot + "/" + DatabaseAndFilePluginDeploymentTest.class.getName() + "/"; private static final String JARS_LOCATION = TEST_DIR + "jars"; private static final String DEPLOY_LOCATION = TEST_DIR + "deploy"; private static final String TESTPLUGIN_1_0_FEB = "1.0-feb"; private static final String TESTPLUGIN_1_0_JUN = "1.0-june"; private static final String TESTPLUGIN_1_1_FEB = "1.1-feb"; private static final String TESTPLUGIN_1_1_JUN = "1.1-june"; private static final String TESTPLUGIN_1_0_FEB2 = "1.0-feb-2"; private final Map<String, File> testPluginFiles = new HashMap<String, File>(); private final Map<String, Plugin> testPlugins = new HashMap<String, Plugin>(); private final Map<String, Date> testTimestamps = new HashMap<String, Date>(); private final Map<String, PluginDescriptor> testPluginDescriptors = new HashMap<String, PluginDescriptor>(); private PluginManagerLocal pluginMgr; private SubjectManagerLocal subjectManager; // Here is a matrix of scenarios we are going to test. // "Winning Plugin" means the plugin considered the most up-to-date (not obsolete). // "Reason" == "exists" means the winning plugin was the only one that existed // "Reason" == "version" means the winning plugin had the newer version // "Reason" == "time" means the winning plugin had the newer/later timestamp // ========================================================================== // | Plugins Deployed In: | Winning | Reason | Side // # | Filesystem | Database | Plugin | | Effects // ========================================================================== // 0 | 1.0-feb | 1.0-feb | N/A | N/A | steady state - all up-to-date // 1 | 1.0-feb | N/A | Filesystem | exists | DB row created // 2 | N/A | 1.0-feb | Database | exists | file created // 3 | 1.0-jun | 1.0-feb | Filesystem | time | DB row updated // 4 | 1.0-feb | 1.0-jun | Database | time | file 1.0-feb deleted, file 1.0-jun created // 5 | 1.1-jun | 1.0-jun | Filesystem | version | DB row updated // 6 | 1.0-jun | 1.1-jun | Database | version | file 1.0-jun deleted, file 1.1-jun created // 7 | 1.1-feb | 1.0-jun | Filesystem | version | DB row updated // 8 | 1.0-jun | 1.1-feb | Database | version | file 1.0-jun deleted, file 1.1-feb created // ------ the tests below have two plugins deployed on the file system ------ // 9 | 1.0-feb | 1.0-feb | Filesystem | time | file 1.0-feb deleted, // | 1.0-jun | | | | DB row updated // -------------------------------------------------------------------------- // 10| 1.0-feb | 1.0-jun | None | N/A | file 1.0-feb deleted, // | 1.0-jun | | | | // -------------------------------------------------------------------------- // 11| 1.0-feb | 1.1-feb | Database | version | files 1.0-feb/jun deleted, // | 1.0-jun | | | | file 1.1-feb created // -------------------------------------------------------------------------- // 12| 1.0-feb | 1.0-feb | Filesystem | version | file 1.0-feb deleted, // | 1.1-jun | | | | DB row updated // -------------------------------------------------------------------------- // 13| 1.0-feb | 1.1-feb | Filesystem | time | file 1.0-feb deleted, // | 1.1-jun | | | | DB row updated // -------------------------------------------------------------------------- // 14| 1.0-feb | 1.0-feb | None | N/A | all files are the same but // | 1.0-feb-2 | | | | one of the files gets deleted // -------------------------------------------------------------------------- // README // Arquillian (1.0.2) does not honor Testng's lifecycle, Before/AfterClass are invoked on // every test. Since beforeClass sets instance variables, we need to now call it for // every test, so we call it from beforeMethod(). We use a stand-in test to simulate AfterClass, // using priorities to make it run last. Testng (I believe) applies priority after dependencies, so it // is important that afterClassStandIn() have a dependency such that it runs in the last test-set. //@BeforeClass private void beforeClass() throws Exception { Calendar cal = Calendar.getInstance(); cal.set(2009, Calendar.FEBRUARY, 1, 1, 0, 0); cal.set(Calendar.MILLISECOND, 0); Date febDate = cal.getTime(); cal.set(2009, Calendar.JUNE, 1, 1, 0, 0); cal.set(Calendar.MILLISECOND, 0); Date juneDate = cal.getTime(); testTimestamps.put(TESTPLUGIN_1_0_FEB, febDate); testTimestamps.put(TESTPLUGIN_1_0_JUN, juneDate); testTimestamps.put(TESTPLUGIN_1_1_FEB, febDate); testTimestamps.put(TESTPLUGIN_1_1_JUN, juneDate); testTimestamps.put(TESTPLUGIN_1_0_FEB2, febDate); pluginMgr = LookupUtil.getPluginManager(); subjectManager = LookupUtil.getSubjectManager(); File deployDir = new File(DEPLOY_LOCATION); deployDir.mkdirs(); assert deployDir.isDirectory(); File jarsDir = new File(JARS_LOCATION); jarsDir.mkdirs(); assert jarsDir.isDirectory(); testPluginFiles.put(TESTPLUGIN_1_0_FEB, new File(jarsDir, TESTPLUGIN_1_0_FEB + ".jar")); testPluginFiles.put(TESTPLUGIN_1_0_JUN, new File(jarsDir, TESTPLUGIN_1_0_JUN + ".jar")); testPluginFiles.put(TESTPLUGIN_1_1_FEB, new File(jarsDir, TESTPLUGIN_1_1_FEB + ".jar")); testPluginFiles.put(TESTPLUGIN_1_1_JUN, new File(jarsDir, TESTPLUGIN_1_1_JUN + ".jar")); testPluginFiles.put(TESTPLUGIN_1_0_FEB2, new File(jarsDir, TESTPLUGIN_1_0_FEB2 + ".jar")); for (Map.Entry<String, File> entry : testPluginFiles.entrySet()) { String descriptor = DESCRIPTORS_LOCATION + entry.getKey() + ".xml"; File file = entry.getValue(); buildPluginJar(descriptor, file); assert file.exists(); PluginDescriptor pluginDescriptor = AgentPluginDescriptorUtil.loadPluginDescriptorFromUrl(file.toURI() .toURL()); testPluginDescriptors.put(entry.getKey(), pluginDescriptor); Plugin pluginPojo = new Plugin(PLUGIN_NAME, file.getName()); pluginPojo.setVersion(pluginDescriptor.getVersion()); pluginPojo.setMd5(MessageDigestGenerator.getDigestString(file)); pluginPojo.setMtime(testTimestamps.get(entry.getKey()).getTime()); testPlugins.put(entry.getKey(), pluginPojo); } return; } //@AfterClass(alwaysRun = true) @Test(priority = 10, alwaysRun = true) public void afterClassStandIn() throws Exception { File jarsDir = new File(JARS_LOCATION); jarsDir.delete(); File deployDir = new File(DEPLOY_LOCATION); emptyDirectory(deployDir); deployDir.delete(); return; } @Override protected void beforeMethod() throws Exception { beforeClass(); afterMethod(); // we clean up before and after, just to be sure we're clean File deployDir = new File(DEPLOY_LOCATION); deployDir.mkdirs(); assert deployDir.isDirectory(); File jarsDir = new File(JARS_LOCATION); jarsDir.mkdirs(); assert jarsDir.isDirectory(); for (Map.Entry<String, File> entry : testPluginFiles.entrySet()) { String descriptor = DESCRIPTORS_LOCATION + entry.getKey() + ".xml"; File file = entry.getValue(); buildPluginJar(descriptor, file); assert file.exists(); PluginDescriptor pluginDescriptor = AgentPluginDescriptorUtil.loadPluginDescriptorFromUrl(file.toURI() .toURL()); testPluginDescriptors.put(entry.getKey(), pluginDescriptor); Plugin pluginPojo = new Plugin(PLUGIN_NAME, file.getName()); pluginPojo.setVersion(pluginDescriptor.getVersion()); pluginPojo.setMd5(MessageDigestGenerator.getDigestString(file)); pluginPojo.setMtime(testTimestamps.get(entry.getKey()).getTime()); testPlugins.put(entry.getKey(), pluginPojo); } } @Override @SuppressWarnings("unchecked") protected void afterMethod() throws Exception { emptyDirectory(new File(DEPLOY_LOCATION)); TransactionManager tm = getTransactionManager(); tm.begin(); try { Query q = em.createNamedQuery(Plugin.QUERY_FIND_BY_NAME); q.setParameter("name", PLUGIN_NAME); List<Plugin> doomedPlugins = q.getResultList(); for (Plugin doomedPlugin : doomedPlugins) { em.remove(em.find(Plugin.class, doomedPlugin.getId())); } } catch (NoResultException ignore) { } finally { tm.commit(); } return; } public void test0() throws Exception { Plugin plugin10feb = deployPluginJarToFilesystem(TESTPLUGIN_1_0_FEB); deployPluginJarToDatabase(TESTPLUGIN_1_0_FEB); createScannerAndScan(TESTPLUGIN_1_0_FEB); assertPluginInDb(plugin10feb); assertPluginOnFilesystem(plugin10feb); return; } public void test1() throws Exception { Plugin plugin10feb = deployPluginJarToFilesystem(TESTPLUGIN_1_0_FEB); createScannerAndScan(TESTPLUGIN_1_0_FEB); assertPluginInDb(plugin10feb); assertPluginOnFilesystem(plugin10feb); return; } public void test2() throws Exception { Plugin plugin10feb = deployPluginJarToDatabase(TESTPLUGIN_1_0_FEB); PluginDeploymentScanner scanner = createScanner(); scan(scanner, null); assertPluginInDb(plugin10feb); assertPluginOnFilesystem(plugin10feb); scan(null, TESTPLUGIN_1_0_FEB); assertPluginInDb(plugin10feb); assertPluginOnFilesystem(plugin10feb); return; } public void test3() throws Exception { Plugin plugin10jun = deployPluginJarToFilesystem(TESTPLUGIN_1_0_JUN); deployPluginJarToDatabase(TESTPLUGIN_1_0_FEB); createScannerAndScan(TESTPLUGIN_1_0_JUN); assertPluginInDb(plugin10jun); assertPluginOnFilesystem(plugin10jun); return; } public void test4() throws Exception { Plugin plugin10feb = deployPluginJarToFilesystem(TESTPLUGIN_1_0_FEB); Plugin plugin10jun = deployPluginJarToDatabase(TESTPLUGIN_1_0_JUN); createScannerAndScan(null); assertPluginInDb(plugin10jun); assertPluginOnFilesystem(plugin10jun); assertPluginNotOnFilesystem(plugin10feb); scan(null, TESTPLUGIN_1_0_JUN); assertPluginInDb(plugin10jun); assertPluginOnFilesystem(plugin10jun); assertPluginNotOnFilesystem(plugin10feb); return; } public void test5() throws Exception { Plugin plugin11jun = deployPluginJarToFilesystem(TESTPLUGIN_1_1_JUN); deployPluginJarToDatabase(TESTPLUGIN_1_0_JUN); createScannerAndScan(TESTPLUGIN_1_1_JUN); assertPluginInDb(plugin11jun); assertPluginOnFilesystem(plugin11jun); return; } public void test6() throws Exception { Plugin plugin10jun = deployPluginJarToFilesystem(TESTPLUGIN_1_0_JUN); Plugin plugin11jun = deployPluginJarToDatabase(TESTPLUGIN_1_1_JUN); createScannerAndScan(null); assertPluginInDb(plugin11jun); assertPluginOnFilesystem(plugin11jun); assertPluginNotOnFilesystem(plugin10jun); scan(null, TESTPLUGIN_1_1_JUN); assertPluginInDb(plugin11jun); assertPluginOnFilesystem(plugin11jun); assertPluginNotOnFilesystem(plugin10jun); return; } public void test7() throws Exception { Plugin plugin11feb = deployPluginJarToFilesystem(TESTPLUGIN_1_1_FEB); deployPluginJarToDatabase(TESTPLUGIN_1_0_JUN); createScannerAndScan(TESTPLUGIN_1_1_FEB); assertPluginInDb(plugin11feb); assertPluginOnFilesystem(plugin11feb); return; } public void test8() throws Exception { Plugin plugin10jun = deployPluginJarToFilesystem(TESTPLUGIN_1_0_JUN); Plugin plugin11feb = deployPluginJarToDatabase(TESTPLUGIN_1_1_FEB); createScannerAndScan(null); assertPluginInDb(plugin11feb); assertPluginOnFilesystem(plugin11feb); assertPluginNotOnFilesystem(plugin10jun); scan(null, TESTPLUGIN_1_1_FEB); assertPluginInDb(plugin11feb); assertPluginOnFilesystem(plugin11feb); assertPluginNotOnFilesystem(plugin10jun); return; } public void test9() throws Exception { Plugin plugin10feb = deployPluginJarToFilesystem(TESTPLUGIN_1_0_FEB); Plugin plugin10jun = deployPluginJarToFilesystem(TESTPLUGIN_1_0_JUN); deployPluginJarToDatabase(TESTPLUGIN_1_0_FEB); createScannerAndScan(null); assertPluginInDb(plugin10feb); // still the old one, will get updated when the file is deployed assertPluginOnFilesystem(plugin10jun); assertPluginNotOnFilesystem(plugin10feb); scan(null, TESTPLUGIN_1_0_JUN); assertPluginInDb(plugin10jun); // bingo - file scan brought the plugin on filesystem into db assertPluginOnFilesystem(plugin10jun); assertPluginNotOnFilesystem(plugin10feb); return; } public void test10() throws Exception { Plugin plugin10feb = deployPluginJarToFilesystem(TESTPLUGIN_1_0_FEB); Plugin plugin10jun = deployPluginJarToFilesystem(TESTPLUGIN_1_0_JUN); deployPluginJarToDatabase(TESTPLUGIN_1_0_JUN); createScannerAndScan(null); assertPluginInDb(plugin10jun); // no change assertPluginOnFilesystem(plugin10jun); // no change assertPluginNotOnFilesystem(plugin10feb); // shows that the old duplicate is gone now scan(null, TESTPLUGIN_1_0_JUN); assertPluginInDb(plugin10jun); // bingo - file scan brought the plugin on filesystem into db assertPluginOnFilesystem(plugin10jun); assertPluginNotOnFilesystem(plugin10feb); return; } public void test11() throws Exception { Plugin plugin10feb = deployPluginJarToFilesystem(TESTPLUGIN_1_0_FEB); Plugin plugin10jun = deployPluginJarToFilesystem(TESTPLUGIN_1_0_JUN); Plugin plugin11feb = deployPluginJarToDatabase(TESTPLUGIN_1_1_FEB); createScannerAndScan(null); assertPluginInDb(plugin11feb); assertPluginOnFilesystem(plugin11feb); assertPluginNotOnFilesystem(plugin10feb); assertPluginNotOnFilesystem(plugin10jun); scan(null, TESTPLUGIN_1_1_FEB); assertPluginInDb(plugin11feb); assertPluginOnFilesystem(plugin11feb); assertPluginNotOnFilesystem(plugin10feb); assertPluginNotOnFilesystem(plugin10jun); return; } public void test12() throws Exception { Plugin plugin10feb = deployPluginJarToFilesystem(TESTPLUGIN_1_0_FEB); Plugin plugin11jun = deployPluginJarToFilesystem(TESTPLUGIN_1_1_JUN); deployPluginJarToDatabase(TESTPLUGIN_1_0_FEB); createScannerAndScan(null); assertPluginInDb(plugin10feb); // still the old one, will get updated when the file is deployed assertPluginOnFilesystem(plugin11jun); assertPluginNotOnFilesystem(plugin10feb); scan(null, TESTPLUGIN_1_1_JUN); assertPluginInDb(plugin11jun); assertPluginOnFilesystem(plugin11jun); assertPluginNotOnFilesystem(plugin10feb); return; } public void test13() throws Exception { Plugin plugin10feb = deployPluginJarToFilesystem(TESTPLUGIN_1_0_FEB); Plugin plugin11jun = deployPluginJarToFilesystem(TESTPLUGIN_1_1_JUN); Plugin plugin11feb = deployPluginJarToDatabase(TESTPLUGIN_1_1_FEB); createScannerAndScan(null); assertPluginInDb(plugin11feb); // still the old one, will get updated when the file is deployed assertPluginOnFilesystem(plugin11jun); assertPluginNotOnFilesystem(plugin10feb); scan(null, TESTPLUGIN_1_1_JUN); assertPluginInDb(plugin11jun); assertPluginOnFilesystem(plugin11jun); assertPluginNotOnFilesystem(plugin10feb); return; } public void test14() throws Exception { Plugin plugin10feb = deployPluginJarToFilesystem(TESTPLUGIN_1_0_FEB); Plugin plugin10feb2 = deployPluginJarToFilesystem(TESTPLUGIN_1_0_FEB2); deployPluginJarToDatabase(TESTPLUGIN_1_0_FEB); createScannerAndScan(null); assertPluginInDb(plugin10feb); boolean plugin10febExists = !isPluginNotOnFilesystem(plugin10feb); boolean plugin10feb2Exists = !isPluginNotOnFilesystem(plugin10feb2); assert plugin10febExists ^ plugin10feb2Exists; // one must exist, but only one (we aren't guaranteed which, they are identical) scan(null, TESTPLUGIN_1_0_FEB); assertPluginInDb(plugin10feb); plugin10febExists = !isPluginNotOnFilesystem(plugin10feb); plugin10feb2Exists = !isPluginNotOnFilesystem(plugin10feb2); assert plugin10febExists ^ plugin10feb2Exists; // one must exist, but only one (we aren't guaranteed which, they are identical) return; } private void assertSamePlugin(Plugin p1, Plugin p2) throws Exception { assert p1.getName().equals(p2.getName()) : "NAME: " + p1 + "!=" + p2; assert p1.getMd5().equals(p2.getMd5()) : "MD5: " + p1 + "!=" + p2; assert p1.getMtime() == p2.getMtime() : "MTIME: " + p1 + "!=" + p2; assert p1.getVersion().equals(p2.getVersion()) : "VERSION: " + p1 + "!=" + p2; } private void assertPluginOnFilesystem(Plugin plugin) throws Exception { File file = new File(DEPLOY_LOCATION, plugin.getPath()); String version = AgentPluginDescriptorUtil.getPluginVersion(file, null).toString(); String md5 = MessageDigestGenerator.getDigestString(file); long mtime = file.lastModified(); Plugin filePlugin = new Plugin(PLUGIN_NAME, file.getName()); filePlugin.setMd5(md5); filePlugin.setVersion(version); filePlugin.setMtime(mtime); assertSamePlugin(plugin, filePlugin); } private void assertPluginInDb(Plugin plugin) throws Exception { Plugin dbPlugin; TransactionManager tm = getTransactionManager(); tm.begin(); try { Query q = em.createNamedQuery(Plugin.QUERY_FIND_BY_NAME); q.setParameter("name", PLUGIN_NAME); dbPlugin = (Plugin) q.getSingleResult(); } finally { tm.rollback(); } assertSamePlugin(plugin, dbPlugin); } private void assertPluginNotOnFilesystem(Plugin plugin) throws Exception { assert isPluginNotOnFilesystem(plugin); } private boolean isPluginNotOnFilesystem(Plugin plugin) { File file = new File(DEPLOY_LOCATION, plugin.getPath()); return !file.exists(); } private PluginDeploymentScanner createScannerAndScan(String pluginId) throws Exception { PluginDeploymentScanner scanner = createScanner(); scan(scanner, pluginId); // see comments in scan() for what pluginId is return scanner; } private PluginDeploymentScanner createScanner() throws Exception { PluginDeploymentScanner scanner = new PluginDeploymentScanner(); File pluginDirectoryFile = new File(DEPLOY_LOCATION); scanner.setAgentPluginDir(pluginDirectoryFile.getAbsolutePath()); return scanner; } /** * Scans in both directions - first asks the db scanner to scan the database. * Then it tries to register the plugin found on the filesystem. * pluginId identifies the plugin on the filesystem that is to be scanned up to DB (if appropriate). * * @param scanner if not-null, uses this to perform a db scan first * @param pluginId if not-null, this is registered (i.e. a file scan registering this plugin) * @throws Exception */ private void scan(PluginDeploymentScanner scanner, String pluginId) throws Exception { if (scanner != null) { scanner.scan(); } if (pluginId != null) { Plugin plugin = this.testPlugins.get(pluginId); Plugin pluginDup = new Plugin(plugin.getName(), plugin.getPath(), plugin.getMd5()); pluginDup.setMtime(plugin.getMtime()); pluginDup.setVersion(plugin.getVersion()); PluginDescriptor pluginDescriptor = this.testPluginDescriptors.get(pluginId); File localPluginFile = this.testPluginFiles.get(pluginId); pluginMgr.registerPlugin(pluginDup, pluginDescriptor, localPluginFile, false); } return; } private Plugin deployPluginJarToDatabase(String pluginId) throws Exception { Plugin plugin = testPlugins.get(pluginId); // make our own copy since we will be persisting it and populating content in it Plugin pluginPojo = new Plugin(plugin.getName(), plugin.getPath(), plugin.getMd5()); pluginPojo.setId(0); pluginPojo.setDisplayName(plugin.getName()); pluginPojo.setVersion(plugin.getVersion()); pluginPojo.setMtime(plugin.getMtime()); pluginPojo.setContent(StreamUtil.slurp(new FileInputStream(testPluginFiles.get(pluginId)))); TransactionManager tm = getTransactionManager(); tm.begin(); try { em.persist(pluginPojo); } catch (Exception e) { e.printStackTrace(); throw e; } finally { tm.commit(); } return plugin; // do not return the persisted pojo, let GC collect the larger pojo with the file content } private Plugin deployPluginJarToFilesystem(String pluginId) throws Exception { File pluginJar = testPluginFiles.get(pluginId); File deployedPluginJar = new File(DEPLOY_LOCATION, pluginJar.getName()); FileOutputStream out = new FileOutputStream(deployedPluginJar); FileInputStream in = new FileInputStream(pluginJar); StreamUtil.copy(in, out); timestampPluginJar(deployedPluginJar, pluginId); // make sure its last-mod time is correct return testPlugins.get(pluginId); } private void timestampPluginJar(File pluginJar, String pluginId) throws Exception { pluginJar.setLastModified(testTimestamps.get(pluginId).getTime()); } private void buildPluginJar(String descriptor, File pluginJar) throws Exception { FileOutputStream fos = new FileOutputStream(pluginJar); ZipOutputStream zip = new ZipOutputStream(fos); try { ZipEntry zipEntry = new ZipEntry("META-INF/rhq-plugin.xml"); zip.putNextEntry(zipEntry); InputStream input = this.getClass().getClassLoader().getResourceAsStream(descriptor); try { StreamUtil.copy(input, zip, false); } finally { input.close(); } } finally { zip.close(); } } private void emptyDirectory(File dirToEmpty) { if (!dirToEmpty.isDirectory()) { return; } File[] doomedFiles = dirToEmpty.listFiles(); for (File doomedFile : doomedFiles) { doomedFile.delete(); } } }