001    
002    import java.util.Set;
003    
004    import java.io.IOException;
005    import java.net.BindException;
006    import java.net.InetSocketAddress;
007    import java.net.Socket;
008    import java.net.ServerSocket;
009    
010    import java.nio.channels.Selector;
011    import java.nio.channels.SelectionKey;
012    import java.nio.channels.ServerSocketChannel;
013    //import java.nio.channels.SocketChannel;
014    
015    
016    /**
017     * ChannelFactoryNio.
018     * Socket channel factory using java.nio and no Thread.
019     *
020     * Usage: ChannelFactoryNio(port).
021     * @author Heinz Kredel.
022     */
023    public class ChannelFactoryNio extends Thread {
024      
025    /**
026     * default port of socket. 
027     */
028      public final static int DEFAULT_PORT = 4711;
029    
030    /**
031     * wait time 500ms. 
032     */
033      public final static int WAIT_TIME = 500;
034    
035    /**
036     * port of socket. 
037     */
038      private final int port;
039    
040    /**
041     * local selector.
042     */
043      private Selector selector = null;
044    
045    /**
046     * local server key.
047     */
048      private SelectionKey serverkey = null;
049    
050    /**
051     * local server socket channel.
052     */
053      private ServerSocketChannel server = null;
054    
055    
056    /**
057     * Constructs a ChannelFactory using Nio. 
058     * @param p port.
059     */
060      public ChannelFactoryNio(int p) {
061        if ( p <= 0 ) { 
062           port = DEFAULT_PORT; 
063        } else { 
064           port = p; 
065        }
066        try {
067            selector = Selector.open();
068    
069            server = ServerSocketChannel.open();
070            server.configureBlocking(false);
071            serverkey = server.register(selector,SelectionKey.OP_ACCEPT);
072            server.socket().bind( new InetSocketAddress(port) );
073    
074            System.out.println("server started on port "+port);
075        } catch (BindException e) { 
076            System.out.println(e);
077            serverkey.cancel();
078            //server.close();
079        } catch (IOException e) { 
080            e.printStackTrace(); 
081        }
082      }
083    
084    
085    /**
086     * Constructs a ChannelFactory Nio.
087     * on the DEFAULT_PORT.
088     */
089      public ChannelFactoryNio() {
090        this(DEFAULT_PORT); 
091      }
092    
093    
094    /**
095     * Get a new socket channel from a server socket.
096     */
097      public SocketChannel getChannel() 
098                           throws IOException {
099        SocketChannel c = null;
100        java.nio.channels.SocketChannel s;
101        while (c == null) {
102            try {
103                System.out.println("waiting for connection");
104                selector.select(); // blocking
105    
106                Set<SelectionKey> keys = selector.selectedKeys();
107                for ( SelectionKey k: keys ) {
108                    if ( k == serverkey ) {
109                       if ( k.isAcceptable() ) { // just in case
110                          keys.remove(k);
111                          s = server.accept();
112                          s.configureBlocking(true);
113                          c = new SocketChannel( s.socket() );
114                          System.out.println("connection accepted");
115                          break; // ignore other keys
116                       }
117                    } else { // ignore client keys
118                        selector.wakeup();
119                    }
120                }
121            } catch (IOException e) {
122              System.out.println(e);
123              try {   // wait for next client to connect
124                  Thread.currentThread().sleep( WAIT_TIME );
125              } catch (InterruptedException ignored) { } 
126            }
127        }
128        return c;
129      }
130    
131    
132    /**
133     * Get a new socket channel to a given host.
134     * @param h hostname.
135     * @param p port.
136     */
137      public SocketChannel getChannel(String h, int p) 
138                                      throws IOException {
139        if ( p <= 0 ) { 
140           p = port; 
141        } 
142        SelectionKey clientkey = null;
143        SocketChannel c = null;
144        java.nio.channels.SocketChannel client;
145        System.out.println("connecting to "+h);
146        while (c == null) {
147            try {
148                client = java.nio.channels.SocketChannel.open();
149                client.configureBlocking(false);
150                clientkey = client.register(selector,SelectionKey.OP_CONNECT);
151                client.connect( new InetSocketAddress(h,p) );
152    
153                selector.select(); // blocking
154    
155                Set<SelectionKey> keys = selector.selectedKeys();
156                for ( SelectionKey k: keys ) {
157                    if ( k == clientkey ) {
158                       if ( k.isConnectable() ) { // if server ready
159                           keys.remove(k);
160                           k.cancel();     // required to make blockable
161                           client = (java.nio.channels.SocketChannel) k.channel();
162                           client.finishConnect();
163                           client.configureBlocking(true);
164                           c = new SocketChannel( client.socket() );
165                           break; // ignore other keys
166                       }
167                    } else { // ignore server keys
168                        selector.wakeup();
169                    }
170                }
171            } catch (IOException e) {
172              System.out.println(e);
173              System.out.println("Server on "+h+" not ready");
174              try { // wait server ready
175                  Thread.currentThread().sleep( WAIT_TIME );
176              } catch (InterruptedException ignored) { } 
177            }
178        }
179        System.out.println("connected");
180        return c;
181      }
182    
183    
184    /**
185     * Close the Channel Factory.
186     */
187      public void close() {
188        try {
189            serverkey.cancel();
190            selector.close();
191            server.close();
192        } catch (IOException e) { 
193            e.printStackTrace();
194        }
195      }
196    
197    }
198