2. Client Configuration

Join Code Example

The AppBase is the parent of App. AppBase is used as a class without an Dojo Cometd dependencies so it can be launched in GWT hosted mode for basic debugging and looking at the GUI layout.

This excerpt from AppBase.onModuleLoad() adds a ClickListenter to the join button. When the button is clicked, the user name is set from the text field, the join method is called, the join panel's visibility is set to false, and the main chat panel is added. The join method in AppBase doesn't do anything, but the child class, App, overrides the join method and calls out to a native JavaScript method which calls Dojo Cometd to subscribe to chat.

Example 2. Join Code Example (excerpt from AppBase.java)

Excerpt from web/chat-webapp/src/main/java/org/springbyexample/web/gwt/chat/client/AppBase.java

                    
joinButton.addClickListener(new ClickListener() {
    public void onClick(Widget sender) {
        userName = joinChatTextBox.getText();
        join(userName);

        joinChatPanel.setVisible(false);
        chatPanel.add(sendChatPanel, DockPanel.SOUTH);
        
        chatTextBox.setFocus(true);
    }
});
                    
                

The join method is native and has special comments before and after the body so the GWT compiler can process the method into JavaScript. The app variable makes a reference to this for use in the anonymous inner function. The call to external JavaScript starts with $wnd which indicates to the GWT compiler that what follows $wnd. is a native JavaScript call that is calling room.join. The room.join takes the user's name and three callbacks to GWT. The first one is for displaying messages, the second is for displaying a user joining, and the last is to clear the user table.

Inside the first anonymous function, it is configured to take from and text values for displaying a chat message. The app variable created about is used to reference the App class. This is the special syntax the GWT compiler uses to make a reference from JavaScrip to GWT generated JavaScript. You'll notice that an @ symbol is put before the full class name, which is then followed by '::' and the name of the method along with it's signature. Right after that the variables passed into the function are passed into App.display(String from, String text) (method actually located in AppBase).

Example 3. Join Code Example (excerpt from App.java)

Excerpt from web/chat-webapp/src/main/java/org/springbyexample/web/gwt/chat/client/App.java

                    
protected native void join(String userName) /*-{
    // Keep reference to self for use inside closure
    var app = this;
    
    $wnd.room.join(userName, 
        function(from, text) { 
            app.@org.springbyexample.web.gwt.chat.client.App::display(Ljava/lang/String;Ljava/lang/String;)(from, text);
        },
        function(user) { 
            app.@org.springbyexample.web.gwt.chat.client.App::addUser(Ljava/lang/String;)(user);
        },
        function() { 
            app.@org.springbyexample.web.gwt.chat.client.App::clearUserTable()();
        }
    );
}-*/;
                    
                

This shows the JavaScript function being called from GWT to join the chat room ($wnd.room.join).

Example 4. Join Code Example (excerpt from gwt-chat.js)

Excerpt from src/main/webapp/js/gwt-chat.js

                    
join: function(userName, displayCallback, addUserCallback, clearUserTableCallback) {
	if (userName == null || userName.length == 0) {
		alert('Please enter a username!');
		return;
	}

    var hostName = window.location.hostname;
    var port = window.location.port;
    var contextPath = "\/chat";
    
    var host = "http:\/\/" + hostName;
    
    if (port) {
    	host += ":" + port;
    }
    
    host += contextPath;
    
    dojox.cometd.init(host + "\/cometd\/chat\/");  1

    room.connected = true;		
    room.userName = userName;
    room.displayCallback = displayCallback;  2
    room.addUserCallback = addUserCallback;
    room.clearUserTableCallback = clearUserTableCallback;
    
    // subscribe and join
    dojox.cometd.startBatch();  3
    dojox.cometd.subscribe("/chat/demo", room, "processMessageEvent");  4
    dojox.cometd.publish("/chat/demo", {  5    
    	user: room.userName,
    	join: true,
    	chat: room.userName + " has joined"
    });
    dojox.cometd.endBatch();  6
    
    ...
       
},
                    
                
1 This makes the main connection to Bayeux using Dojo Cometd's init function.
2 This sets the GWT callback for displaying a chat message when this code receives a message.
3 Dojo Cometd's startBatch() is called to batch together subscribing to the chat room and publishing the current user has joined the room.
4 This method subscribes to /chat/demo and configures the callback to be the room variable's processMessageEvent function.
5 Dojo Cometd's publish function publishes that the current user has just joined the room so other chat users are notified.
6 This line ends the current batch so it can be processed.

