KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jdesktop > jdic > browser > MsgClient


1 /*
2  * Copyright (C) 2004 Sun Microsystems, Inc. All rights reserved. Use is
3  * subject to license terms.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the Lesser GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA.
19  */

20
21 package org.jdesktop.jdic.browser;
22
23 import java.io.*;
24 import java.nio.*;
25 import java.nio.channels.*;
26 import java.nio.charset.*;
27 import java.net.*;
28 import java.util.*;
29
30 import org.jdesktop.jdic.browser.internal.WebBrowserUtil;
31
32 /**
33  * An internal class that implements a socket client.
34  *
35  * @author Kyle Yuan
36  * @version 0.1, 03/07/30
37  */

38 class MsgClient {
39     private static final int MAX_RETRY = 30;
40     private static final int BUFFERSIZE = 2048;
41
42     // socket message delimiter.
43
// use these delimiters assuming they won't appear in the message itself.
44
private static final String JavaDoc MSG_DELIMITER = "</html><body></html>";
45     // a long message may be devided into several pieces:
46
// a head piece, multiple middle pieces and an end piece.
47
private static final String JavaDoc MSG_DELIMITER_ = MSG_DELIMITER + "_";
48     private static final String JavaDoc MSG_DELIMITER_HEAD = MSG_DELIMITER + "_head";
49     private static final String JavaDoc MSG_DELIMITER_MIDDLE = MSG_DELIMITER + "_middle";
50     private static final String JavaDoc MSG_DELIMITER_END = MSG_DELIMITER + "_end";
51
52     private Selector selector = null;
53     private SocketChannel channel = null;
54     private int port;
55     private InetSocketAddress serverAddr;
56
57     private String JavaDoc charsetName = null;
58     private CharsetDecoder decoder;
59     private CharsetEncoder encoder;
60     private ByteBuffer buffer;
61     private CharBuffer charBuffer;
62
63     private String JavaDoc sendBuffer = new String JavaDoc();
64     private String JavaDoc recvBuffer = new String JavaDoc();
65     
66     // cached long message pieces, once a complete message is received, it will
67
// be handled and removed from the set.
68
private static Set msgPieces = new HashSet();
69
70     MsgClient() {
71         // For IE on Windows, use the system default charset. With JDK 5.0,
72
// there is a method Charset.defaultCharset().
73
// Note: for Mozilla on Windows/*nix, use "UTF-8", as there is no
74
// public/frozen APIs to use the system default charset, which must be
75
// the *same* charset used by the native code.
76
charsetName = WebBrowserUtil.isDefaultBrowserMozilla() ?
77             "UTF-8" : System.getProperty("file.encoding");
78         
79         Charset charset = Charset.forName(charsetName);
80         decoder = charset.newDecoder();
81         encoder = charset.newEncoder();
82
83         buffer = ByteBuffer.allocateDirect(BUFFERSIZE);
84         charBuffer = CharBuffer.allocate(BUFFERSIZE);
85
86         try {
87             //initialize a Selector
88
selector = Selector.open();
89
90             ServerSocketChannel sc = ServerSocketChannel.open();
91             //find a free port
92
sc.socket().bind(new InetSocketAddress("localhost", 0));
93             port = sc.socket().getLocalPort();
94             sc.close();
95             sc = null;
96             serverAddr = new InetSocketAddress("localhost", port);
97             WebBrowserUtil.trace("found a free port: " + port);
98         } catch (Exception JavaDoc e) {
99         }
100     }
101
102     int getPort() {
103         return port;
104     }
105
106     void connect() throws IOException, InterruptedException JavaDoc {
107         int retry;
108         for (retry = 0; retry < MAX_RETRY; retry++) {
109             WebBrowserUtil.trace("connecting ... " + retry);
110
111             try {
112                 channel = SocketChannel.open();
113                 channel.configureBlocking(false);
114                 //connect to server
115
channel.connect(serverAddr);
116                 //register events to listen
117
channel.register(selector, SelectionKey.OP_CONNECT);
118
119                 while (! channel.isConnected()) {
120                     if (selector.select(1) > 0) {
121                         Set readyKeys = selector.selectedKeys();
122                         Iterator i = readyKeys.iterator();
123                         while (i.hasNext()) {
124                             SelectionKey key = (SelectionKey)i.next();
125                             i.remove();
126                             SocketChannel keyChannel = (SocketChannel) key.channel();
127                             if (key.isConnectable()) {
128                                 if (keyChannel.isConnectionPending()) {
129                                     keyChannel.finishConnect();
130                                 }
131                                 break;
132                             }
133                         }
134                     }
135                 }
136                 break;
137             } catch (Exception JavaDoc e) {
138                 WebBrowserUtil.trace(e.toString());
139                 channel.close();
140                 channel = null;
141                 try {
142                     Thread.sleep(150);
143                 } catch (Exception JavaDoc ex) {
144                 }
145             }
146
147         }
148
149         if (retry == MAX_RETRY) {
150             throw new InterruptedException JavaDoc("Maximum retry number reached!");
151         }
152
153         WebBrowserUtil.trace("connected");
154         channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
155     }
156
157     // Append a sockate message string to the send buffer.
158
// NOTE: the "," character is used as the message field delimiter to
159
// compose/decompose socket message strings. Which should be identical
160
// between the Java side and native side.
161
void sendMessage(String JavaDoc msg) {
162         sendBuffer += msg + MSG_DELIMITER;
163     }
164    
165     String JavaDoc getMessage() {
166         int pos = recvBuffer.indexOf(MSG_DELIMITER);
167         if (pos < 0)
168             return null;
169
170         String JavaDoc msg = recvBuffer.substring(0, pos);
171         if (pos != recvBuffer.indexOf(MSG_DELIMITER_)) {
172             // a short message.
173
recvBuffer = recvBuffer.substring(pos +
174                     (new String JavaDoc(MSG_DELIMITER).length()));
175             WebBrowserUtil.trace("get a complete short message: " + msg);
176             return msg;
177         }
178
179         NativeEventData eventData = NativeEventThread.parseIncomingMessage(msg);
180
181         // receive a long message, consisting of one head message piece,
182
// multiple middle message pieces and one end message piece.
183
if (pos == recvBuffer.indexOf(MSG_DELIMITER_HEAD)) {
184             // The head piece of a long message.
185
// Each head piece contains the instance and type information
186
// identifying a long message.
187
msgPieces.add(new NativeEventData(eventData.instance,
188                     eventData.type, eventData.stringValue));
189             recvBuffer = recvBuffer.substring(pos +
190                     (new String JavaDoc(MSG_DELIMITER_HEAD).length()));
191             WebBrowserUtil.trace("get a head message piece: "
192                     + eventData.stringValue);
193             return null;
194         } else {
195             Iterator it = msgPieces.iterator();
196             while (it.hasNext()) {
197                 NativeEventData element = (NativeEventData)it.next();
198                 if ((element.instance == eventData.instance) &&
199                     (element.type == eventData.type)) {
200                     if (pos == recvBuffer.indexOf(MSG_DELIMITER_MIDDLE)) {
201                         NativeEventData newElement = new NativeEventData(
202                                 eventData.instance, eventData.type,
203                                 element.stringValue + eventData.stringValue);
204                         msgPieces.remove(element);
205                         msgPieces.add(newElement);
206                         recvBuffer = recvBuffer.substring(pos +
207                                 (new String JavaDoc(MSG_DELIMITER_MIDDLE).length()));
208                         WebBrowserUtil.trace("got a middle message piece: " +
209                                 eventData.stringValue);
210                         return null;
211                     } else if (pos == recvBuffer.indexOf(MSG_DELIMITER_END)) {
212                         // The end piece of a long message. Concat the complete
213
// message and return it.
214
msg = eventData.instance + "," + eventData.type + ","
215                             + element.stringValue + eventData.stringValue;
216                         msgPieces.remove(element);
217                         recvBuffer = recvBuffer.substring(pos +
218                                 (new String JavaDoc(MSG_DELIMITER_END).length()));
219                         WebBrowserUtil.trace("got an end message piece: " +
220                                 eventData.stringValue);
221                         WebBrowserUtil.trace("got a complete long message: " +
222                                 element.stringValue + eventData.stringValue);
223                                                 
224                         return (msg);
225                     }
226                 }
227             }
228            
229             return null;
230         }
231     }
232
233     void portListening() throws IOException, InterruptedException JavaDoc {
234         if (selector != null && selector.select(1) > 0) {
235             Set readyKeys = selector.selectedKeys();
236             Iterator i = readyKeys.iterator();
237             while (i.hasNext()) {
238                 SelectionKey key = (SelectionKey)i.next();
239                 i.remove();
240                 SocketChannel keyChannel = (SocketChannel) key.channel();
241                 if (key.isReadable()) {
242                     buffer.clear();
243                     charBuffer.clear();
244                     keyChannel.read(buffer);
245                     buffer.flip();
246                     decoder.decode(buffer, charBuffer, false);
247                     charBuffer.flip();
248                     recvBuffer += charBuffer;
249                     WebBrowserUtil.trace("read data from socket: "
250                             + recvBuffer);
251                 }
252                 else if (key.isWritable()) {
253                     if (sendBuffer.length() > 0) {
254                         WebBrowserUtil.trace("send data to socket: "
255                                 + sendBuffer);
256                         ByteBuffer buf
257                             = ByteBuffer.wrap(sendBuffer.getBytes(charsetName));
258                         keyChannel.write(buf);
259                         sendBuffer = "";
260                     }
261                 }
262             }
263         }
264     }
265 }
266
Popular Tags