1616
1717package org .springframework .boot .buildpack .platform .socket ;
1818
19- import java .io .FileNotFoundException ;
2019import java .io .IOException ;
2120import java .io .InputStream ;
2221import java .io .OutputStream ;
23- import java .io .RandomAccessFile ;
2422import java .net .Socket ;
23+ import java .nio .ByteBuffer ;
24+ import java .nio .channels .AsynchronousByteChannel ;
25+ import java .nio .channels .AsynchronousCloseException ;
26+ import java .nio .channels .AsynchronousFileChannel ;
27+ import java .nio .channels .Channels ;
28+ import java .nio .channels .CompletionHandler ;
29+ import java .nio .file .NoSuchFileException ;
30+ import java .nio .file .Paths ;
31+ import java .nio .file .StandardOpenOption ;
32+ import java .util .concurrent .CompletableFuture ;
33+ import java .util .concurrent .Future ;
2534import java .util .concurrent .TimeUnit ;
2635import java .util .function .Consumer ;
2736
3241 * A {@link Socket} implementation for named pipes.
3342 *
3443 * @author Phillip Webb
44+ * @author Scott Frederick
3545 * @since 2.3.0
3646 */
3747public class NamedPipeSocket extends Socket {
@@ -40,27 +50,22 @@ public class NamedPipeSocket extends Socket {
4050
4151 private static final long TIMEOUT = TimeUnit .MILLISECONDS .toNanos (1000 );
4252
43- private final RandomAccessFile file ;
44-
45- private final InputStream inputStream ;
46-
47- private final OutputStream outputStream ;
53+ private final AsynchronousFileByteChannel channel ;
4854
4955 NamedPipeSocket (String path ) throws IOException {
50- this .file = open (path );
51- this .inputStream = new NamedPipeInputStream ();
52- this .outputStream = new NamedPipeOutputStream ();
56+ this .channel = open (path );
5357 }
5458
55- private static RandomAccessFile open (String path ) throws IOException {
59+ private AsynchronousFileByteChannel open (String path ) throws IOException {
5660 Consumer <String > awaiter = Platform .isWindows () ? new WindowsAwaiter () : new SleepAwaiter ();
5761 long startTime = System .nanoTime ();
5862 while (true ) {
5963 try {
60- return new RandomAccessFile (path , "rw" );
64+ return new AsynchronousFileByteChannel (AsynchronousFileChannel .open (Paths .get (path ),
65+ StandardOpenOption .READ , StandardOpenOption .WRITE ));
6166 }
62- catch (FileNotFoundException ex ) {
63- if (System .nanoTime () - startTime > TIMEOUT ) {
67+ catch (NoSuchFileException ex ) {
68+ if (System .nanoTime () - startTime >= TIMEOUT ) {
6469 throw ex ;
6570 }
6671 awaiter .accept (path );
@@ -70,21 +75,19 @@ private static RandomAccessFile open(String path) throws IOException {
7075
7176 @ Override
7277 public InputStream getInputStream () {
73- return this .inputStream ;
78+ return Channels . newInputStream ( this .channel ) ;
7479 }
7580
7681 @ Override
7782 public OutputStream getOutputStream () {
78- return this .outputStream ;
83+ return Channels . newOutputStream ( this .channel ) ;
7984 }
8085
8186 @ Override
8287 public void close () throws IOException {
83- this .file .close ();
84- }
85-
86- protected final RandomAccessFile getFile () {
87- return this .file ;
88+ if (this .channel != null ) {
89+ this .channel .close ();
90+ }
8891 }
8992
9093 /**
@@ -98,35 +101,81 @@ public static NamedPipeSocket get(String path) throws IOException {
98101 }
99102
100103 /**
101- * {@link InputStream} returned from the {@link NamedPipeSocket }.
104+ * Adapt an {@code AsynchronousByteChannel} to an {@code AsynchronousFileChannel }.
102105 */
103- private class NamedPipeInputStream extends InputStream {
106+ private static class AsynchronousFileByteChannel implements AsynchronousByteChannel {
107+
108+ private final AsynchronousFileChannel fileChannel ;
109+
110+ AsynchronousFileByteChannel (AsynchronousFileChannel fileChannel ) {
111+ this .fileChannel = fileChannel ;
112+ }
104113
105114 @ Override
106- public int read () throws IOException {
107- return getFile ().read ();
115+ public <A > void read (ByteBuffer dst , A attachment , CompletionHandler <Integer , ? super A > handler ) {
116+ this .fileChannel .read (dst , 0 , attachment , new CompletionHandler <Integer , A >() {
117+
118+ @ Override
119+ public void completed (Integer read , A attachment ) {
120+ handler .completed ((read > 0 ) ? read : -1 , attachment );
121+ }
122+
123+ @ Override
124+ public void failed (Throwable exc , A attachment ) {
125+ if (exc instanceof AsynchronousCloseException ) {
126+ handler .completed (-1 , attachment );
127+ return ;
128+ }
129+ handler .failed (exc , attachment );
130+ }
131+ });
132+
108133 }
109134
110135 @ Override
111- public int read (byte [] bytes , int off , int len ) throws IOException {
112- return getFile ().read (bytes , off , len );
136+ public Future <Integer > read (ByteBuffer dst ) {
137+ CompletableFutureHandler future = new CompletableFutureHandler ();
138+ this .fileChannel .read (dst , 0 , null , future );
139+ return future ;
113140 }
114141
115- }
142+ @ Override
143+ public <A > void write (ByteBuffer src , A attachment , CompletionHandler <Integer , ? super A > handler ) {
144+ this .fileChannel .write (src , 0 , attachment , handler );
145+ }
116146
117- /**
118- * {@link InputStream} returned from the {@link NamedPipeSocket}.
119- */
120- private class NamedPipeOutputStream extends OutputStream {
147+ @ Override
148+ public Future < Integer > write ( ByteBuffer src ) {
149+ return this . fileChannel . write ( src , 0 );
150+ }
121151
122152 @ Override
123- public void write ( int value ) throws IOException {
124- NamedPipeSocket . this .file . write ( value );
153+ public void close ( ) throws IOException {
154+ this .fileChannel . close ( );
125155 }
126156
127157 @ Override
128- public void write (byte [] bytes , int off , int len ) throws IOException {
129- NamedPipeSocket .this .file .write (bytes , off , len );
158+ public boolean isOpen () {
159+ return this .fileChannel .isOpen ();
160+ }
161+
162+ private static class CompletableFutureHandler extends CompletableFuture <Integer >
163+ implements CompletionHandler <Integer , Object > {
164+
165+ @ Override
166+ public void completed (Integer read , Object attachment ) {
167+ complete ((read > 0 ) ? read : -1 );
168+ }
169+
170+ @ Override
171+ public void failed (Throwable exc , Object attachment ) {
172+ if (exc instanceof AsynchronousCloseException ) {
173+ complete (-1 );
174+ return ;
175+ }
176+ completeExceptionally (exc );
177+ }
178+
130179 }
131180
132181 }
0 commit comments