diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/JarFileArchive.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/JarFileArchive.java index d71f922293a..b31ebf59a50 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/JarFileArchive.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/JarFileArchive.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.UUID; import java.util.jar.JarEntry; import java.util.jar.Manifest; @@ -40,6 +41,7 @@ import org.springframework.boot.loader.util.AsciiBytes; * {@link Archive} implementation backed by a {@link JarFile}. * * @author Phillip Webb + * @author Andy Wilkinson */ public class JarFileArchive extends Archive { @@ -53,6 +55,8 @@ public class JarFileArchive extends Archive { private URL url; + private File tempUnpackFolder; + public JarFileArchive(File file) throws IOException { this(file, null); } @@ -123,10 +127,25 @@ public class JarFileArchive extends Archive { } private File getTempUnpackFolder() { - File tempFolder = new File(System.getProperty("java.io.tmpdir")); - File unpackFolder = new File(tempFolder, "spring-boot-libs"); - unpackFolder.mkdirs(); - return unpackFolder; + if (this.tempUnpackFolder == null) { + File tempFolder = new File(System.getProperty("java.io.tmpdir")); + this.tempUnpackFolder = createUnpackFolder(tempFolder); + } + return this.tempUnpackFolder; + } + + private File createUnpackFolder(File parent) { + int attempts = 0; + while (attempts++ < 1000) { + String fileName = new File(this.jarFile.getName()).getName(); + File unpackFolder = new File(parent, + fileName + "-spring-boot-libs-" + UUID.randomUUID()); + if (unpackFolder.mkdirs()) { + return unpackFolder; + } + } + throw new IllegalStateException( + "Failed to create unpack folder in directory '" + parent + "'"); } private void unpack(JarEntryData data, File file) throws IOException { diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/TestJarCreator.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/TestJarCreator.java index 3ffa0acf963..a67fcb57958 100644 --- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/TestJarCreator.java +++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/TestJarCreator.java @@ -50,27 +50,33 @@ public abstract class TestJarCreator { writeDirEntry(jarOutputStream, "special/"); writeEntry(jarOutputStream, "special/\u00EB.dat", '\u00EB'); - JarEntry nestedEntry = new JarEntry("nested.jar"); - byte[] nestedJarData = getNestedJarData(); - nestedEntry.setSize(nestedJarData.length); - nestedEntry.setCompressedSize(nestedJarData.length); - if (unpackNested) { - nestedEntry.setComment("UNPACK:0000000000000000000000000000000000000000"); - } - CRC32 crc32 = new CRC32(); - crc32.update(nestedJarData); - nestedEntry.setCrc(crc32.getValue()); - - nestedEntry.setMethod(ZipEntry.STORED); - jarOutputStream.putNextEntry(nestedEntry); - jarOutputStream.write(nestedJarData); - jarOutputStream.closeEntry(); + writeNestedEntry("nested.jar", unpackNested, jarOutputStream); + writeNestedEntry("another-nested.jar", unpackNested, jarOutputStream); } finally { jarOutputStream.close(); } } + private static void writeNestedEntry(String name, boolean unpackNested, + JarOutputStream jarOutputStream) throws Exception, IOException { + JarEntry nestedEntry = new JarEntry(name); + byte[] nestedJarData = getNestedJarData(); + nestedEntry.setSize(nestedJarData.length); + nestedEntry.setCompressedSize(nestedJarData.length); + if (unpackNested) { + nestedEntry.setComment("UNPACK:0000000000000000000000000000000000000000"); + } + CRC32 crc32 = new CRC32(); + crc32.update(nestedJarData); + nestedEntry.setCrc(crc32.getValue()); + + nestedEntry.setMethod(ZipEntry.STORED); + jarOutputStream.putNextEntry(nestedEntry); + jarOutputStream.write(nestedJarData); + jarOutputStream.closeEntry(); + } + private static byte[] getNestedJarData() throws Exception { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); JarOutputStream jarOutputStream = new JarOutputStream(byteArrayOutputStream); diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/archive/JarFileArchiveTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/archive/JarFileArchiveTests.java index 3ebc190bb93..0f0994e532a 100644 --- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/archive/JarFileArchiveTests.java +++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/archive/JarFileArchiveTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,8 @@ import org.springframework.boot.loader.util.AsciiBytes; import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertThat; @@ -38,6 +40,7 @@ import static org.junit.Assert.assertThat; * Tests for {@link JarFileArchive}. * * @author Phillip Webb + * @author Andy Wilkinson */ public class JarFileArchiveTests { @@ -57,8 +60,7 @@ public class JarFileArchiveTests { private void setup(boolean unpackNested) throws Exception { this.rootJarFile = this.temporaryFolder.newFile(); - this.rootJarFileUrl = rootJarFile.toURI().toString(); - System.out.println(rootJarFileUrl); + this.rootJarFileUrl = this.rootJarFile.toURI().toString(); TestJarCreator.createTestJar(this.rootJarFile, unpackNested); this.archive = new JarFileArchive(this.rootJarFile); } @@ -72,7 +74,7 @@ public class JarFileArchiveTests { @Test public void getEntries() throws Exception { Map entries = getEntriesMap(this.archive); - assertThat(entries.size(), equalTo(9)); + assertThat(entries.size(), equalTo(10)); } @Test @@ -98,6 +100,31 @@ public class JarFileArchiveTests { assertThat(nested.getUrl().toString(), endsWith(".jar")); } + @Test + public void unpackedLocationsAreUniquePerArchive() throws Exception { + setup(true); + Entry entry = getEntriesMap(this.archive).get("nested.jar"); + URL firstNested = this.archive.getNestedArchive(entry).getUrl(); + setup(true); + entry = getEntriesMap(this.archive).get("nested.jar"); + URL secondNested = this.archive.getNestedArchive(entry).getUrl(); + assertThat(secondNested, is(not(equalTo(firstNested)))); + } + + @Test + public void unpackedLocationsFromSameArchiveShareSameParent() throws Exception { + setup(true); + File nested = new File(this.archive + .getNestedArchive(getEntriesMap(this.archive).get("nested.jar")).getUrl() + .toURI()); + File anotherNested = new File( + this.archive + .getNestedArchive( + getEntriesMap(this.archive).get("another-nested.jar")) + .getUrl().toURI()); + assertThat(nested.getParent(), is(equalTo(anotherNested.getParent()))); + } + @Test public void getFilteredArchive() throws Exception { Archive filteredArchive = this.archive