blob: 93ac64551300f9ac85850e530a29af2db3c08f51 [file] [log] [blame]
/*
* =========================================================================
* Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* more patents listed at http://www.pivotal.io/patents.
* =========================================================================
*/
package com.gemstone.gemfire.internal;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.Test;
import com.gemstone.gemfire.cache.execute.Execution;
import com.gemstone.gemfire.cache.execute.FunctionService;
import com.gemstone.gemfire.cache.execute.ResultCollector;
import com.gemstone.gemfire.cache30.CacheTestCase;
import com.gemstone.gemfire.distributed.DistributedSystem;
import com.gemstone.gemfire.distributed.internal.DistributionConfig;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import dunit.Host;
import dunit.SerializableRunnable;
import dunit.VM;
/**
* Unit tests for the JarDeployer class
*
* @author David Hoots
* @since 7.0
*/
public class JarDeployerDUnitTest extends CacheTestCase {
private static final long serialVersionUID = 1L;
static FileLock savedFileLock = null;
private final ClassBuilder classBuilder = new ClassBuilder();
public JarDeployerDUnitTest(String name) {
super(name);
}
@Override
public void tearDown2() throws Exception {
JarDeployer jarDeployer = new JarDeployer();
for (JarClassLoader jarClassLoader : jarDeployer.findJarClassLoaders()) {
if (jarClassLoader.getJarName().startsWith("JarDeployerDUnit")) {
jarDeployer.undeploy(jarClassLoader.getJarName());
}
}
for (String functionName : FunctionService.getRegisteredFunctions().keySet()) {
if (functionName.startsWith("JarDeployerDUnit")) {
FunctionService.unregisterFunction(functionName);
}
}
disconnectAllFromDS();
deleteSavedJarFiles();
super.tearDown2();
}
@Test
public void testDeployFileAndChange() throws IOException, ClassNotFoundException {
final JarDeployer jarDeployer = new JarDeployer();
final File currentDir = new File(".").getAbsoluteFile();
// First deploy of the JAR file
File jarFile = getFirstVersionForTest(currentDir, "JarDeployerDUnit.jar");
byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDFACA");
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
try {
ClassPathLoader.getLatest().forName("JarDeployerDUnitDFACA");
} catch (ClassNotFoundException cnfex) {
fail("JAR file not correctly added to Classpath");
}
if (!jarFile.exists()) {
fail("JAR file not found where expected: " + jarFile.getName());
}
if (!doesFileMatchBytes(jarFile, jarBytes)) {
fail("Contents of JAR file do not match those provided: " + jarFile.getName());
}
// Now deploy an updated JAR file and make sure that the next version of the JAR file
// was created and the first one was deleted.
jarFile = getNextVersionJarFile(jarFile);
jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDFACB");
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
if (!jarFile.exists()) {
fail("JAR file not found where expected: " + jarFile.getName());
}
if (!doesFileMatchBytes(jarFile, jarBytes)) {
fail("Contents of JAR file do not match those provided: " + jarFile.getName());
}
try {
ClassPathLoader.getLatest().forName("JarDeployerDUnitDFACB");
} catch (ClassNotFoundException cnfex) {
fail("JAR file not correctly added to Classpath");
}
try {
ClassPathLoader.getLatest().forName("JarDeployerDUnitDFACA");
fail("Class should not be found on Classpath: JarDeployerDUnitDFACA");
} catch (ClassNotFoundException expected) { // expected
}
}
@Test
public void testDeployNoUpdateWhenNoChange() throws IOException, ClassNotFoundException {
final JarDeployer jarDeployer = new JarDeployer();
final File currentDir = new File(".").getAbsoluteFile();
// First deploy of the JAR file
File jarFile = getFirstVersionForTest(currentDir, "JarDeployerDUnit.jar");
byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDNUWNC");
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
if (!jarFile.exists()) {
fail("JAR file not found where expected: " + jarFile.getName());
}
// Now deploy the same JAR file
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
if (!jarFile.exists()) {
fail("JAR file not found where expected: " + jarFile.getName());
}
jarFile = getNextVersionJarFile(jarFile);
if (jarFile.exists()) {
fail("JAR file should not have been created: " + jarFile.getName());
}
}
@Test
@SuppressWarnings("serial")
public void testDeployExclusiveLock() throws IOException, ClassNotFoundException {
final JarDeployer jarDeployer = new JarDeployer();
final File currentDir = new File(".").getAbsoluteFile();
final VM vm = Host.getHost(0).getVM(0);
// Deploy the Class JAR file
final File jarFile1 = getFirstVersionForTest(currentDir, "JarDeployerDUnit.jar");
byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDELA");
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
try {
ClassPathLoader.getLatest().forName("JarDeployerDUnitDELA");
} catch (ClassNotFoundException cnfex) {
fail("JAR file not correctly added to Classpath");
}
assertNotNull(ClassPathLoader.getLatest().getResource("JarDeployerDUnitDELA.class"));
// Attempt to acquire an exclusive lock in the other VM
vm.invoke(new SerializableRunnable() {
@Override
public void run() {
FileOutputStream outStream = null;
FileLock fileLock = null;
try {
outStream = new FileOutputStream(jarFile1, true);
fileLock = outStream.getChannel().tryLock(0, 1, false);
if (fileLock != null) {
fail("Should not have been able to obtain exclusive lock on file:" + jarFile1.getAbsolutePath());
}
} catch (FileNotFoundException fnfex) {
fail("JAR file not found where expected", fnfex);
} catch (IOException ioex) {
fail("IOException when trying to obtain exclusive lock", ioex);
} finally {
if (outStream != null) {
try {
outStream.close();
} catch (IOException ioex) {
fail("Could not close lock file output stream");
}
}
if (fileLock != null) {
try {
fileLock.channel().close();
} catch (IOException ioex) {
fail("Could not close lock file channel");
}
}
}
}
});
}
@Test
@SuppressWarnings("serial")
public void testDeploySharedLock() throws IOException, ClassNotFoundException {
final JarDeployer jarDeployer = new JarDeployer();
final File currentDir = new File(".").getAbsoluteFile();
final VM vm = Host.getHost(0).getVM(0);
// Deploy the JAR file
final File jarFile1 = getFirstVersionForTest(currentDir, "JarDeployerDUnit.jar");
byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDSLA");
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
try {
ClassPathLoader.getLatest().forName("JarDeployerDUnitDSLA");
} catch (ClassNotFoundException cnfex) {
fail("JAR file not correctly added to Classpath");
}
// Acquire a shared lock in the other VM
vm.invoke(new SerializableRunnable() {
@Override
public void run() {
if (!jarFile1.exists()) {
fail("JAR file not found where expected: " + jarFile1.getName());
}
try {
JarDeployerDUnitTest.savedFileLock = acquireSharedLock(jarFile1);
} catch (IOException ioex) {
fail("Unable to acquire the shared file lock");
}
}
});
// Now update the JAR file and make sure the first one isn't deleted
jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDSLB");
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
try {
ClassPathLoader.getLatest().forName("JarDeployerDUnitDSLB");
} catch (ClassNotFoundException cnfex) {
fail("JAR file not correctly added to Classpath");
}
try {
ClassPathLoader.getLatest().forName("JarDeployerDUnitC");
fail("Class should not be found on Classpath: JarDeployerDUniDSLA");
} catch (ClassNotFoundException expected) { // expected
}
if (!jarFile1.exists()) {
fail("JAR file should not have been deleted: " + jarFile1.getName());
}
vm.invoke(new SerializableRunnable() {
@Override
public void run() {
try {
releaseLock(JarDeployerDUnitTest.savedFileLock, jarFile1);
} catch (IOException ioex) {
fail("Unable to release the shared file lock");
}
}
});
}
@Test
@SuppressWarnings("serial")
public void testUndeploySharedLock() throws IOException, ClassNotFoundException {
final JarDeployer jarDeployer = new JarDeployer();
final File currentDir = new File(".").getAbsoluteFile();
final VM vm = Host.getHost(0).getVM(0);
// Deploy the JAR file
final File jarFile1 = getFirstVersionForTest(currentDir, "JarDeployerDUnit.jar");
byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitUSL");
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
try {
ClassPathLoader.getLatest().forName("JarDeployerDUnitUSL");
} catch (ClassNotFoundException cnfex) {
fail("JAR file not correctly added to Classpath");
}
// Acquire a shared lock in the other VM
vm.invoke(new SerializableRunnable() {
@Override
public void run() {
if (!jarFile1.exists()) {
fail("JAR file not found where expected: " + jarFile1.getName());
}
try {
JarDeployerDUnitTest.savedFileLock = acquireSharedLock(jarFile1);
} catch (IOException ioex) {
fail("Unable to acquire the shared file lock");
}
}
});
// Now undeploy the JAR file and make sure the first one isn't deleted
jarDeployer.undeploy("JarDeployerDUnit.jar");
if (!jarFile1.exists()) {
fail("JAR file should not have been deleted: " + jarFile1.getName());
}
vm.invoke(new SerializableRunnable() {
@Override
public void run() {
try {
releaseLock(JarDeployerDUnitTest.savedFileLock, jarFile1);
} catch (IOException ioex) {
fail("Unable to release the shared file lock");
}
}
});
}
@Test
@SuppressWarnings("serial")
public void testDeployUpdateByAnotherVM() throws IOException, ClassNotFoundException {
final JarDeployer jarDeployer = new JarDeployer();
final File currentDir = new File(".").getAbsoluteFile();
final VM vm = Host.getHost(0).getVM(0);
final File jarFile1 = getFirstVersionForTest(currentDir, "JarDeployerDUnit.jar");
byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDUBAVMA");
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
try {
ClassPathLoader.getLatest().forName("JarDeployerDUnitDUBAVMA");
} catch (ClassNotFoundException cnfex) {
fail("JAR file not correctly added to Classpath");
}
final File jarFile2 = getNextVersionJarFile(jarFile1);
final byte[] vmJarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDUBAVMB");
vm.invoke(new SerializableRunnable() {
@Override
public void run() {
if (!jarFile1.exists()) {
fail("JAR file not found where expected: " + jarFile1.getName());
}
// The other VM writes out a newer version of the JAR file.
try {
writeJarBytesToFile(jarFile2, vmJarBytes);
} catch (IOException ioex) {
fail("Could not write JAR File");
}
}
});
// This VM is told to deploy the same JAR file.
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { vmJarBytes });
try {
ClassPathLoader.getLatest().forName("JarDeployerDUnitDUBAVMB");
} catch (ClassNotFoundException cnfex) {
fail("JAR file not correctly added to Classpath");
}
try {
ClassPathLoader.getLatest().forName("JarDeployerDUnitDUBAVMA");
fail("Class should not be found on Classpath: JarDeployerDUnitDUBAVMA");
} catch (ClassNotFoundException expected) { // expected
}
if (!jarFile2.exists()) {
fail("JAR file should not have been deleted: " + jarFile2.getName());
}
// Make sure the second deploy didn't create a 3rd version of the JAR file.
final File jarFile3 = getNextVersionJarFile(jarFile2);
if (jarFile3.exists()) {
fail("JAR file should not have been created: " + jarFile3.getName());
}
}
@Test
public void testLoadPreviouslyDeployedJars() throws IOException {
final File parentJarFile = new File(JarDeployer.JAR_PREFIX + "JarDeployerDUnitAParent.jar#1");
final File usesJarFile = new File(JarDeployer.JAR_PREFIX + "JarDeployerDUnitUses.jar#1");
final File functionJarFile = new File(JarDeployer.JAR_PREFIX + "JarDeployerDUnitFunction.jar#1");
// Write out a JAR files.
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("package jddunit.parent;");
stringBuffer.append("public class JarDeployerDUnitParent {");
stringBuffer.append("public String getValueParent() {");
stringBuffer.append("return \"PARENT\";}}");
byte[] jarBytes = this.classBuilder.createJarFromClassContent("jddunit/parent/JarDeployerDUnitParent", stringBuffer.toString());
FileOutputStream outStream = new FileOutputStream(parentJarFile);
outStream.write(jarBytes);
outStream.close();
stringBuffer = new StringBuffer();
stringBuffer.append("package jddunit.uses;");
stringBuffer.append("public class JarDeployerDUnitUses {");
stringBuffer.append("public String getValueUses() {");
stringBuffer.append("return \"USES\";}}");
jarBytes = this.classBuilder.createJarFromClassContent("jddunit/uses/JarDeployerDUnitUses", stringBuffer.toString());
outStream = new FileOutputStream(usesJarFile);
outStream.write(jarBytes);
outStream.close();
stringBuffer = new StringBuffer();
stringBuffer.append("package jddunit.function;");
stringBuffer.append("import jddunit.parent.JarDeployerDUnitParent;");
stringBuffer.append("import jddunit.uses.JarDeployerDUnitUses;");
stringBuffer.append("import com.gemstone.gemfire.cache.execute.Function;");
stringBuffer.append("import com.gemstone.gemfire.cache.execute.FunctionContext;");
stringBuffer.append("public class JarDeployerDUnitFunction extends JarDeployerDUnitParent implements Function {");
stringBuffer.append("private JarDeployerDUnitUses uses = new JarDeployerDUnitUses();");
stringBuffer.append("public boolean hasResult() {return true;}");
stringBuffer
.append("public void execute(FunctionContext context) {context.getResultSender().lastResult(getValueParent() + \":\" + uses.getValueUses());}");
stringBuffer.append("public String getId() {return \"JarDeployerDUnitFunction\";}");
stringBuffer.append("public boolean optimizeForWrite() {return false;}");
stringBuffer.append("public boolean isHA() {return false;}}");
ClassBuilder functionClassBuilder = new ClassBuilder();
functionClassBuilder.addToClassPath(parentJarFile.getAbsolutePath());
functionClassBuilder.addToClassPath(usesJarFile.getAbsolutePath());
jarBytes = functionClassBuilder.createJarFromClassContent("jddunit/function/JarDeployerDUnitFunction", stringBuffer.toString());
outStream = new FileOutputStream(functionJarFile);
outStream.write(jarBytes);
outStream.close();
// Start the distributed system and check to see if the function executes correctly
DistributedSystem distributedSystem = getSystem();
getCache();
Execution execution = FunctionService.onMember(distributedSystem, distributedSystem.getDistributedMember());
ResultCollector resultCollector = execution.execute("JarDeployerDUnitFunction");
@SuppressWarnings("unchecked")
List<String> result = (List<String>) resultCollector.getResult();
assertEquals("PARENT:USES", result.get(0));
}
@Test
public void testDeployToAlternateDirectory() throws IOException, ClassNotFoundException {
final File alternateDir = new File("JarDeployerDUnit");
alternateDir.mkdir();
// Add the alternate directory to the distributed system, get it back out, and then create
// a JarDeployer object with it.
Properties properties = new Properties();
properties.put(DistributionConfig.DEPLOY_WORKING_DIR, alternateDir.getAbsolutePath());
InternalDistributedSystem distributedSystem = getSystem(properties);
final JarDeployer jarDeployer = new JarDeployer(distributedSystem.getConfig().getDeployWorkingDir());
File jarFile = getFirstVersionForTest(alternateDir, "JarDeployerDUnit.jar");
byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDTAC");
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
try {
ClassPathLoader.getLatest().forName("JarDeployerDUnitDTAC");
} catch (ClassNotFoundException cnfex) {
fail("JAR file not correctly added to Classpath");
}
if (!jarFile.exists()) {
fail("JAR file not found where expected: " + jarFile.getName());
}
if (!doesFileMatchBytes(jarFile, jarBytes)) {
fail("Contents of JAR file do not match those provided: " + jarFile.getName());
}
}
@Test
public void testDeployToInvalidDirectory() throws IOException, ClassNotFoundException {
final File alternateDir = new File("JarDeployerDUnit");
FileUtil.delete(new File("JarDeployerDUnit"));
final JarDeployer jarDeployer = new JarDeployer(alternateDir);
final CyclicBarrier barrier = new CyclicBarrier(2);
final byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitDTID");
// Test to verify that deployment fails if the directory doesn't exist.
try {
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
fail("Exception should have been thrown due to missing deployment directory.");
} catch (IOException expected) {
// Expected.
}
// Test to verify that deployment succeeds if the directory doesn't
// initially exist, but is then created while the JarDeployer is looping
// looking for a valid directory.
Thread thread = new Thread () {
@Override
public void run() {
try {
barrier.await();
} catch (InterruptedException iex) {
fail("Interrupted while waiting.");
} catch (BrokenBarrierException bbex) {
fail("Broken barrier.");
}
try {
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
} catch (IOException ioex) {
fail("IOException received unexpectedly.");
} catch (ClassNotFoundException cnfex) {
fail("ClassNotFoundException received unexpectedly.");
}
}
};
thread.start();
try {
barrier.await();
Thread.sleep(500);
alternateDir.mkdir();
thread.join();
} catch (InterruptedException iex) {
fail("Interrupted while waiting.");
} catch (BrokenBarrierException bbex) {
fail("Broken barrier.");
}
}
boolean okayToResume;
@Test
public void testSuspendAndResume() throws IOException, ClassNotFoundException {
final JarDeployer jarDeployer = new JarDeployer();
byte[] jarBytes = this.classBuilder.createJarFromName("JarDeployerDUnitSAR");
final JarDeployer suspendingJarDeployer = new JarDeployer();
final CountDownLatch latch = new CountDownLatch(1);
Thread thread = new Thread () {
@Override
public void run() {
try {
suspendingJarDeployer.suspendAll();
latch.countDown();
Thread.sleep(3000);
} catch (InterruptedException iex) {
// It doesn't matter, just fail the test
}
JarDeployerDUnitTest.this.okayToResume = true;
suspendingJarDeployer.resumeAll();
}
};
thread.start();
try {
latch.await();
} catch (InterruptedException iex) {
// It doesn't matter, just fail the test
}
jarDeployer.deploy(new String[] { "JarDeployerDUnit.jar" }, new byte[][] { jarBytes });
if (!this.okayToResume) {
fail("JarDeployer did not suspend as expected");
}
}
@Test
public void testZeroLengthFile() throws IOException, ClassNotFoundException {
final JarDeployer jarDeployer = new JarDeployer();
try {
jarDeployer.deploy(new String[] { "JarDeployerDUnitZLF.jar" }, new byte[][] { new byte[0] });
fail("Zero length files are not deployable");
} catch (IllegalArgumentException expected) {
// Expected
}
try {
jarDeployer.deploy(new String[] { "JarDeployerDUnitZLF1.jar", "JarDeployerDUnitZLF2.jar" }, new byte[][] {
this.classBuilder.createJarFromName("JarDeployerDUnitZLF1"), new byte[0] });
fail("Zero length files are not deployable");
} catch (IllegalArgumentException expected) {
// Expected
}
}
@Test
public void testInvalidJarFile() throws IOException, ClassNotFoundException {
final JarDeployer jarDeployer = new JarDeployer();
try {
jarDeployer.deploy(new String[] { "JarDeployerDUnitIJF.jar" }, new byte[][] { "INVALID JAR CONTENT".getBytes() });
fail("Non-JAR files are not deployable");
} catch (IllegalArgumentException expected) {
// Expected
}
try {
jarDeployer.deploy(new String[] { "JarDeployerDUnitIJF1.jar", "JarDeployerDUnitIJF2.jar" }, new byte[][] {
this.classBuilder.createJarFromName("JarDeployerDUnitIJF1"), "INVALID JAR CONTENT".getBytes() });
fail("Non-JAR files are not deployable");
} catch (IllegalArgumentException expected) {
// Expected
}
final VM vm = Host.getHost(0).getVM(1);
vm.invoke(new SerializableRunnable() {
@Override
public void run() {
File invalidFile = new File(JarDeployer.JAR_PREFIX + "JarDeployerDUnitIJF.jar#3");
try {
RandomAccessFile randomAccessFile = new RandomAccessFile(invalidFile, "rw");
randomAccessFile.write("GARBAGE".getBytes(), 0, 7);
randomAccessFile.close();
} catch (IOException ioex) {
fail("Error trying to create garbage file for test", ioex);
}
getSystem();
getCache();
if (invalidFile.exists()) {
fail("Invalid JAR file should have been deleted at startup");
}
}
});
}
FileLock acquireSharedLock(final File file) throws IOException {
@SuppressWarnings("resource")
FileLock fileLock = new FileInputStream(file).getChannel().lock(0, 1, true);
return fileLock;
}
void releaseLock(final FileLock fileLock, final File lockFile) throws IOException {
if (lockFile == null) {
return;
}
try {
if (fileLock != null) {
fileLock.release();
fileLock.channel().close();
}
} finally {
if (!lockFile.delete()) {
lockFile.deleteOnExit();
}
}
}
protected boolean doesFileMatchBytes(final File file, final byte[] bytes) throws IOException {
// If the don't have the same number of bytes then nothing to do
if (file.length() != bytes.length) {
return false;
}
// Open the file then loop comparing each byte
InputStream inStream = new FileInputStream(file);
int index = 0;
try {
for (; index < bytes.length; index++) {
if (((byte) inStream.read()) != bytes[index])
break;
}
} finally {
inStream.close();
}
// If we didn't get to the end then something was different
if (index < bytes.length)
return false;
return true;
}
private void deleteSavedJarFiles() throws IOException {
FileUtil.deleteMatching(new File("."), "^" + JarDeployer.JAR_PREFIX + "JarDeployerDUnit.*#\\d++$");
FileUtil.delete(new File("JarDeployerDUnit"));
}
private File getFirstVersionForTest(final File saveDirfile, final String jarFilename) {
final File[] oldJarFiles = findSortedOldVersionsOfJar(saveDirfile, jarFilename);
if (oldJarFiles.length == 0) {
return new File(saveDirfile, JarDeployer.JAR_PREFIX + jarFilename + "#1");
}
return getNextVersionJarFile(oldJarFiles[0]);
}
private File getNextVersionJarFile(final File oldJarFile) {
final Matcher matcher = JarDeployer.versionedPattern.matcher(oldJarFile.getName());
matcher.find();
String newFileName = matcher.group(1) + "#" + (Integer.parseInt(matcher.group(2)) + 1);
return new File(oldJarFile.getParentFile(), newFileName);
}
private File[] findSortedOldVersionsOfJar(final File saveDirfile, final String jarFilename) {
// Find all matching files
final Pattern pattern = Pattern.compile("^" + JarDeployer.JAR_PREFIX + jarFilename + "#\\d++$");
final File[] oldJarFiles = saveDirfile.listFiles(new FilenameFilter() {
@Override
public boolean accept(final File file, final String name) {
return pattern.matcher(name).matches();
}
});
// Sort them in order from newest (highest version) to oldest
Arrays.sort(oldJarFiles, new Comparator<File>() {
@Override
public int compare(final File file1, final File file2) {
int file1Version = extractVersionFromFilename(file1);
int file2Version = extractVersionFromFilename(file2);
return file2Version - file1Version;
}
});
return oldJarFiles;
}
int extractVersionFromFilename(final File file) {
final Matcher matcher = JarDeployer.versionedPattern.matcher(file.getName());
matcher.find();
return Integer.parseInt(matcher.group(2));
}
void writeJarBytesToFile(File jarFile, byte[] jarBytes) throws IOException {
final OutputStream outStream = new FileOutputStream(jarFile);
outStream.write(jarBytes);
outStream.close();
}
}