Send Code Example

This excerpt from AppBase.onModuleLoad() adds a KeyboardListener to the text box that listens for the enter key being pressed to send a messag, and a ClickListenter to the the send button.

Example 5. Send Code Example (excerpt from AppBase.java)

Excerpt from web/chat-webapp/src/main/java/org/springbyexample/web/gwt/chat/client/AppBase.java

                    
chatTextBox.addKeyboardListener(new KeyboardListener() {
    public void onKeyDown(Widget sender, char keyCode, int modifiers) {
    }

    public void onKeyPress(Widget sender, char keyCode,
            int modifiers) {
        if (keyCode == KEY_ENTER) {
            send(chatTextBox.getText());
            chatTextBox.setText("");
        }                    
    }

    public void onKeyUp(Widget sender, char keyCode, int modifiers) {
    }                
});

Button sendButton = new Button();
sendButton.setText(sendLabel);
sendButton.addClickListener(new ClickListener() {
    public void onClick(Widget sender) {
        send(chatTextBox.getText());
        chatTextBox.setText("");
    }
});
                    
                

This is the send method being called by the KeyboardListener and ClickListenter defined for send that calls the native JavaScript method $wnd.room.chat.

Example 6. Send Code Example (excerpt from App.java)

Excerpt from web/chat-webapp/src/main/java/org/springbyexample/web/gwt/chat/client/App.java

                    
protected native void send(String message) /*-{   
    $wnd.room.chat(message);  
}-*/;
                    
                

Below is the JavaScript function being called from GWT to send a chat message ($wnd.room.chat).

Example 7. Send Code Example (excerpt from gwt-chat.js)

Excerpt from src/main/webapp/js/gwt-chat.js

                    
chat: function(text) {
    if (!text || !text.length) {
        return false;
    }

    dojox.cometd.publish("/chat/demo", {  1
        user: room.userName,
        chat: text
    });
},
                    
                
1 Dojo Cometd's publish function to the /chat/demo channel sending user and chat message.

Leave Code Example

The leave button has a ClickListener that leaves the chat room, clears the screen and chat panel, then shows the join panel so the user can rejoin the chat.

Example 8. Leave Code Example (excerpt from AppBase.java)

Excerpt from web/chat-webapp/src/main/java/org/springbyexample/web/gwt/chat/client/AppBase.java

                    
leaveButton.addClickListener(new ClickListener() {
    public void onClick(Widget sender) {
        leave(userName);
        chatTextBox.setText("");
        chatPanel.remove(sendChatPanel);

         clearUserTable();
         clearChatTable();
         
        joinChatPanel.setVisible(true);
    }
});
                    
                

The leave method calls the native JavaScript room's leave function.

Example 9. Leave Code Example (excerpt from App.java)

Excerpt from web/chat-webapp/src/main/java/org/springbyexample/web/gwt/chat/client/App.java

                    
protected native void leave(String userName) /*-{
    $wnd.room.leave();
}-*/;
                    
                

The leave function doesn't do anything if the user name is null. If the Dojo Cometd meta subscription isn't null, it unsubscribes from the meta channel. Then it begins a batch that unsubscribes from the chat channel and publishes that the user has left the room before ending the batch. At the end it disconnects from Bayeux on the server.

Example 10. Leave Code Example (excerpt from gwt-chat.js)

Excerpt from src/main/webapp/js/gwt-chat.js

                    
leave: function(){
	if (!room.userName) {
		return;
	}
	
	if (room.meta) {
		dojo.unsubscribe(room.meta);
	}
	room.meta = null;
	
	dojox.cometd.startBatch();  1
	dojox.cometd.unsubscribe("/chat/demo", room, "processMessageEvent");  2
	dojox.cometd.publish("/chat/demo", {  3
		user: room.userName,
		leave: true,
		chat: room.userName + " has left"
	});
	dojox.cometd.endBatch();  4
	
	room.userName = null;
	dojox.cometd.disconnect();  5
},
                    
                
1 Dojo Cometd's startBatch() is called to batch together unsubscribing to the chat room and publishing the current user has left the room.
2 This method unsubscribes from /chat/demo and configures the callback to be the room variable's processMessageEvent function.
3 Dojo Cometd's publish function publishes that the current user has just left the room.
4 This line ends the current batch so it can be processed.
5 Dojo Cometd's disconnect function is called to disconnect from Bayeux.