This is an automated email from the ASF dual-hosted git repository. reta pushed a commit to branch 3.5.x-fixes in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 9a3018b2e1d18e6bb0fd3ba1b5e9877dd4ddbbbc Author: Andriy Redko <[email protected]> AuthorDate: Thu Mar 13 17:24:33 2025 -0400 CXF-9118: DelayedCachedOutputStreamCleaner may expire streams prematurely (#2317) (cherry picked from commit f70c8a7de9c49c25ebd610721d22fa2a206d7f41) (cherry picked from commit 3717ebbb75cf30fffcfb7608dd75394d62363b79) (cherry picked from commit d13c085ee5d68576baba192f61c74e88263c691c) --- .../cxf/io/DelayedCachedOutputStreamCleaner.java | 2 +- .../io/DelayedCachedOutputStreamCleanerTest.java | 25 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/apache/cxf/io/DelayedCachedOutputStreamCleaner.java b/core/src/main/java/org/apache/cxf/io/DelayedCachedOutputStreamCleaner.java index 524adc0a69..b52d82b71d 100644 --- a/core/src/main/java/org/apache/cxf/io/DelayedCachedOutputStreamCleaner.java +++ b/core/src/main/java/org/apache/cxf/io/DelayedCachedOutputStreamCleaner.java @@ -145,7 +145,7 @@ public final class DelayedCachedOutputStreamCleaner implements CachedOutputStrea DelayedCloseable(final Closeable closeable, final long delay) { this.closeable = closeable; - this.expireAt = System.nanoTime() + delay; + this.expireAt = System.nanoTime() + TimeUnit.NANOSECONDS.convert(delay, TimeUnit.MILLISECONDS); } @Override diff --git a/core/src/test/java/org/apache/cxf/io/DelayedCachedOutputStreamCleanerTest.java b/core/src/test/java/org/apache/cxf/io/DelayedCachedOutputStreamCleanerTest.java index 3c6c6a82f7..562b3a18f2 100644 --- a/core/src/test/java/org/apache/cxf/io/DelayedCachedOutputStreamCleanerTest.java +++ b/core/src/test/java/org/apache/cxf/io/DelayedCachedOutputStreamCleanerTest.java @@ -206,6 +206,31 @@ public class DelayedCachedOutputStreamCleanerTest { assertNoopCleaner(cleaner); } + + @Test + public void testDelayedClean() throws InterruptedException { + final AtomicInteger latch = new AtomicInteger(); + final Closeable closeable1 = () -> latch.incrementAndGet(); + final Closeable closeable2 = () -> latch.incrementAndGet(); + + /* Delay of 5 seconds */ + final Map<String, Object> properties = Collections.singletonMap(CachedConstants.CLEANER_DELAY_BUS_PROP, 2500); + bus = new ExtensionManagerBus(new HashMap<>(), properties); + + final CachedOutputStreamCleaner cleaner = bus.getExtension(CachedOutputStreamCleaner.class); + cleaner.register(closeable1); + + Thread.sleep(2000); + cleaner.register(closeable2); + + // Await for Closeable::close to be called on schedule + await().atMost(3, TimeUnit.SECONDS).untilAtomic(latch, equalTo(1)); + + // Await for Closeable::close to be called on schedule + await().atMost(5, TimeUnit.SECONDS).untilAtomic(latch, equalTo(2)); + + assertThat(cleaner, instanceOf(DelayedCachedOutputStreamCleaner.class)); + } private void assertNoopCleaner(final CachedOutputStreamCleaner cleaner) { final AtomicBoolean latch = new AtomicBoolean(false);
