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