Skip to content

Commit 83208c8

Browse files
committed
Multiplex now notifies on flush so that subscribers can wait on the
multiplex object and act after flushes.
1 parent 92ffa6d commit 83208c8

File tree

1 file changed

+40
-10
lines changed

1 file changed

+40
-10
lines changed

interceptor/src/main/java/com/github/technosf/slf4/interceptor/util/MultiplexOutputStream.java

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,19 @@
1818
import java.io.ByteArrayOutputStream;
1919
import java.io.IOException;
2020
import java.io.OutputStream;
21+
import java.util.ArrayList;
2122
import java.util.Arrays;
23+
import java.util.Collections;
2224
import java.util.HashSet;
25+
import java.util.List;
2326
import java.util.Set;
2427

2528
/**
2629
* OutputStream Multiplexer
2730
* <p>
2831
* Multiplexes data on an output stream to subscribing other output streams.
32+
* This implementation synchronizes on {@code flush} allowing threads expecting
33+
* data on subscribing output streams to wait.
2934
*
3035
* @author technosf
3136
* @see Inspired by Brogdan Matasaru,
@@ -45,7 +50,8 @@ public class MultiplexOutputStream
4550
/**
4651
* The set of subscribing streams
4752
*/
48-
private Set<OutputStream> subscribers = new HashSet<>();
53+
private Set<OutputStream> subscribers =
54+
Collections.synchronizedSet(new HashSet<OutputStream>());
4955

5056
/**
5157
* Automatically flush output streams on writes ending with EOL char 10
@@ -97,7 +103,7 @@ public MultiplexOutputStream(OutputStream... os)
97103

98104
/**
99105
* Sets autoFlush property, causing output streams to be flushed when writes
100-
* end with character 10.
106+
* end with character 10 (LF).
101107
*
102108
* @param autoFlush
103109
* true to autoflush
@@ -177,7 +183,13 @@ public boolean hasOutputStream(OutputStream os)
177183
*/
178184
public boolean addOutputStreams(OutputStream... os)
179185
{
180-
return subscribers.addAll(Arrays.asList(os));
186+
synchronized (publisher)
187+
/*
188+
* Lock on publisher, so that IO operations are consistent
189+
*/
190+
{
191+
return subscribers.addAll(Arrays.asList(os));
192+
}
181193
}
182194

183195

@@ -190,7 +202,13 @@ public boolean addOutputStreams(OutputStream... os)
190202
*/
191203
public boolean removeOutputStreams(OutputStream... os)
192204
{
193-
return subscribers.removeAll(Arrays.asList(os));
205+
synchronized (publisher)
206+
/*
207+
* Lock on publisher, so that IO operations are consistent
208+
*/
209+
{
210+
return subscribers.removeAll(Arrays.asList(os));
211+
}
194212
}
195213

196214

@@ -244,9 +262,11 @@ public void close() throws IOException
244262

245263

246264
/**
247-
* {@inheritDoc}
265+
* {code flush} takes accumulated writes and pushes them onto subscribing
266+
* {@code OutputStream}s.
248267
* <p>
249-
* Notify's after <em>flush</em>
268+
* <em>flush</em> is synchronous and calls {@code notifyAll} once all
269+
* {@code OutputStream}s have been flushed.
250270
*
251271
* @see java.io.OutputStream#flush()
252272
*/
@@ -258,6 +278,8 @@ public synchronized void flush() throws IOException
258278
* Lock on publisher, so that IO operations are consistent
259279
*/
260280
{
281+
List<OutputStream> deadStreams = new ArrayList<>(); // Container streams found dead
282+
261283
/*
262284
* Copy the publisher contents to be flushed and clear the publisher
263285
*/
@@ -286,16 +308,24 @@ public synchronized void flush() throws IOException
286308
}
287309
catch (IOException e)
288310
/*
289-
* Assume os is closed, remove
311+
* Assume os is closed, add to dead list
290312
*/
291313
{
292-
subscribers.remove(os);
314+
deadStreams.add(os);
293315
}
294316
}
317+
318+
if (!deadStreams.isEmpty())
319+
/*
320+
* Remove dead streams
321+
*/
322+
{
323+
subscribers.remove(deadStreams);
324+
}
325+
295326
writeFlag = false;
296327
}
297-
298-
notifyAll();
328+
notifyAll(); // Notify waiting threads that a flush has occured
299329
}
300330

301331

0 commit comments

Comments
 (0)