From f6acca258be8f9073295e26c7c263e6c69cbfe5e Mon Sep 17 00:00:00 2001 From: Maycon Bordin Date: Fri, 2 Mar 2012 17:43:44 -0300 Subject: [PATCH] modified IOWebSocket to comply with the WebSocketClient interface. Also added a simple chat client. --- .../src/org/socketio/chat/Chat.java | 43 ++ .../src/org/socketio/chat/ChatCallback.java | 51 ++ .../socketio/chat/ChatCallbackAdapter.java | 15 + .../src/org/socketio/chat/ChatFrame.form | 107 +++++ .../src/org/socketio/chat/ChatFrame.java | 200 ++++++++ examples/chat-server/app.js | 37 ++ .../clwillingham/socket/io/AckCallback.java | 16 +- src/com/clwillingham/socket/io/IOBeat.java | 58 ++- src/com/clwillingham/socket/io/IOMessage.java | 246 +++++----- src/com/clwillingham/socket/io/IOSocket.java | 434 +++++++++--------- .../clwillingham/socket/io/IOWebSocket.java | 336 +++++++------- src/com/clwillingham/socket/io/Message.java | 8 +- .../socket/io/MessageCallback.java | 12 +- .../socket/io/log/DefaultLog.java | 20 + src/com/clwillingham/socket/io/log/Log.java | 28 ++ .../socket/io/log/LogAdapter.java | 7 + 16 files changed, 1059 insertions(+), 559 deletions(-) create mode 100644 examples/chat-client/src/org/socketio/chat/Chat.java create mode 100644 examples/chat-client/src/org/socketio/chat/ChatCallback.java create mode 100644 examples/chat-client/src/org/socketio/chat/ChatCallbackAdapter.java create mode 100644 examples/chat-client/src/org/socketio/chat/ChatFrame.form create mode 100644 examples/chat-client/src/org/socketio/chat/ChatFrame.java create mode 100644 examples/chat-server/app.js create mode 100644 src/com/clwillingham/socket/io/log/DefaultLog.java create mode 100644 src/com/clwillingham/socket/io/log/Log.java create mode 100644 src/com/clwillingham/socket/io/log/LogAdapter.java diff --git a/examples/chat-client/src/org/socketio/chat/Chat.java b/examples/chat-client/src/org/socketio/chat/Chat.java new file mode 100644 index 0000000..ff0942c --- /dev/null +++ b/examples/chat-client/src/org/socketio/chat/Chat.java @@ -0,0 +1,43 @@ +package org.socketio.chat; + +import com.clwillingham.socket.io.IOSocket; +import java.io.IOException; +import org.json.JSONException; +import org.json.JSONObject; + +public class Chat extends Thread { + private IOSocket socket; + private ChatCallback callback; + + public Chat(ChatCallbackAdapter callback) { + this.callback = new ChatCallback(callback); + } + + @Override + public void run() { + socket = new IOSocket("http://localhost:3000", callback); + socket.connect(); + } + + public void sendMessage(String message) { + try { + JSONObject json = new JSONObject(); + json.putOpt("message", message); + socket.emit("user message", json); + } catch (IOException ex) { + ex.printStackTrace(); + } catch (JSONException ex) { + ex.printStackTrace(); + } + } + + public void join(String nickname) { + try { + JSONObject json = new JSONObject(); + json.putOpt("nickname", nickname); + socket.emit("nickname", json, callback); + } catch (Exception ex) { + ex.printStackTrace(); + } + } +} diff --git a/examples/chat-client/src/org/socketio/chat/ChatCallback.java b/examples/chat-client/src/org/socketio/chat/ChatCallback.java new file mode 100644 index 0000000..0887786 --- /dev/null +++ b/examples/chat-client/src/org/socketio/chat/ChatCallback.java @@ -0,0 +1,51 @@ +package org.socketio.chat; + +import com.clwillingham.socket.io.AckCallback; +import com.clwillingham.socket.io.MessageCallback; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public class ChatCallback extends AckCallback implements MessageCallback { + private ChatCallbackAdapter callback; + + public ChatCallback(ChatCallbackAdapter callback) { + this.callback = callback; + } + + @Override + public void callback(JSONArray data) throws JSONException { + callback.callback(data); + } + + @Override + public void on(String event, JSONObject... data) { + callback.on(event, data); + } + + @Override + public void onMessage(String message) { + callback.onMessage(message); + } + + @Override + public void onMessage(JSONObject json) { + callback.onMessage(json); + } + + @Override + public void onConnect() { + callback.onConnect(); + } + + @Override + public void onDisconnect() { + callback.onDisconnect(); + } + + @Override + public void onConnectFailure() { + callback.onConnectFailure(); + } + +} diff --git a/examples/chat-client/src/org/socketio/chat/ChatCallbackAdapter.java b/examples/chat-client/src/org/socketio/chat/ChatCallbackAdapter.java new file mode 100644 index 0000000..bd9287a --- /dev/null +++ b/examples/chat-client/src/org/socketio/chat/ChatCallbackAdapter.java @@ -0,0 +1,15 @@ +package org.socketio.chat; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public interface ChatCallbackAdapter { + public void callback(JSONArray data) throws JSONException; + public void on(String event, JSONObject... data); + public void onMessage(String message); + public void onMessage(JSONObject json); + public void onConnect(); + public void onDisconnect(); + public void onConnectFailure(); +} diff --git a/examples/chat-client/src/org/socketio/chat/ChatFrame.form b/examples/chat-client/src/org/socketio/chat/ChatFrame.form new file mode 100644 index 0000000..9aaf619 --- /dev/null +++ b/examples/chat-client/src/org/socketio/chat/ChatFrame.form @@ -0,0 +1,107 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/examples/chat-client/src/org/socketio/chat/ChatFrame.java b/examples/chat-client/src/org/socketio/chat/ChatFrame.java new file mode 100644 index 0000000..afa3203 --- /dev/null +++ b/examples/chat-client/src/org/socketio/chat/ChatFrame.java @@ -0,0 +1,200 @@ +package org.socketio.chat; + +import javax.swing.JOptionPane; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public class ChatFrame extends javax.swing.JFrame implements ChatCallbackAdapter { + private Chat chat; + + /** Creates new form Chat */ + public ChatFrame() { + initComponents(); + setVisible(true); + setLocationRelativeTo(null); + disableNewMessages(); + + startChat(); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + MessagesScrollPane = new javax.swing.JScrollPane(); + MessagesTextArea = new javax.swing.JTextArea(); + NewMessageScrollPane = new javax.swing.JScrollPane(); + NewMessageTextArea = new javax.swing.JTextArea(); + SendButton = new javax.swing.JButton(); + OnlineUsersLabel = new javax.swing.JLabel(); + OnlineUsers = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + setTitle("Chat"); + + MessagesTextArea.setColumns(20); + MessagesTextArea.setEditable(false); + MessagesTextArea.setRows(5); + MessagesScrollPane.setViewportView(MessagesTextArea); + + NewMessageTextArea.setColumns(20); + NewMessageTextArea.setRows(5); + NewMessageScrollPane.setViewportView(NewMessageTextArea); + + SendButton.setText("Send"); + SendButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + SendButtonActionPerformed(evt); + } + }); + + OnlineUsersLabel.setText("Online:"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(MessagesScrollPane, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(NewMessageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 295, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(SendButton, javax.swing.GroupLayout.DEFAULT_SIZE, 75, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(OnlineUsersLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(OnlineUsers, javax.swing.GroupLayout.DEFAULT_SIZE, 326, Short.MAX_VALUE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(OnlineUsersLabel) + .addComponent(OnlineUsers)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(MessagesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 192, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(SendButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(NewMessageScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 51, Short.MAX_VALUE)) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void SendButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SendButtonActionPerformed + chat.sendMessage(NewMessageTextArea.getText()); + MessagesTextArea.append("Me: " + NewMessageTextArea.getText() + "\n"); + NewMessageTextArea.setText(null); + }//GEN-LAST:event_SendButtonActionPerformed + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + java.awt.EventQueue.invokeLater(new Runnable() { + + @Override + public void run() { + new ChatFrame(); + } + }); + } + + + public void startChat() { + MessagesTextArea.append("Connecting..."); + chat = new Chat(this); + chat.start(); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JScrollPane MessagesScrollPane; + private javax.swing.JTextArea MessagesTextArea; + private javax.swing.JScrollPane NewMessageScrollPane; + private javax.swing.JTextArea NewMessageTextArea; + private javax.swing.JLabel OnlineUsers; + private javax.swing.JLabel OnlineUsersLabel; + private javax.swing.JButton SendButton; + // End of variables declaration//GEN-END:variables + + public void disableNewMessages() { + NewMessageTextArea.setEnabled(false); + SendButton.setEnabled(false); + } + + public void enableNewMessages() { + NewMessageTextArea.setEnabled(true); + SendButton.setEnabled(true); + } + + @Override + public void callback(JSONArray data) throws JSONException {} + + @Override + public void on(String event, JSONObject... data) { + try { + if (event.equals("user message")) { + MessagesTextArea.append(data[0].getString("user") + ": " + data[0].getString("message") + "\n"); + } + + else if (event.equals("announcement")) { + MessagesTextArea.append(data[0].getString("user") + " " + data[0].getString("action") + "\n"); + } + + else if (event.equals("nicknames")) { + JSONArray names = data[0].names(); + String str = ""; + for (int i=0; i < names.length(); i++) { + if (i != 0) + str += ", "; + str += names.getString(i); + } + OnlineUsers.setText(str); + } + } catch (JSONException ex) { + ex.printStackTrace(); + } + } + + @Override + public void onMessage(String message) {} + + @Override + public void onMessage(JSONObject json) {} + + @Override + public void onConnect() { + MessagesTextArea.append("done!\n"); + enableNewMessages(); + + String nickname = JOptionPane.showInputDialog(null, "Nickname", null, WIDTH); + if (!nickname.isEmpty()) { + chat.join(nickname); + MessagesTextArea.append("You joined as " + nickname + "\n"); + } + } + + @Override + public void onDisconnect() { + JOptionPane.showMessageDialog(null, "Connection lost", "Error", JOptionPane.ERROR_MESSAGE); + disableNewMessages(); + } + + @Override + public void onConnectFailure() { + MessagesTextArea.append("error!\n"); + } + +} \ No newline at end of file diff --git a/examples/chat-server/app.js b/examples/chat-server/app.js new file mode 100644 index 0000000..cbee63b --- /dev/null +++ b/examples/chat-server/app.js @@ -0,0 +1,37 @@ +var http = require('http') + , io = require('socket.io'); + +var app = http.createServer(); +app.listen(3000); + +console.log('Server running at http://127.0.0.1:3000/'); + +// Socket.IO server +var io = io.listen(app) + , nicknames = {}; + +io.sockets.on('connection', function (socket) { + socket.on('user message', function (msg) { + socket.broadcast.emit('user message', {user: socket.nickname, message: msg.message}); + }); + + socket.on('nickname', function (nick, fn) { + nickname = nick.nickname; + if (nicknames[nickname]) { + fn(true); + } else { + fn(false); + nicknames[nickname] = socket.nickname = nickname; + socket.broadcast.emit('announcement', {user: nickname, action: 'connected'}); + io.sockets.emit('nicknames', nicknames); + } + }); + + socket.on('disconnect', function () { + if (!socket.nickname) return; + + delete nicknames[socket.nickname]; + socket.broadcast.emit('announcement', {user: socket.nickname, action: 'disconected'}); + socket.broadcast.emit('nicknames', nicknames); + }); +}); diff --git a/src/com/clwillingham/socket/io/AckCallback.java b/src/com/clwillingham/socket/io/AckCallback.java index 57d2e80..edc4d38 100644 --- a/src/com/clwillingham/socket/io/AckCallback.java +++ b/src/com/clwillingham/socket/io/AckCallback.java @@ -6,15 +6,15 @@ public abstract class AckCallback { - private JSONObject requestData; + private JSONObject requestData; - public abstract void callback(JSONArray data) throws JSONException; + public abstract void callback(JSONArray data) throws JSONException; - public JSONObject getRequestData() { - return requestData; - } + public JSONObject getRequestData() { + return requestData; + } - public void setRequestData(JSONObject requestData) { - this.requestData = requestData; - } + public void setRequestData(JSONObject requestData) { + this.requestData = requestData; + } } diff --git a/src/com/clwillingham/socket/io/IOBeat.java b/src/com/clwillingham/socket/io/IOBeat.java index c6d3eb8..7684ac1 100644 --- a/src/com/clwillingham/socket/io/IOBeat.java +++ b/src/com/clwillingham/socket/io/IOBeat.java @@ -1,41 +1,39 @@ package com.clwillingham.socket.io; -import java.io.IOException; +import com.clwillingham.socket.io.log.Log; import java.util.TimerTask; public class IOBeat extends TimerTask { - private IOWebSocket socket; - private boolean running = false; + private IOWebSocket socket; + private boolean running = false; - public IOBeat(IOWebSocket socket){ - this.socket = socket; - } + public IOBeat(IOWebSocket socket){ + this.socket = socket; + } - @Override - public void run() { - // TODO Auto-generated method stub - if(running){ - try { - socket.send("2::"); //send heartbeat; - System.out.println("HeartBeat Written to server"); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - - public void start(){ - running = true; - } - - public void stop(){ - running = false; + @Override + public void run() { + if(running) { + try { + socket.send("2::"); //send heartbeat; + Log.info("HeartBeat Written to server"); + } catch (Exception e) { + Log.error(e.getMessage()); + } } + } - public boolean isRunning(){ - return running; - } + public void start() { + running = true; + } + + public void stop() { + running = false; + } + + public boolean isRunning() { + return running; + } -} +} \ No newline at end of file diff --git a/src/com/clwillingham/socket/io/IOMessage.java b/src/com/clwillingham/socket/io/IOMessage.java index 0eb0d28..b17704b 100644 --- a/src/com/clwillingham/socket/io/IOMessage.java +++ b/src/com/clwillingham/socket/io/IOMessage.java @@ -1,127 +1,129 @@ package com.clwillingham.socket.io; +import com.clwillingham.socket.io.log.Log; + public class IOMessage { - public static final int DISCONNECT = 0; - public static final int CONNECT = 1; - public static final int HEARTBEAT = 2; - public static final int MESSAGE = 3; - public static final int JSONMSG = 4; - public static final int EVENT = 5; - public static final int ACK = 6; - public static final int ERROR = 7; - - private int type; - private int id = -1; - private String endpoint = ""; - private String messageData; - private boolean ack = false; - - public IOMessage(int type, int id, String endpoint, String data){ - this.type = type; - this.id = id; - this.endpoint = endpoint; - this.messageData = data; - } - - public IOMessage(int type, String endpoint, String data) { - this.type = type; - this.endpoint = endpoint; - this.messageData = data; - } - - public IOMessage(){ - - } - - - public static IOMessage parseMsg(String message){ - String[] content = message.split(":", 4); - IOMessage msg = new IOMessage(); - msg.setType(Integer.parseInt(content[0])); - - if(message.endsWith("::")){ - msg.setId(-1); - msg.setMessageData(""); - msg.setEndpoint(""); - return msg; - } - System.out.println(content[1]); - if(!content[1].equals("")){ - msg.setId(Integer.parseInt(content[1])); - } - if(!content[2].equals("")){ - msg.setEndpoint(content[2]); - } - if(content.length > 3 && !content[3].equals("")){ - msg.setMessageData(content[3]); - } - return msg; - } - - public String toString(){ - if(id == -1 && endpoint.equals("") && messageData.equals("")){ - return type+"::"; - } - else if(id == -1 && endpoint.equals("")){ - return type+":::"+messageData; - } - else if(id > -1){ - String idAck = ack ? "+" : ""; - return type + ":" + id + idAck + ":" + endpoint + ":" + messageData; - } - else{ - return type+"::"+endpoint+":"+messageData; - } - } - - - public void setType(int type) { - this.type = type; - } - - - public int getType() { - return type; - } - - - public void setId(int id) { - this.id = id; - } - - - public int getId() { - return id; - } - - - public void setEndpoint(String endpoint) { - this.endpoint = endpoint; - } - - - public String getEndpoint() { - return endpoint; - } - - - public void setMessageData(String messageData) { - this.messageData = messageData; - } - - - public String getMessageData() { - return messageData; - } - - - public void setAck(boolean ack) { - this.ack = ack; - } - - - public boolean getAck() { - return ack; - } + public static final int DISCONNECT = 0; + public static final int CONNECT = 1; + public static final int HEARTBEAT = 2; + public static final int MESSAGE = 3; + public static final int JSONMSG = 4; + public static final int EVENT = 5; + public static final int ACK = 6; + public static final int ERROR = 7; + + private int type; + private int id = -1; + private String endpoint = ""; + private String messageData; + private boolean ack = false; + + public IOMessage(int type, int id, String endpoint, String data){ + this.type = type; + this.id = id; + this.endpoint = endpoint; + this.messageData = data; + } + + public IOMessage(int type, String endpoint, String data) { + this.type = type; + this.endpoint = endpoint; + this.messageData = data; + } + + public IOMessage() {} + + public static IOMessage parseMsg(String message){ + String[] content = message.split(":", 4); + IOMessage msg = new IOMessage(); + msg.setType(Integer.parseInt(content[0])); + + if (message.endsWith("::")) { + msg.setId(-1); + msg.setMessageData(""); + msg.setEndpoint(""); + return msg; + } + + Log.info(content[1]); + + if (!content[1].equals("")){ + msg.setId(Integer.parseInt(content[1])); + } + if (!content[2].equals("")){ + msg.setEndpoint(content[2]); + } + if (content.length > 3 && !content[3].equals("")){ + msg.setMessageData(content[3]); + } + + return msg; + } + + public String toString(){ + if (id == -1 && endpoint.equals("") && messageData.equals("")){ + return type+"::"; + } + else if (id == -1 && endpoint.equals("")){ + return type+":::"+messageData; + } + else if (id > -1){ + String idAck = ack ? "+" : ""; + return type + ":" + id + idAck + ":" + endpoint + ":" + messageData; + } + else { + return type+"::"+endpoint+":"+messageData; + } + } + + + public void setType(int type) { + this.type = type; + } + + + public int getType() { + return type; + } + + + public void setId(int id) { + this.id = id; + } + + + public int getId() { + return id; + } + + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + + public String getEndpoint() { + return endpoint; + } + + + public void setMessageData(String messageData) { + this.messageData = messageData; + } + + + public String getMessageData() { + return messageData; + } + + + public void setAck(boolean ack) { + this.ack = ack; + } + + + public boolean getAck() { + return ack; + } } diff --git a/src/com/clwillingham/socket/io/IOSocket.java b/src/com/clwillingham/socket/io/IOSocket.java index e5c9f4e..4d2aafd 100644 --- a/src/com/clwillingham/socket/io/IOSocket.java +++ b/src/com/clwillingham/socket/io/IOSocket.java @@ -1,5 +1,6 @@ package com.clwillingham.socket.io; +import com.clwillingham.socket.io.log.Log; import java.io.IOException; import java.io.InputStream; import java.net.URI; @@ -15,30 +16,29 @@ import org.json.JSONObject; public class IOSocket { - - private IOWebSocket webSocket; - private URL connection; - private String sessionID; - private int heartTimeout; - private int closingTimeout; - private int connectTimeout = 10000; - private String[] protocals; - private final String webSocketAddress; + private IOWebSocket webSocket; + private URL connection; + private String sessionID; + private int heartTimeout; + private int closingTimeout; + private int connectTimeout = 10000; + private String[] protocals; + private final String webSocketAddress; private final String namespace; - private final MessageCallback callback; - private Timer timer; + private final MessageCallback callback; + private Timer timer; - private int ackCount = 0; - private HashMap ackCallbacks = new HashMap(); + private int ackCount = 0; + private HashMap ackCallbacks = new HashMap(); - private boolean connecting; - private boolean connected; - private boolean open; + private boolean connecting; + private boolean connected; + private boolean open; - public IOSocket(String address, MessageCallback callback){ - + public IOSocket(String address, MessageCallback callback) { // check for socket.io namespace int i = address.lastIndexOf("/"); + if (address.charAt(i-1) != '/') { namespace = address.substring(i); webSocketAddress = address.substring(0, i); @@ -47,109 +47,106 @@ public IOSocket(String address, MessageCallback callback){ webSocketAddress = address; } - this.callback = callback; - } + this.callback = callback; + } - public void connect() { - synchronized(this) { - connecting = true; - } - - timer = new Timer(); - timer.schedule(new ConnectTimeout(), connectTimeout); - + public void connect() { + synchronized(this) { + connecting = true; + } + + timer = new Timer(); + timer.schedule(new ConnectTimeout(), connectTimeout); + (new Thread(new Handshake())).start(); - } - - public void emit(String event, JSONObject... message) throws IOException { - try { - JSONObject data = new JSONObject(); - JSONArray args = new JSONArray(); - for (JSONObject arg : message) { - args.put(arg); - } - data.put("name", event); - data.put("args", args); - IOMessage packet = new IOMessage(IOMessage.EVENT, "", data.toString()); - webSocket.sendMessage(packet); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - public void emit(String event, JSONObject message, AckCallback callback) throws IOException { - try { - JSONObject data = new JSONObject(); - data.put("name", event); - data.put("args", message); - IOMessage packet = new IOMessage(IOMessage.EVENT, addAcknowledge(callback, message), "", data.toString()); - packet.setAck(true); - webSocket.sendMessage(packet); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - public void send(String message) throws IOException { - IOMessage packet = new IOMessage(IOMessage.MESSAGE, "", message); - webSocket.sendMessage(packet); - } - - public synchronized void disconnect() { - if (connected) { - try { - if (open) { - webSocket.sendMessage(new IOMessage(IOMessage.DISCONNECT, "", "")); - } - } catch (IOException e) { - e.printStackTrace(); - } - - onDisconnect(); - } - } - - synchronized void onOpen() { - open = true; - } - - synchronized void onClose() { - open = false; - } - - synchronized void onConnect() { - - if (!connected) { - connected = true; - connecting = false; - - callback.onConnect(); - } - } + } - synchronized void onDisconnect() { - boolean wasConnected = connected; - - connected = false; - connecting = false; - - if (open) { - try { - webSocket.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - - if (wasConnected) { - callback.onDisconnect(); - - //TODO: reconnect - } - } + public void emit(String event, JSONObject... message) throws IOException { + try { + JSONObject data = new JSONObject(); + JSONArray args = new JSONArray(); + for (JSONObject arg : message) { + args.put(arg); + } + data.put("name", event); + data.put("args", args); + IOMessage packet = new IOMessage(IOMessage.EVENT, "", data.toString()); + webSocket.sendMessage(packet); + } catch (JSONException e) { + Log.error(e.getMessage()); + } catch (InterruptedException e) { + Log.error(e.getMessage()); + } + } + + public void emit(String event, JSONObject message, AckCallback callback) throws IOException { + try { + JSONObject data = new JSONObject(); + data.put("name", event); + data.put("args", message); + IOMessage packet = new IOMessage(IOMessage.EVENT, addAcknowledge(callback, message), "", data.toString()); + packet.setAck(true); + webSocket.sendMessage(packet); + } catch (JSONException e) { + Log.error(e.getMessage()); + } catch (InterruptedException e) { + Log.error(e.getMessage()); + } + } + + public void send(String message) throws InterruptedException { + IOMessage packet = new IOMessage(IOMessage.MESSAGE, "", message); + webSocket.sendMessage(packet); + } + + public synchronized void disconnect() { + if (connected) { + try { + if (open) { + webSocket.sendMessage(new IOMessage(IOMessage.DISCONNECT, "", "")); + } + } catch (InterruptedException e) { + Log.error(e.getMessage()); + } + onDisconnect(); + } + } + + synchronized void onOpen() { + open = true; + } + + synchronized void onClose() { + open = false; + } + + synchronized void onConnect() { + if (!connected) { + connected = true; + connecting = false; + + callback.onConnect(); + } + } + + synchronized void onDisconnect() { + boolean wasConnected = connected; + + connected = false; + connecting = false; + + if (open) { + try { + webSocket.close(); + } catch (Exception e) { + Log.error(e.getMessage()); + } + } + + if (wasConnected) { + callback.onDisconnect(); + } + } private synchronized void onConnectFailure() { connecting = false; @@ -158,94 +155,93 @@ private synchronized void onConnectFailure() { callback.onConnectFailure(); } - public void onAcknowledge(int ackId, JSONArray data) { - AckCallback ackCallback = ackCallbacks.get(ackId); - if (ackCallback != null) { - try { - ackCallback.callback(data); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - ackCallbacks.remove(ackId); - } - } - - public synchronized boolean isConnected() { - return connected; - } - - public synchronized boolean isConnecting() { - return connecting; - } - - public boolean isOpen() { - return open; - } + public void onAcknowledge(int ackId, JSONArray data) { + AckCallback ackCallback = ackCallbacks.get(ackId); + if (ackCallback != null) { + try { + ackCallback.callback(data); + } catch (JSONException e) { + Log.error(e.getMessage()); + } + ackCallbacks.remove(ackId); + } + } - public void setConnection(URL connection) { - this.connection = connection; - } - - private int addAcknowledge(AckCallback cb, JSONObject message) { - if (cb != null) { - cb.setRequestData(message); - ackCount++; - ackCallbacks.put(ackCount, cb); - return ackCount; - } - - return -1; - } - - - public URL getConnection() { - return connection; - } - - public void setConnectTimeout(int connectTimeout) { - this.connectTimeout = connectTimeout; - } - - public int getConnectTimeout() { - return connectTimeout; - } + public synchronized boolean isConnected() { + return connected; + } - public void setHeartTimeout(int heartTimeOut) { - this.heartTimeout = heartTimeOut; - } + public synchronized boolean isConnecting() { + return connecting; + } - public int getHeartTimeout() { - return heartTimeout; - } - - public void setClosingTimeout(int closingTimeout) { - this.closingTimeout = closingTimeout; - } + public boolean isOpen() { + return open; + } + + public void setConnection(URL connection) { + this.connection = connection; + } - public int getClosingTimeout() { - return closingTimeout; - } + private int addAcknowledge(AckCallback cb, JSONObject message) { + if (cb != null) { + cb.setRequestData(message); + ackCount++; + ackCallbacks.put(ackCount, cb); + return ackCount; + } + + return -1; + } - public void setSessionID(String sessionID) { - this.sessionID = sessionID; - } + public URL getConnection() { + return connection; + } + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } - public String getSessionID() { - return sessionID; - } + public int getConnectTimeout() { + return connectTimeout; + } + public void setHeartTimeout(int heartTimeOut) { + this.heartTimeout = heartTimeOut; + } - public void setProtocals(String[] protocals) { - this.protocals = protocals; - } + public int getHeartTimeout() { + return heartTimeout; + } + public void setClosingTimeout(int closingTimeout) { + this.closingTimeout = closingTimeout; + } - public String[] getProtocals() { - return protocals; - } + public int getClosingTimeout() { + return closingTimeout; + } + + + public void setSessionID(String sessionID) { + this.sessionID = sessionID; + } + + + public String getSessionID() { + return sessionID; + } + + + public void setProtocals(String[] protocals) { + this.protocals = protocals; + } + + + public String[] getProtocals() { + return protocals; + } private synchronized void onHandshakeSuccess() { if (!connecting) { @@ -272,43 +268,47 @@ public void run() { // process handshake response // example: 4d4f185e96a7b:15:10:websocket,xhr-polling - if(response.contains(":")) { + if (response.contains(":")) { String[] data = response.split(":"); setSessionID(data[0]); setHeartTimeout(Integer.parseInt(data[1]) * 1000); setClosingTimeout(Integer.parseInt(data[2]) * 1000); setProtocals(data[3].split(",")); + Log.info("Handshaked: " + data[0]); onHandshakeSuccess(); } else { + Log.error("Response error: " + response.toString()); onConnectFailure(); } } catch (IOException e) { + Log.error(e.getMessage()); onConnectFailure(); } } } - private class ConnectTimeout extends TimerTask { - @Override - public void run() { - synchronized(IOSocket.this) { - if (connected || !connecting) { - return; - } - connecting = false; - - if (webSocket != null) { - try { - webSocket.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - onConnectFailure(); - } - } - } -} + private class ConnectTimeout extends TimerTask { + @Override + public void run() { + synchronized(IOSocket.this) { + if (connected || !connecting) { + return; + } + connecting = false; + + if (webSocket != null) { + try { + webSocket.close(); + } catch (Exception e) { + Log.error(e.getMessage()); + } + } + Log.error("Connection timed out"); + onConnectFailure(); + } + } + } + +} \ No newline at end of file diff --git a/src/com/clwillingham/socket/io/IOWebSocket.java b/src/com/clwillingham/socket/io/IOWebSocket.java index 5d756eb..47d168c 100644 --- a/src/com/clwillingham/socket/io/IOWebSocket.java +++ b/src/com/clwillingham/socket/io/IOWebSocket.java @@ -1,9 +1,10 @@ package com.clwillingham.socket.io; -import java.io.IOException; +import com.clwillingham.socket.io.log.Log; import java.net.URI; import java.util.Timer; import java.util.TimerTask; +import net.tootallnate.websocket.Handshakedata; import org.json.JSONArray; import org.json.JSONException; @@ -12,178 +13,169 @@ import net.tootallnate.websocket.WebSocketClient; public class IOWebSocket extends WebSocketClient { - - private Timer closeTimeout; - private MessageCallback callback; - private IOSocket ioSocket; - private static int currentID = 0; - private String namespace; - - public IOWebSocket(URI arg0, IOSocket ioSocket, MessageCallback callback) { - super(arg0); - this.callback = callback; - this.ioSocket = ioSocket; - } - - - @Override - public void onIOError(IOException arg0) { - // TODO Auto-generated method stub - - } - - @Override - public void onMessage(String arg0) { - // The javascript socket.io client doesn't seem - // to use the hearbeat timeout at all, just the close - // timeout. - clearCloseTimeout(); - setCloseTimeout(); - - IOMessage message = IOMessage.parseMsg(arg0); - - switch (message.getType()) { - case IOMessage.HEARTBEAT: - try { - send("2::"); - System.out.println("HeartBeat written to server"); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - break; - - case IOMessage.MESSAGE: - callback.onMessage(message.getMessageData()); - break; - - case IOMessage.JSONMSG: - try { - callback.onMessage(new JSONObject(message.getMessageData())); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - break; - - case IOMessage.EVENT: - try { - JSONObject event = new JSONObject(message.getMessageData()); - JSONArray args = event.getJSONArray("args"); - JSONObject[] argsArray = new JSONObject[args.length()]; - for (int i = 0; i < args.length(); i++) { - argsArray[i] = args.getJSONObject(i); - } - String eventName = event.getString("name"); - - callback.on(eventName, argsArray); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - break; - - case IOMessage.CONNECT: - ioSocket.onConnect(); - break; - - case IOMessage.ACK: - String[] parts = message.getMessageData().split("\\+", 2); - int ackId = Integer.parseInt(parts[0]); - - JSONArray data = null; - if (parts.length > 1) { - try { - data = new JSONArray(parts[1]); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - ioSocket.onAcknowledge(ackId, data); - break; - - case IOMessage.ERROR: - case IOMessage.DISCONNECT: - //TODO - break; - } - } - - @Override - public void onOpen() { - try { - if (!namespace.equals("")) { + private Timer closeTimeout; + private MessageCallback callback; + private IOSocket ioSocket; + private static int currentID = 0; + private String namespace; + + public IOWebSocket(URI arg0, IOSocket ioSocket, MessageCallback callback) { + super(arg0); + this.callback = callback; + this.ioSocket = ioSocket; + } + + @Override + public void onMessage(String arg0) { + // The javascript socket.io client doesn't seem + // to use the hearbeat timeout at all, just the close + // timeout. + clearCloseTimeout(); + setCloseTimeout(); + + IOMessage message = IOMessage.parseMsg(arg0); + + switch (message.getType()) { + case IOMessage.HEARTBEAT: + try { + send("2::"); + Log.info("HeartBeat written to server"); + } catch (Exception e) { + Log.error(e.getMessage()); + } + break; + + case IOMessage.MESSAGE: + callback.onMessage(message.getMessageData()); + break; + + case IOMessage.JSONMSG: + try { + callback.onMessage(new JSONObject(message.getMessageData())); + } catch (JSONException e) { + Log.error(e.getMessage()); + } + break; + + case IOMessage.EVENT: + try { + JSONObject event = new JSONObject(message.getMessageData()); + JSONArray args = event.getJSONArray("args"); + JSONObject[] argsArray = new JSONObject[args.length()]; + for (int i = 0; i < args.length(); i++) { + argsArray[i] = args.getJSONObject(i); + } + String eventName = event.getString("name"); + + callback.on(eventName, argsArray); + } catch (JSONException e) { + Log.error(e.getMessage()); + } + break; + + case IOMessage.CONNECT: + ioSocket.onConnect(); + break; + + case IOMessage.ACK: + String[] parts = message.getMessageData().split("\\+", 2); + int ackId = Integer.parseInt(parts[0]); + + JSONArray data = null; + if (parts.length > 1) { + try { + data = new JSONArray(parts[1]); + } catch (JSONException e) { + Log.error(e.getMessage()); + } + } + + ioSocket.onAcknowledge(ackId, data); + break; + + case IOMessage.ERROR: + case IOMessage.DISCONNECT: + break; + } + } + + public void init(String path) throws InterruptedException { + send("1::"+path); + } + + public void init(String path, String query) throws InterruptedException { + send("1::"+path+"?"+query); + + } + + public void sendMessage(IOMessage message) throws InterruptedException { + send(message.toString()); + } + + public void sendMessage(String message) throws InterruptedException { + send(new Message(message).toString()); + } + + + public static int genID(){ + currentID++; + return currentID; + } + + public void setNamespace(String ns) { + namespace = ns; + } + + public String getNamespace() { + return namespace; + } + + private void setCloseTimeout() { + closeTimeout = new Timer(); + closeTimeout.schedule(new CloseTask(), ioSocket.getClosingTimeout()); + } + + private void clearCloseTimeout() { + if (closeTimeout != null) { + closeTimeout.cancel(); + closeTimeout = null; + } + } + + @Override + public void onOpen(Handshakedata h) { + try { + if (!namespace.equals("")) { init(namespace); } - } catch (IOException e) { - e.printStackTrace(); - } - - ioSocket.onOpen(); - - setCloseTimeout(); - } - - @Override - public void onClose() { - ioSocket.onClose(); - ioSocket.onDisconnect(); - } - - public void init(String path) throws IOException{ - send("1::"+path); - } - - public void init(String path, String query) throws IOException{ - this.send("1::"+path+"?"+query); - - } - - public void sendMessage(IOMessage message) throws IOException{ - send(message.toString()); - } - - public void sendMessage(String message) throws IOException{ - send(new Message(message).toString()); - } - - - public static int genID(){ - currentID++; - return currentID; - } - - public void setNamespace(String ns) { - namespace = ns; - } - - public String getNamespace() { - return namespace; - } - - private void setCloseTimeout() { - closeTimeout = new Timer(); - closeTimeout.schedule(new CloseTask(), ioSocket.getClosingTimeout()); - } - - private void clearCloseTimeout() { - if (closeTimeout != null) { - closeTimeout.cancel(); - closeTimeout = null; - } - } + } catch (Exception e) { + Log.error(e.getMessage()); + } + + ioSocket.onOpen(); + setCloseTimeout(); + } + + @Override + public void onClose(int i, String string, boolean bln) { + ioSocket.onClose(); + ioSocket.onDisconnect(); + } + + @Override + public void onError(Exception excptn) { + + } - private class CloseTask extends TimerTask { - @Override - public void run() { - try { - close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - ioSocket.onDisconnect(); - } - } + private class CloseTask extends TimerTask { + @Override + public void run() { + try { + close(); + } catch (Exception e) { + Log.error(e.getMessage()); + } + ioSocket.onDisconnect(); + } + } } diff --git a/src/com/clwillingham/socket/io/Message.java b/src/com/clwillingham/socket/io/Message.java index b6b5526..71920e3 100644 --- a/src/com/clwillingham/socket/io/Message.java +++ b/src/com/clwillingham/socket/io/Message.java @@ -1,8 +1,8 @@ package com.clwillingham.socket.io; -public class Message extends IOMessage{ +public class Message extends IOMessage { - public Message(String message){ - super(IOMessage.MESSAGE, -1, "", message); - } + public Message(String message) { + super(IOMessage.MESSAGE, -1, "", message); + } } diff --git a/src/com/clwillingham/socket/io/MessageCallback.java b/src/com/clwillingham/socket/io/MessageCallback.java index aa7b6bd..7bc9c5e 100644 --- a/src/com/clwillingham/socket/io/MessageCallback.java +++ b/src/com/clwillingham/socket/io/MessageCallback.java @@ -3,10 +3,10 @@ import org.json.JSONObject; public interface MessageCallback { - public void on(String event, JSONObject... data); - public void onMessage(String message); - public void onMessage(JSONObject json); - public void onConnect(); - public void onDisconnect(); - public void onConnectFailure(); + public void on(String event, JSONObject... data); + public void onMessage(String message); + public void onMessage(JSONObject json); + public void onConnect(); + public void onDisconnect(); + public void onConnectFailure(); } diff --git a/src/com/clwillingham/socket/io/log/DefaultLog.java b/src/com/clwillingham/socket/io/log/DefaultLog.java new file mode 100644 index 0000000..1ad49bb --- /dev/null +++ b/src/com/clwillingham/socket/io/log/DefaultLog.java @@ -0,0 +1,20 @@ +package com.clwillingham.socket.io.log; + +public class DefaultLog implements LogAdapter { + + @Override + public void info(String message) { + System.out.println("INFO: " + message); + } + + @Override + public void warning(String message) { + System.out.println("WARNING: " + message); + } + + @Override + public void error(String message) { + System.err.println("ERROR: " + message); + } + +} diff --git a/src/com/clwillingham/socket/io/log/Log.java b/src/com/clwillingham/socket/io/log/Log.java new file mode 100644 index 0000000..0a32877 --- /dev/null +++ b/src/com/clwillingham/socket/io/log/Log.java @@ -0,0 +1,28 @@ +package com.clwillingham.socket.io.log; + +public class Log { + public static LogAdapter logger; + + public static LogAdapter getInstance() { + if (logger == null) { + logger = new DefaultLog(); + } + return logger; + } + + public static void setInstance(LogAdapter adapter) { + logger = adapter; + } + + public static void info(String message) { + getInstance().info(message); + } + + public static void warning(String message) { + getInstance().warning(message); + } + + public static void error(String message) { + getInstance().error(message); + } +} diff --git a/src/com/clwillingham/socket/io/log/LogAdapter.java b/src/com/clwillingham/socket/io/log/LogAdapter.java new file mode 100644 index 0000000..6455c7b --- /dev/null +++ b/src/com/clwillingham/socket/io/log/LogAdapter.java @@ -0,0 +1,7 @@ +package com.clwillingham.socket.io.log; + +public interface LogAdapter { + public void info(String message); + public void warning(String message); + public void error(String message); +}