1 /*
2  * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /* @test
25  * @bug 4607272 6842687
26  * @summary Unit test for AsynchronousChannelGroup
27  */
28 
29 import java.nio.ByteBuffer;
30 import java.nio.channels.*;
31 import java.net.*;
32 import java.util.*;
33 import java.util.concurrent.*;
34 import java.io.IOException;
35 
36 /**
37  * This test verifies that a channel or channel group can be closed from a
38  * completion handler when there are no threads available to handle I/O events.
39  */
40 
41 public class GroupOfOne {
42 
main(String[] args)43     public static void main(String[] args) throws Exception {
44         final List<AsynchronousSocketChannel> accepted = new ArrayList<>();
45 
46         // create listener to accept connections
47         try (final AsynchronousServerSocketChannel listener =
48                 AsynchronousServerSocketChannel.open()) {
49 
50             listener.bind(new InetSocketAddress(0));
51             listener.accept((Void)null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
52                 public void completed(AsynchronousSocketChannel ch, Void att) {
53                     synchronized (accepted) {
54                         accepted.add(ch);
55                     }
56                     listener.accept((Void)null, this);
57                 }
58                 public void failed(Throwable exc, Void att) {
59                 }
60             });
61 
62             int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
63             SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port);
64 
65             test(sa, true, false);
66             test(sa, false, true);
67             test(sa, true, true);
68         } finally {
69             // clean-up
70             synchronized (accepted) {
71                 for (AsynchronousSocketChannel ch: accepted) {
72                     ch.close();
73                 }
74             }
75         }
76     }
77 
test(SocketAddress sa, final boolean closeChannel, final boolean shutdownGroup)78     static void test(SocketAddress sa,
79                      final boolean closeChannel,
80                      final boolean shutdownGroup)
81         throws Exception
82     {
83         // group with 1 thread
84         final AsynchronousChannelGroup group = AsynchronousChannelGroup
85             .withFixedThreadPool(1, new ThreadFactory() {
86                 @Override
87                 public Thread newThread(final Runnable r) {
88                     return new Thread(r);
89                 }});
90         final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group);
91         try {
92             // the latch counts down when:
93             // 1. The read operation fails (expected)
94             // 2. the close/shutdown completes
95             final CountDownLatch latch = new CountDownLatch(2);
96 
97             ch.connect(sa, (Void)null, new CompletionHandler<Void,Void>() {
98                 public void completed(Void result, Void att)  {
99                     System.out.println("Connected");
100 
101                     // initiate I/O operation that does not complete (successfully)
102                     ByteBuffer buf = ByteBuffer.allocate(100);
103                     ch.read(buf, (Void)null, new CompletionHandler<Integer,Void>() {
104                         public void completed(Integer bytesRead, Void att)  {
105                             throw new RuntimeException();
106                         }
107                         public void failed(Throwable exc, Void att) {
108                             if (!(exc instanceof AsynchronousCloseException))
109                                 throw new RuntimeException(exc);
110                             System.out.println("Read failed (expected)");
111                             latch.countDown();
112                         }
113                     });
114 
115                     // close channel or shutdown group
116                     try {
117                         if (closeChannel) {
118                             System.out.print("Close channel ...");
119                             ch.close();
120                             System.out.println(" done.");
121                         }
122                         if (shutdownGroup) {
123                             System.out.print("Shutdown group ...");
124                             group.shutdownNow();
125                             System.out.println(" done.");
126                         }
127                         latch.countDown();
128                     } catch (IOException e) {
129                         throw new RuntimeException();
130                     }
131                 }
132                 public void failed(Throwable exc, Void att) {
133                     throw new RuntimeException(exc);
134                 }
135             });
136 
137             latch.await();
138         } finally {
139             // clean-up
140             group.shutdown();
141             boolean terminated = group.awaitTermination(20, TimeUnit.SECONDS);
142             if (!terminated)
143                 throw new RuntimeException("Group did not terminate");
144         }
145         System.out.println("TEST OKAY");
146     }
147 }
148