Improve startup performance for nested JARs
Refactor spring-boot-loader to work directly with low level zip data structures, removing the need to read every byte when the application loads. This change was initially driven by the desire to improve tab-completion time when working with the Spring CLI tool. Local tests show CLI startup time improving from ~0.7 to ~0.22 seconds. Startup times for regular Spring Boot applications are also improved, for example, the tomcat sample application now starts 0.5 seconds faster.
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.
|
||||
* 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 org.springframework.boot.loader;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link AsciiBytes}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class AsciiBytesTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void createFromBytes() throws Exception {
|
||||
AsciiBytes bytes = new AsciiBytes(new byte[] { 65, 66 });
|
||||
assertThat(bytes.toString(), equalTo("AB"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromBytesWithOffset() throws Exception {
|
||||
AsciiBytes bytes = new AsciiBytes(new byte[] { 65, 66, 67, 68 }, 1, 2);
|
||||
assertThat(bytes.toString(), equalTo("BC"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromString() throws Exception {
|
||||
AsciiBytes bytes = new AsciiBytes("AB");
|
||||
assertThat(bytes.toString(), equalTo("AB"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void length() throws Exception {
|
||||
AsciiBytes b1 = new AsciiBytes(new byte[] { 65, 66 });
|
||||
AsciiBytes b2 = new AsciiBytes(new byte[] { 65, 66, 67, 68 }, 1, 2);
|
||||
assertThat(b1.length(), equalTo(2));
|
||||
assertThat(b2.length(), equalTo(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWith() throws Exception {
|
||||
AsciiBytes abc = new AsciiBytes(new byte[] { 65, 66, 67 });
|
||||
AsciiBytes ab = new AsciiBytes(new byte[] { 65, 66 });
|
||||
AsciiBytes bc = new AsciiBytes(new byte[] { 65, 66, 67 }, 1, 2);
|
||||
AsciiBytes abcd = new AsciiBytes(new byte[] { 65, 66, 67, 68 });
|
||||
assertThat(abc.startsWith(abc), equalTo(true));
|
||||
assertThat(abc.startsWith(ab), equalTo(true));
|
||||
assertThat(abc.startsWith(bc), equalTo(false));
|
||||
assertThat(abc.startsWith(abcd), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endsWith() throws Exception {
|
||||
AsciiBytes abc = new AsciiBytes(new byte[] { 65, 66, 67 });
|
||||
AsciiBytes bc = new AsciiBytes(new byte[] { 65, 66, 67 }, 1, 2);
|
||||
AsciiBytes ab = new AsciiBytes(new byte[] { 65, 66 });
|
||||
AsciiBytes aabc = new AsciiBytes(new byte[] { 65, 65, 66, 67 });
|
||||
assertThat(abc.endsWith(abc), equalTo(true));
|
||||
assertThat(abc.endsWith(bc), equalTo(true));
|
||||
assertThat(abc.endsWith(ab), equalTo(false));
|
||||
assertThat(abc.endsWith(aabc), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void substringFromBeingIndex() throws Exception {
|
||||
AsciiBytes abcd = new AsciiBytes(new byte[] { 65, 66, 67, 68 });
|
||||
assertThat(abcd.substring(0).toString(), equalTo("ABCD"));
|
||||
assertThat(abcd.substring(1).toString(), equalTo("BCD"));
|
||||
assertThat(abcd.substring(2).toString(), equalTo("CD"));
|
||||
assertThat(abcd.substring(3).toString(), equalTo("D"));
|
||||
assertThat(abcd.substring(4).toString(), equalTo(""));
|
||||
this.thrown.expect(IndexOutOfBoundsException.class);
|
||||
abcd.substring(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void substring() throws Exception {
|
||||
AsciiBytes abcd = new AsciiBytes(new byte[] { 65, 66, 67, 68 });
|
||||
assertThat(abcd.substring(0, 4).toString(), equalTo("ABCD"));
|
||||
assertThat(abcd.substring(1, 3).toString(), equalTo("BC"));
|
||||
assertThat(abcd.substring(3, 4).toString(), equalTo("D"));
|
||||
assertThat(abcd.substring(3, 3).toString(), equalTo(""));
|
||||
this.thrown.expect(IndexOutOfBoundsException.class);
|
||||
abcd.substring(3, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendString() throws Exception {
|
||||
AsciiBytes bc = new AsciiBytes(new byte[] { 65, 66, 67, 68 }, 1, 2);
|
||||
AsciiBytes appended = bc.append("D");
|
||||
assertThat(bc.toString(), equalTo("BC"));
|
||||
assertThat(appended.toString(), equalTo("BCD"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendBytes() throws Exception {
|
||||
AsciiBytes bc = new AsciiBytes(new byte[] { 65, 66, 67, 68 }, 1, 2);
|
||||
AsciiBytes appended = bc.append(new byte[] { 68 });
|
||||
assertThat(bc.toString(), equalTo("BC"));
|
||||
assertThat(appended.toString(), equalTo("BCD"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashCodeAndEquals() throws Exception {
|
||||
AsciiBytes abcd = new AsciiBytes(new byte[] { 65, 66, 67, 68 });
|
||||
AsciiBytes bc = new AsciiBytes(new byte[] { 66, 67 });
|
||||
AsciiBytes bc_substring = new AsciiBytes(new byte[] { 65, 66, 67, 68 })
|
||||
.substring(1, 3);
|
||||
AsciiBytes bc_string = new AsciiBytes("BC");
|
||||
assertThat(bc.hashCode(), equalTo(bc.hashCode()));
|
||||
assertThat(bc.hashCode(), equalTo(bc_substring.hashCode()));
|
||||
assertThat(bc.hashCode(), equalTo(bc_string.hashCode()));
|
||||
assertThat(bc, equalTo(bc));
|
||||
assertThat(bc, equalTo(bc_substring));
|
||||
assertThat(bc, equalTo(bc_string));
|
||||
|
||||
assertThat(bc.hashCode(), not(equalTo(abcd.hashCode())));
|
||||
assertThat(bc, not(equalTo(abcd)));
|
||||
}
|
||||
}
|
||||
@@ -33,10 +33,9 @@ import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.boot.loader.AsciiBytes;
|
||||
import org.springframework.boot.loader.TestJarCreator;
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.Archive.Entry;
|
||||
import org.springframework.boot.loader.archive.ExplodedArchive;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
@@ -131,8 +130,8 @@ public class ExplodedArchiveTests {
|
||||
Archive filteredArchive = this.archive
|
||||
.getFilteredArchive(new Archive.EntryRenameFilter() {
|
||||
@Override
|
||||
public String apply(String entryName, Entry entry) {
|
||||
if (entryName.equals("1.dat")) {
|
||||
public AsciiBytes apply(AsciiBytes entryName, Entry entry) {
|
||||
if (entryName.toString().equals("1.dat")) {
|
||||
return entryName;
|
||||
}
|
||||
return null;
|
||||
@@ -149,7 +148,7 @@ public class ExplodedArchiveTests {
|
||||
private Map<String, Archive.Entry> getEntriesMap(Archive archive) {
|
||||
Map<String, Archive.Entry> entries = new HashMap<String, Archive.Entry>();
|
||||
for (Archive.Entry entry : archive.getEntries()) {
|
||||
entries.put(entry.getName(), entry);
|
||||
entries.put(entry.getName().toString(), entry);
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
@@ -25,9 +25,8 @@ import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.boot.loader.AsciiBytes;
|
||||
import org.springframework.boot.loader.TestJarCreator;
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.JarFileArchive;
|
||||
import org.springframework.boot.loader.archive.Archive.Entry;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
@@ -86,8 +85,8 @@ public class JarFileArchiveTests {
|
||||
Archive filteredArchive = this.archive
|
||||
.getFilteredArchive(new Archive.EntryRenameFilter() {
|
||||
@Override
|
||||
public String apply(String entryName, Entry entry) {
|
||||
if (entryName.equals("1.dat")) {
|
||||
public AsciiBytes apply(AsciiBytes entryName, Entry entry) {
|
||||
if (entryName.toString().equals("1.dat")) {
|
||||
return entryName;
|
||||
}
|
||||
return null;
|
||||
@@ -100,7 +99,7 @@ public class JarFileArchiveTests {
|
||||
private Map<String, Archive.Entry> getEntriesMap(Archive archive) {
|
||||
Map<String, Archive.Entry> entries = new HashMap<String, Archive.Entry>();
|
||||
for (Archive.Entry entry : archive.getEntries()) {
|
||||
entries.put(entry.getName(), entry);
|
||||
entries.put(entry.getName().toString(), entry);
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.boot.loader.data;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.loader.data.RandomAccessData.ResourceAccess;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
@@ -33,7 +34,8 @@ public class ByteArrayRandomAccessDataTest {
|
||||
public void testGetInputStream() throws Exception {
|
||||
byte[] bytes = new byte[] { 0, 1, 2, 3, 4, 5 };
|
||||
RandomAccessData data = new ByteArrayRandomAccessData(bytes);
|
||||
assertThat(FileCopyUtils.copyToByteArray(data.getInputStream()), equalTo(bytes));
|
||||
assertThat(FileCopyUtils.copyToByteArray(data
|
||||
.getInputStream(ResourceAccess.PER_READ)), equalTo(bytes));
|
||||
assertThat(data.getSize(), equalTo((long) bytes.length));
|
||||
}
|
||||
|
||||
@@ -42,8 +44,8 @@ public class ByteArrayRandomAccessDataTest {
|
||||
byte[] bytes = new byte[] { 0, 1, 2, 3, 4, 5 };
|
||||
RandomAccessData data = new ByteArrayRandomAccessData(bytes);
|
||||
data = data.getSubsection(1, 4).getSubsection(1, 2);
|
||||
assertThat(FileCopyUtils.copyToByteArray(data.getInputStream()),
|
||||
equalTo(new byte[] { 2, 3 }));
|
||||
assertThat(FileCopyUtils.copyToByteArray(data
|
||||
.getInputStream(ResourceAccess.PER_READ)), equalTo(new byte[] { 2, 3 }));
|
||||
assertThat(data.getSize(), equalTo(2L));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package org.springframework.boot.loader.data;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
@@ -40,8 +37,10 @@ import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.boot.loader.ByteArrayStartsWith;
|
||||
import org.springframework.boot.loader.data.RandomAccessData;
|
||||
import org.springframework.boot.loader.data.RandomAccessDataFile;
|
||||
import org.springframework.boot.loader.data.RandomAccessData.ResourceAccess;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link RandomAccessDataFile}.
|
||||
@@ -72,73 +71,73 @@ public class RandomAccessDataFileTests {
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
this.tempFile = temporaryFolder.newFile();
|
||||
FileOutputStream outputStream = new FileOutputStream(tempFile);
|
||||
this.tempFile = this.temporaryFolder.newFile();
|
||||
FileOutputStream outputStream = new FileOutputStream(this.tempFile);
|
||||
outputStream.write(BYTES);
|
||||
outputStream.close();
|
||||
this.file = new RandomAccessDataFile(tempFile);
|
||||
this.inputStream = file.getInputStream();
|
||||
this.file = new RandomAccessDataFile(this.tempFile);
|
||||
this.inputStream = this.file.getInputStream(ResourceAccess.PER_READ);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() throws Exception {
|
||||
inputStream.close();
|
||||
file.close();
|
||||
this.inputStream.close();
|
||||
this.file.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileNotNull() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.equals("File must not be null");
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.equals("File must not be null");
|
||||
new RandomAccessDataFile(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileExists() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.equals("File must exist");
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.equals("File must exist");
|
||||
new RandomAccessDataFile(new File("/does/not/exist"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileNotNullWithConcurrentReads() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.equals("File must not be null");
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.equals("File must not be null");
|
||||
new RandomAccessDataFile(null, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileExistsWithConcurrentReads() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.equals("File must exist");
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.equals("File must exist");
|
||||
new RandomAccessDataFile(new File("/does/not/exist"), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamRead() throws Exception {
|
||||
for (int i = 0; i <= 255; i++) {
|
||||
assertThat(inputStream.read(), equalTo(i));
|
||||
assertThat(this.inputStream.read(), equalTo(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadNullBytes() throws Exception {
|
||||
thrown.expect(NullPointerException.class);
|
||||
thrown.expectMessage("Bytes must not be null");
|
||||
inputStream.read(null);
|
||||
this.thrown.expect(NullPointerException.class);
|
||||
this.thrown.expectMessage("Bytes must not be null");
|
||||
this.inputStream.read(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void intputStreamReadNullBytesWithOffset() throws Exception {
|
||||
thrown.expect(NullPointerException.class);
|
||||
thrown.expectMessage("Bytes must not be null");
|
||||
inputStream.read(null, 0, 1);
|
||||
this.thrown.expect(NullPointerException.class);
|
||||
this.thrown.expectMessage("Bytes must not be null");
|
||||
this.inputStream.read(null, 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadBytes() throws Exception {
|
||||
byte[] b = new byte[256];
|
||||
int amountRead = inputStream.read(b);
|
||||
int amountRead = this.inputStream.read(b);
|
||||
assertThat(b, equalTo(BYTES));
|
||||
assertThat(amountRead, equalTo(256));
|
||||
}
|
||||
@@ -146,8 +145,8 @@ public class RandomAccessDataFileTests {
|
||||
@Test
|
||||
public void inputSteamReadOffsetBytes() throws Exception {
|
||||
byte[] b = new byte[7];
|
||||
inputStream.skip(1);
|
||||
int amountRead = inputStream.read(b, 2, 3);
|
||||
this.inputStream.skip(1);
|
||||
int amountRead = this.inputStream.read(b, 2, 3);
|
||||
assertThat(b, equalTo(new byte[] { 0, 0, 1, 2, 3, 0, 0 }));
|
||||
assertThat(amountRead, equalTo(3));
|
||||
}
|
||||
@@ -155,91 +154,91 @@ public class RandomAccessDataFileTests {
|
||||
@Test
|
||||
public void inputStreamReadMoreBytesThanAvailable() throws Exception {
|
||||
byte[] b = new byte[257];
|
||||
int amountRead = inputStream.read(b);
|
||||
int amountRead = this.inputStream.read(b);
|
||||
assertThat(b, startsWith(BYTES));
|
||||
assertThat(amountRead, equalTo(256));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadPastEnd() throws Exception {
|
||||
inputStream.skip(255);
|
||||
assertThat(inputStream.read(), equalTo(0xFF));
|
||||
assertThat(inputStream.read(), equalTo(-1));
|
||||
assertThat(inputStream.read(), equalTo(-1));
|
||||
this.inputStream.skip(255);
|
||||
assertThat(this.inputStream.read(), equalTo(0xFF));
|
||||
assertThat(this.inputStream.read(), equalTo(-1));
|
||||
assertThat(this.inputStream.read(), equalTo(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadZeroLength() throws Exception {
|
||||
byte[] b = new byte[] { 0x0F };
|
||||
int amountRead = inputStream.read(b, 0, 0);
|
||||
int amountRead = this.inputStream.read(b, 0, 0);
|
||||
assertThat(b, equalTo(new byte[] { 0x0F }));
|
||||
assertThat(amountRead, equalTo(0));
|
||||
assertThat(inputStream.read(), equalTo(0));
|
||||
assertThat(this.inputStream.read(), equalTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamSkip() throws Exception {
|
||||
long amountSkipped = inputStream.skip(4);
|
||||
assertThat(inputStream.read(), equalTo(4));
|
||||
long amountSkipped = this.inputStream.skip(4);
|
||||
assertThat(this.inputStream.read(), equalTo(4));
|
||||
assertThat(amountSkipped, equalTo(4L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamSkipMoreThanAvailable() throws Exception {
|
||||
long amountSkipped = inputStream.skip(257);
|
||||
assertThat(inputStream.read(), equalTo(-1));
|
||||
long amountSkipped = this.inputStream.skip(257);
|
||||
assertThat(this.inputStream.read(), equalTo(-1));
|
||||
assertThat(amountSkipped, equalTo(256L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamSkipPastEnd() throws Exception {
|
||||
inputStream.skip(256);
|
||||
long amountSkipped = inputStream.skip(1);
|
||||
this.inputStream.skip(256);
|
||||
long amountSkipped = this.inputStream.skip(1);
|
||||
assertThat(amountSkipped, equalTo(0L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionNegativeOffset() throws Exception {
|
||||
thrown.expect(IndexOutOfBoundsException.class);
|
||||
file.getSubsection(-1, 1);
|
||||
this.thrown.expect(IndexOutOfBoundsException.class);
|
||||
this.file.getSubsection(-1, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionNegativeLength() throws Exception {
|
||||
thrown.expect(IndexOutOfBoundsException.class);
|
||||
file.getSubsection(0, -1);
|
||||
this.thrown.expect(IndexOutOfBoundsException.class);
|
||||
this.file.getSubsection(0, -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionZeroLength() throws Exception {
|
||||
RandomAccessData subsection = file.getSubsection(0, 0);
|
||||
assertThat(subsection.getInputStream().read(), equalTo(-1));
|
||||
RandomAccessData subsection = this.file.getSubsection(0, 0);
|
||||
assertThat(subsection.getInputStream(ResourceAccess.PER_READ).read(), equalTo(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionTooBig() throws Exception {
|
||||
file.getSubsection(0, 256);
|
||||
thrown.expect(IndexOutOfBoundsException.class);
|
||||
file.getSubsection(0, 257);
|
||||
this.file.getSubsection(0, 256);
|
||||
this.thrown.expect(IndexOutOfBoundsException.class);
|
||||
this.file.getSubsection(0, 257);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionTooBigWithOffset() throws Exception {
|
||||
file.getSubsection(1, 255);
|
||||
thrown.expect(IndexOutOfBoundsException.class);
|
||||
file.getSubsection(1, 256);
|
||||
this.file.getSubsection(1, 255);
|
||||
this.thrown.expect(IndexOutOfBoundsException.class);
|
||||
this.file.getSubsection(1, 256);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsection() throws Exception {
|
||||
RandomAccessData subsection = file.getSubsection(1, 1);
|
||||
assertThat(subsection.getInputStream().read(), equalTo(1));
|
||||
RandomAccessData subsection = this.file.getSubsection(1, 1);
|
||||
assertThat(subsection.getInputStream(ResourceAccess.PER_READ).read(), equalTo(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadPastSubsection() throws Exception {
|
||||
RandomAccessData subsection = file.getSubsection(1, 2);
|
||||
InputStream inputStream = subsection.getInputStream();
|
||||
RandomAccessData subsection = this.file.getSubsection(1, 2);
|
||||
InputStream inputStream = subsection.getInputStream(ResourceAccess.PER_READ);
|
||||
assertThat(inputStream.read(), equalTo(1));
|
||||
assertThat(inputStream.read(), equalTo(2));
|
||||
assertThat(inputStream.read(), equalTo(-1));
|
||||
@@ -247,8 +246,8 @@ public class RandomAccessDataFileTests {
|
||||
|
||||
@Test
|
||||
public void inputStreamReadBytesPastSubsection() throws Exception {
|
||||
RandomAccessData subsection = file.getSubsection(1, 2);
|
||||
InputStream inputStream = subsection.getInputStream();
|
||||
RandomAccessData subsection = this.file.getSubsection(1, 2);
|
||||
InputStream inputStream = subsection.getInputStream(ResourceAccess.PER_READ);
|
||||
byte[] b = new byte[3];
|
||||
int amountRead = inputStream.read(b);
|
||||
assertThat(b, equalTo(new byte[] { 1, 2, 0 }));
|
||||
@@ -257,20 +256,20 @@ public class RandomAccessDataFileTests {
|
||||
|
||||
@Test
|
||||
public void inputStreamSkipPastSubsection() throws Exception {
|
||||
RandomAccessData subsection = file.getSubsection(1, 2);
|
||||
InputStream inputStream = subsection.getInputStream();
|
||||
RandomAccessData subsection = this.file.getSubsection(1, 2);
|
||||
InputStream inputStream = subsection.getInputStream(ResourceAccess.PER_READ);
|
||||
assertThat(inputStream.skip(3), equalTo(2L));
|
||||
assertThat(inputStream.read(), equalTo(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamSkipNegative() throws Exception {
|
||||
assertThat(inputStream.skip(-1), equalTo(0L));
|
||||
assertThat(this.inputStream.skip(-1), equalTo(0L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFile() throws Exception {
|
||||
assertThat(file.getFile(), equalTo(tempFile));
|
||||
assertThat(this.file.getFile(), equalTo(this.tempFile));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -282,8 +281,9 @@ public class RandomAccessDataFileTests {
|
||||
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
InputStream subsectionInputStream = file.getSubsection(0, 256)
|
||||
.getInputStream();
|
||||
InputStream subsectionInputStream = RandomAccessDataFileTests.this.file
|
||||
.getSubsection(0, 256)
|
||||
.getInputStream(ResourceAccess.PER_READ);
|
||||
byte[] b = new byte[256];
|
||||
subsectionInputStream.read(b);
|
||||
return Arrays.equals(b, BYTES);
|
||||
@@ -297,11 +297,11 @@ public class RandomAccessDataFileTests {
|
||||
|
||||
@Test
|
||||
public void close() throws Exception {
|
||||
file.getInputStream().read();
|
||||
file.close();
|
||||
this.file.getInputStream(ResourceAccess.PER_READ).read();
|
||||
this.file.close();
|
||||
Field filePoolField = RandomAccessDataFile.class.getDeclaredField("filePool");
|
||||
filePoolField.setAccessible(true);
|
||||
Object filePool = filePoolField.get(file);
|
||||
Object filePool = filePoolField.get(this.file);
|
||||
Field filesField = filePool.getClass().getDeclaredField("files");
|
||||
filesField.setAccessible(true);
|
||||
Queue<?> queue = (Queue<?>) filesField.get(filePool);
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.
|
||||
* 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 org.springframework.boot.loader.jar;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.boot.loader.data.RandomAccessDataFile;
|
||||
import org.springframework.boot.loader.jar.RandomAccessDataJarEntry;
|
||||
import org.springframework.boot.loader.jar.RandomAccessDataJarInputStream;
|
||||
|
||||
/**
|
||||
* Tests for {@link RandomAccessDataJarInputStream}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class RandomAccessDataJarInputStreamTests {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
private File file;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
this.file = temporaryFolder.newFile();
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(file));
|
||||
try {
|
||||
writeDataEntry(zipOutputStream, "a", new byte[10]);
|
||||
writeDataEntry(zipOutputStream, "b", new byte[20]);
|
||||
}
|
||||
finally {
|
||||
zipOutputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeDataEntry(ZipOutputStream zipOutputStream, String name, byte[] data)
|
||||
throws IOException {
|
||||
ZipEntry entry = new ZipEntry(name);
|
||||
entry.setMethod(ZipEntry.STORED);
|
||||
entry.setSize(data.length);
|
||||
entry.setCompressedSize(data.length);
|
||||
CRC32 crc32 = new CRC32();
|
||||
crc32.update(data);
|
||||
entry.setCrc(crc32.getValue());
|
||||
zipOutputStream.putNextEntry(entry);
|
||||
zipOutputStream.write(data);
|
||||
zipOutputStream.closeEntry();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entryData() throws Exception {
|
||||
RandomAccessDataJarInputStream z = new RandomAccessDataJarInputStream(
|
||||
new RandomAccessDataFile(file));
|
||||
try {
|
||||
RandomAccessDataJarEntry entry1 = z.getNextEntry();
|
||||
RandomAccessDataJarEntry entry2 = z.getNextEntry();
|
||||
assertThat(entry1.getName(), equalTo("a"));
|
||||
assertThat(entry1.getData().getSize(), equalTo(10L));
|
||||
assertThat(entry2.getName(), equalTo("b"));
|
||||
assertThat(entry2.getData().getSize(), equalTo(20L));
|
||||
assertThat(z.getNextEntry(), nullValue());
|
||||
}
|
||||
finally {
|
||||
z.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,11 +20,9 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
@@ -33,6 +31,7 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.boot.loader.AsciiBytes;
|
||||
import org.springframework.boot.loader.TestJarCreator;
|
||||
import org.springframework.boot.loader.data.RandomAccessDataFile;
|
||||
|
||||
@@ -42,12 +41,13 @@ import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link RandomAccessJarFile}.
|
||||
* Tests for {@link JarFile}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@@ -61,27 +61,18 @@ public class RandomAccessJarFileTests {
|
||||
|
||||
private File rootJarFile;
|
||||
|
||||
private RandomAccessJarFile jarFile;
|
||||
private JarFile jarFile;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
this.rootJarFile = this.temporaryFolder.newFile();
|
||||
TestJarCreator.createTestJar(this.rootJarFile);
|
||||
this.jarFile = new RandomAccessJarFile(this.rootJarFile);
|
||||
this.jarFile = new JarFile(this.rootJarFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromFile() throws Exception {
|
||||
RandomAccessJarFile jarFile = new RandomAccessJarFile(this.rootJarFile);
|
||||
assertThat(jarFile.getName(), notNullValue(String.class));
|
||||
jarFile.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromRandomAccessDataFile() throws Exception {
|
||||
RandomAccessDataFile randomAccessDataFile = new RandomAccessDataFile(
|
||||
this.rootJarFile, 1);
|
||||
RandomAccessJarFile jarFile = new RandomAccessJarFile(randomAccessDataFile);
|
||||
JarFile jarFile = new JarFile(this.rootJarFile);
|
||||
assertThat(jarFile.getName(), notNullValue(String.class));
|
||||
jarFile.close();
|
||||
}
|
||||
@@ -101,7 +92,7 @@ public class RandomAccessJarFileTests {
|
||||
|
||||
@Test
|
||||
public void getEntries() throws Exception {
|
||||
Enumeration<JarEntry> entries = this.jarFile.entries();
|
||||
Enumeration<java.util.jar.JarEntry> entries = this.jarFile.entries();
|
||||
assertThat(entries.nextElement().getName(), equalTo("META-INF/"));
|
||||
assertThat(entries.nextElement().getName(), equalTo("META-INF/MANIFEST.MF"));
|
||||
assertThat(entries.nextElement().getName(), equalTo("1.dat"));
|
||||
@@ -114,7 +105,7 @@ public class RandomAccessJarFileTests {
|
||||
|
||||
@Test
|
||||
public void getJarEntry() throws Exception {
|
||||
JarEntry entry = this.jarFile.getJarEntry("1.dat");
|
||||
java.util.jar.JarEntry entry = this.jarFile.getJarEntry("1.dat");
|
||||
assertThat(entry, notNullValue(ZipEntry.class));
|
||||
assertThat(entry.getName(), equalTo("1.dat"));
|
||||
}
|
||||
@@ -143,7 +134,7 @@ public class RandomAccessJarFileTests {
|
||||
public void close() throws Exception {
|
||||
RandomAccessDataFile randomAccessDataFile = spy(new RandomAccessDataFile(
|
||||
this.rootJarFile, 1));
|
||||
RandomAccessJarFile jarFile = new RandomAccessJarFile(randomAccessDataFile);
|
||||
JarFile jarFile = new JarFile(randomAccessDataFile);
|
||||
jarFile.close();
|
||||
verify(randomAccessDataFile).close();
|
||||
}
|
||||
@@ -154,7 +145,7 @@ public class RandomAccessJarFileTests {
|
||||
assertThat(url.toString(), equalTo("jar:file:" + this.rootJarFile.getPath()
|
||||
+ "!/"));
|
||||
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
|
||||
assertThat(jarURLConnection.getJarFile(), sameInstance((JarFile) this.jarFile));
|
||||
assertThat(jarURLConnection.getJarFile(), sameInstance(this.jarFile));
|
||||
assertThat(jarURLConnection.getJarEntry(), nullValue());
|
||||
assertThat(jarURLConnection.getContentLength(), greaterThan(1));
|
||||
assertThat(jarURLConnection.getContent(), sameInstance((Object) this.jarFile));
|
||||
@@ -167,7 +158,7 @@ public class RandomAccessJarFileTests {
|
||||
assertThat(url.toString(), equalTo("jar:file:" + this.rootJarFile.getPath()
|
||||
+ "!/1.dat"));
|
||||
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
|
||||
assertThat(jarURLConnection.getJarFile(), sameInstance((JarFile) this.jarFile));
|
||||
assertThat(jarURLConnection.getJarFile(), sameInstance(this.jarFile));
|
||||
assertThat(jarURLConnection.getJarEntry(),
|
||||
sameInstance(this.jarFile.getJarEntry("1.dat")));
|
||||
assertThat(jarURLConnection.getContentLength(), equalTo(1));
|
||||
@@ -203,10 +194,10 @@ public class RandomAccessJarFileTests {
|
||||
|
||||
@Test
|
||||
public void getNestedJarFile() throws Exception {
|
||||
RandomAccessJarFile nestedJarFile = this.jarFile.getNestedJarFile(this.jarFile
|
||||
JarFile nestedJarFile = this.jarFile.getNestedJarFile(this.jarFile
|
||||
.getEntry("nested.jar"));
|
||||
|
||||
Enumeration<JarEntry> entries = nestedJarFile.entries();
|
||||
Enumeration<java.util.jar.JarEntry> entries = nestedJarFile.entries();
|
||||
assertThat(entries.nextElement().getName(), equalTo("META-INF/"));
|
||||
assertThat(entries.nextElement().getName(), equalTo("META-INF/MANIFEST.MF"));
|
||||
assertThat(entries.nextElement().getName(), equalTo("3.dat"));
|
||||
@@ -222,15 +213,15 @@ public class RandomAccessJarFileTests {
|
||||
assertThat(url.toString(), equalTo("jar:file:" + this.rootJarFile.getPath()
|
||||
+ "!/nested.jar!/"));
|
||||
assertThat(((JarURLConnection) url.openConnection()).getJarFile(),
|
||||
sameInstance((JarFile) nestedJarFile));
|
||||
sameInstance(nestedJarFile));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNestedJarDirectory() throws Exception {
|
||||
RandomAccessJarFile nestedJarFile = this.jarFile.getNestedJarFile(this.jarFile
|
||||
.getEntry("d/"));
|
||||
JarFile nestedJarFile = this.jarFile
|
||||
.getNestedJarFile(this.jarFile.getEntry("d/"));
|
||||
|
||||
Enumeration<JarEntry> entries = nestedJarFile.entries();
|
||||
Enumeration<java.util.jar.JarEntry> entries = nestedJarFile.entries();
|
||||
assertThat(entries.nextElement().getName(), equalTo("9.dat"));
|
||||
assertThat(entries.hasMoreElements(), equalTo(false));
|
||||
|
||||
@@ -243,7 +234,7 @@ public class RandomAccessJarFileTests {
|
||||
assertThat(url.toString(), equalTo("jar:file:" + this.rootJarFile.getPath()
|
||||
+ "!/d!/"));
|
||||
assertThat(((JarURLConnection) url.openConnection()).getJarFile(),
|
||||
sameInstance((JarFile) nestedJarFile));
|
||||
sameInstance(nestedJarFile));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -263,17 +254,16 @@ public class RandomAccessJarFileTests {
|
||||
|
||||
@Test
|
||||
public void getFilteredJarFile() throws Exception {
|
||||
RandomAccessJarFile filteredJarFile = this.jarFile
|
||||
.getFilteredJarFile(new JarEntryFilter() {
|
||||
@Override
|
||||
public String apply(String entryName, JarEntry entry) {
|
||||
if (entryName.equals("1.dat")) {
|
||||
return "x.dat";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
Enumeration<JarEntry> entries = filteredJarFile.entries();
|
||||
JarFile filteredJarFile = this.jarFile.getFilteredJarFile(new JarEntryFilter() {
|
||||
@Override
|
||||
public AsciiBytes apply(AsciiBytes entryName, JarEntryData entry) {
|
||||
if (entryName.toString().equals("1.dat")) {
|
||||
return new AsciiBytes("x.dat");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
Enumeration<java.util.jar.JarEntry> entries = filteredJarFile.entries();
|
||||
assertThat(entries.nextElement().getName(), equalTo("x.dat"));
|
||||
assertThat(entries.hasMoreElements(), equalTo(false));
|
||||
|
||||
@@ -289,4 +279,31 @@ public class RandomAccessJarFileTests {
|
||||
assertThat(this.jarFile.getNestedJarFile(this.jarFile.getEntry("nested.jar"))
|
||||
.toString(), equalTo(this.rootJarFile.getPath() + "!/nested.jar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifySignedJar() throws Exception {
|
||||
String classpath = System.getProperty("java.class.path");
|
||||
String[] entries = classpath.split(System.getProperty("path.separator"));
|
||||
String signedJarFile = null;
|
||||
for (String entry : entries) {
|
||||
if (entry.contains("bcprov")) {
|
||||
signedJarFile = entry;
|
||||
}
|
||||
}
|
||||
assertNotNull(signedJarFile);
|
||||
java.util.jar.JarFile jarFile = new JarFile(new File(signedJarFile));
|
||||
jarFile.getManifest();
|
||||
Enumeration<JarEntry> jarEntries = jarFile.entries();
|
||||
while (jarEntries.hasMoreElements()) {
|
||||
JarEntry jarEntry = jarEntries.nextElement();
|
||||
InputStream inputStream = jarFile.getInputStream(jarEntry);
|
||||
inputStream.skip(Long.MAX_VALUE);
|
||||
inputStream.close();
|
||||
if (!jarEntry.getName().startsWith("META-INF") && !jarEntry.isDirectory()
|
||||
&& !jarEntry.getName().endsWith("TigerDigest.class")) {
|
||||
assertNotNull("Missing cert " + jarEntry.getName(),
|
||||
jarEntry.getCertificates());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user