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