Skip to content

Commit fff8350

Browse files
Copilotslachiewicz
andcommitted
Fix FileNotFoundException for temp files by properly closing DeferredFileOutputStream
Co-authored-by: slachiewicz <[email protected]>
1 parent 5f0d6ac commit fff8350

File tree

3 files changed

+118
-0
lines changed

3 files changed

+118
-0
lines changed

src/main/java/org/codehaus/plexus/components/io/resources/Deferred.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public Deferred(final PlexusIoResource resource, PlexusIoResourceCollection owne
5050
InputStream inputStream = owner.getInputStream(resource);
5151
IOUtils.copy(inputStream, dfos);
5252
IOUtils.closeQuietly(inputStream);
53+
dfos.close();
5354
}
5455
}
5556

src/main/java/org/codehaus/plexus/components/io/resources/PlexusIoFileResource.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ private static DeferredFileOutputStream asDeferredStream(
113113
IOUtils.copy(transformed, dfos);
114114
IOUtils.closeQuietly(inputStream);
115115
IOUtils.closeQuietly(transformed);
116+
dfos.close();
116117
return dfos;
117118
}
118119

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package org.codehaus.plexus.components.io.resources;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.io.InputStream;
6+
import java.io.OutputStream;
7+
import java.nio.charset.StandardCharsets;
8+
import java.nio.file.Files;
9+
10+
import org.apache.commons.io.IOUtils;
11+
import org.codehaus.plexus.components.io.attributes.FileAttributes;
12+
import org.codehaus.plexus.components.io.functions.InputStreamTransformer;
13+
import org.junit.jupiter.api.Test;
14+
import org.junit.jupiter.api.io.TempDir;
15+
16+
import static org.junit.jupiter.api.Assertions.*;
17+
18+
/**
19+
* Tests for PlexusIoFileResource with DeferredFileOutputStream scenarios.
20+
* This specifically tests the fix for issue #118 where temp files were deleted
21+
* before they could be accessed, causing FileNotFoundException.
22+
*/
23+
public class PlexusIoFileResourceDeferredTest {
24+
25+
@TempDir
26+
File tempDir;
27+
28+
@Test
29+
void testFileResourceWithTransformerCanReadContentsMultipleTimes() throws IOException {
30+
// Create a test file with content larger than typical buffer size
31+
File testFile = new File(tempDir, "test-file.txt");
32+
byte[] largeContent = new byte[10000]; // 10KB
33+
for (int i = 0; i < largeContent.length; i++) {
34+
largeContent[i] = (byte) ('A' + (i % 26));
35+
}
36+
Files.write(testFile.toPath(), largeContent);
37+
38+
// Create a transformer that modifies the content
39+
InputStreamTransformer transformer = (resource, inputStream) -> {
40+
// Simple transformer that reads and returns the same content
41+
return inputStream;
42+
};
43+
44+
// Create PlexusIoFileResource with transformer
45+
PlexusIoFileResource resource =
46+
new PlexusIoFileResource(testFile, testFile.getName(), new FileAttributes(testFile), null, transformer);
47+
48+
// First read - this should work and not delete the temp file
49+
try (InputStream is1 = resource.getContents()) {
50+
byte[] read1 = IOUtils.toByteArray(is1);
51+
assertEquals(largeContent.length, read1.length);
52+
}
53+
54+
// Second read - this should also work if the temp file wasn't prematurely deleted
55+
// This is the key test - without the fix, this would throw FileNotFoundException
56+
try (InputStream is2 = resource.getContents()) {
57+
byte[] read2 = IOUtils.toByteArray(is2);
58+
assertEquals(largeContent.length, read2.length);
59+
}
60+
}
61+
62+
@Test
63+
void testFileResourceWithTransformerLargeFile() throws IOException {
64+
// Create a large file that exceeds the DeferredFileOutputStream threshold (5MB)
65+
File testFile = new File(tempDir, "large-test-file.bin");
66+
byte[] chunk = new byte[1024 * 1024]; // 1MB chunks
67+
for (int i = 0; i < chunk.length; i++) {
68+
chunk[i] = (byte) i;
69+
}
70+
71+
// Write 6MB to exceed the 5MB threshold
72+
try (OutputStream os = Files.newOutputStream(testFile.toPath())) {
73+
for (int i = 0; i < 6; i++) {
74+
os.write(chunk);
75+
}
76+
}
77+
78+
InputStreamTransformer transformer = (resource, inputStream) -> inputStream;
79+
80+
PlexusIoFileResource resource =
81+
new PlexusIoFileResource(testFile, testFile.getName(), new FileAttributes(testFile), null, transformer);
82+
83+
// Verify we can read the content - this tests that the temp file
84+
// created by DeferredFileOutputStream is properly accessible
85+
long size = resource.getSize();
86+
assertTrue(size > 5_000_000, "File should be larger than 5MB threshold");
87+
88+
try (InputStream is = resource.getContents()) {
89+
assertNotNull(is);
90+
byte[] firstBytes = new byte[1024];
91+
int read = is.read(firstBytes);
92+
assertEquals(1024, read);
93+
}
94+
}
95+
96+
@Test
97+
void testFileResourceWithTransformerSmallFile() throws IOException {
98+
// Test with a small file that stays in memory (below 5MB threshold)
99+
File testFile = new File(tempDir, "small-test-file.txt");
100+
String content = "Hello, World!";
101+
Files.write(testFile.toPath(), content.getBytes(StandardCharsets.UTF_8));
102+
103+
InputStreamTransformer transformer = (resource, inputStream) -> inputStream;
104+
105+
PlexusIoFileResource resource =
106+
new PlexusIoFileResource(testFile, testFile.getName(), new FileAttributes(testFile), null, transformer);
107+
108+
// Multiple reads should work for small files too
109+
for (int i = 0; i < 3; i++) {
110+
try (InputStream is = resource.getContents()) {
111+
String readContent = IOUtils.toString(is, StandardCharsets.UTF_8);
112+
assertEquals(content, readContent);
113+
}
114+
}
115+
}
116+
}

0 commit comments

Comments
 (0)