Thursday, March 19, 2009

Messaging With GWT (AJAX)

"Writing web apps today is a tedious and error-prone process. Developers can spend 90% of their time working around browser quirks. In addition, building, reusing, and maintaining large JavaScript code bases and AJAX components can be difficult and fragile. Google Web Toolkit (GWT) eases this burden by allowing developers to quickly build and maintain complex yet highly performant JavaScript front-end applications in the Java programming language." --Quoted from "http://code.google.com/webtoolkit/".

Since version 6.x, Netbeans included plug-ins for GWT/AJAX web application development. This makes writing GWT/AJAX applications a pleasant experience. With just a few clicks, the required GWT/AJAX web application skeleton files are automatically created. A complete war file is also generated when the (GWT/AJAX) web application is successfully built. The Netbeans/GWT tutorial to create a GWT web application is fairly simple to follow:

http://www.netbeans.org/kb/60/web/quickstart-webapps-gwt.html

The GWT quick start guide is at the link here:

http://code.google.com/webtoolkit/

This article provides a simple (GWT/AJAX) code example to send/receive text messages from a browser. A JMS TextMessage sent to a specific (JMS) destination can be received by the AJAX script running in the browser. The example can be modified to receive GWT supported serializable objects. The example looks like (Figure 1) after launched. The text entered in the lower text area is sent to a queue ("myqueue") when the Send button is clicked. The text is then (concurrently) received from the same queue and displayed in the upper text area.










(Figure 1)

The example assumes that you know about 2% of GWT and 0.1% of AJAX. The 2% means you know how to create and write a Hello-World GWT application and how "GWT RPC" works. No AJAX knowledge is required. You do need to know Java and JMS.

The code example is created with Netbeans IDE 6.5 with GWT plug-ins. The example is divided into the following components. AJAX and HTML files generated from GWT compiler and Netbeans IDE are not included here.
  • Creating services (interfaces)
  • Implementing services (interfaces)
  • Making the service calls
1. Creating services.

The interface defined in GWTService allows AJAX clients to send/receive messages on the specified destination name.

GWTService.java

package com.em.gwt.client;
import com.google.gwt.user.client.rpc.RemoteService;

//RPC interface for client to send/receive messages from destination name "destName".

public interface GWTService extends RemoteService {

public String receive (String queueName) throws IllegalStateException;

public void send (String queueName, String msg);
}

GWTServiceAsync.java

package com.em.gwt.client;
import com.google.gwt.user.client.rpc.AsyncCallback;

public interface GWTServiceAsync {

public void receive (String queueName, AsyncCallback callback);
public abstract void send(String queueName, String msg, AsyncCallback asyncCallback);
}


2. Implementing services (interfaces).

The service is implemented with Open Message Queue. So you need to include imq.jar, jms.jar in the IDE project library.

GWTServiceImpl.java

/*
* GWTServiceImpl.java
*
* Created on March 17, 2009, 2:02 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/

package com.em.gwt.server;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.em.gwt.client.GWTService;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.servlet.ServletException;

/**
*
* An example GWT service implementation to receive messages from
* specified JMS destinations.
*/
public class GWTServiceImpl extends RemoteServiceServlet implements
GWTService {

private ConnectionFactory factory = null;
private Connection connection = null;

/**
* This is an example implementation. No connection pooling.
*/
@Override
public void init() throws ServletException {

try {
//get conn facory
factory = new com.sun.messaging.ConnectionFactory();

//create jms connection
connection = factory.createConnection();
//start the connection
connection.start();

log ("Connection started.");
} catch (Exception e) {
log (e.getMessage(), e);
throw new ServletException (e);
}

}

/**
* Receive a message from the specified queue destination name.
*
* The performance can be improved if the session/consumer
* are cached.
*
* @param qname the queue name.
* @return The body of the text message.
*
* @throws java.lang.IllegalStateException if any internal error occurred.
*/
public String receive (String qname) throws IllegalStateException {

String msg = null;
Session session = null;

try {
//create a session
session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//get the queue reference
Queue queue = session.createQueue(qname);
//create a consumer
MessageConsumer consumer = session.createConsumer(queue);

//receive with 10 seconds timeout
Message m = consumer.receive(10000);

//get the body of the message
if (m != null && m instanceof TextMessage) {
msg = ((TextMessage)m).getText();
}

} catch (Exception e) {
msg = e.getMessage();
throw new IllegalStateException (e);
} finally {
close(session);
}

return msg;
}

public void send (String qname, String msg) {

Session session = null;

try {
//create a session
session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//get the queue reference
Queue queue = session.createQueue(qname);
//create a consumer
MessageProducer producer = session.createProducer(queue);

TextMessage tm = session.createTextMessage();
tm.setText(msg);

producer.send(tm);

} catch (Exception e) {
throw new IllegalStateException (e);
} finally {
close(session);
}

return;
}

/**
* close the specified session.
* @param s the session to be closed.
*/
private void close (Session s) {
try {
s.close();
} catch (Exception e) {
log (e.getMessage(), e);
//throw new IllegalStateException (e);
}
}

/**
* close connection when servlet is destroyed.
*/
@Override
public void destroy() {

try {
this.connection.close();
} catch (Exception e) {
log (e.getMessage(), e);
}
}
}


3. Making service calls.

The entry point of the GWT client application. Each message received is updated in the TextArea.

maasEntryPoint.java

package com.em.gwt.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import java.util.Date;

public class maasEntryPoint implements EntryPoint {

private VerticalPanel vp = new VerticalPanel();

private TextArea recvTextArea = new TextArea();

private TextArea sendTextArea = new TextArea();

private Button btnSend = new Button("Send");

private Label recvLabel = new Label ("message received:");

private Label sendLabel = new Label ("message sent:");

private AsyncCallbackRecvImpl recvCallBack = new AsyncCallbackRecvImpl();
private AsyncCallbackSendImpl sendCallBack = new AsyncCallbackSendImpl();

private GWTServiceAsync service = null;

private static final String MYQUEUE = "myqueue";

/** Creates a new instance of maasEntryPoint */
public maasEntryPoint() {
}

/**
* The entry point method, called automatically by loading a module
* that declares an implementing class as an entry-point
*/
public void onModuleLoad() {

vp.add(recvLabel);

recvTextArea.setCharacterWidth(70);

vp.add(recvTextArea);

vp.add(sendTextArea);

btnSend.addClickListener(new SendBtnListener());

vp.add(btnSend);

vp.add(sendLabel);

RootPanel.get().add (vp);

service = getService();

receive();
}

private void receive() {
service.receive(MYQUEUE, recvCallBack);
}

public static GWTServiceAsync getService(){
// Create the client proxy. Note that although you are creating the
// service interface proper, you cast the result to the asynchronous
// version of
// the interface. The cast is always safe because the generated proxy
// implements the asynchronous interface automatically.
GWTServiceAsync service = (GWTServiceAsync) GWT.create(GWTService.class);
// Specify the URL at which our service implementation is running.
// Note that the target URL must reside on the same domain and port from
// which the host page was served.
//
ServiceDefTarget endpoint = (ServiceDefTarget) service;
String moduleRelativeURL = GWT.getModuleBaseURL() + "gwtservice";
endpoint.setServiceEntryPoint(moduleRelativeURL);
return service;
}

class AsyncCallbackRecvImpl implements AsyncCallback {

public void onFailure(Throwable caught) {
recvTextArea.setText("receive failed: " + caught.getMessage());

caught.printStackTrace();
}

public void onSuccess(Object result) {

if (result != null) {
recvTextArea.setText("Received msg = " + (String)result);
}

receive();
}

}

class AsyncCallbackSendImpl implements AsyncCallback {

public void onFailure(Throwable caught) {

sendLabel.setText(new Date() + ": send failed.");

caught.printStackTrace();
}

public void onSuccess(Object result) {

sendLabel.setText(new Date() + ", sent message = " + sendTextArea.getText());

}

}

class SendBtnListener implements ClickListener {

public void onClick(Widget sender) {
String msg = sendTextArea.getText();
if (msg == null || msg.isEmpty()) {
Window.alert("No message entered in send text area.");
} else {
service.send(MYQUEUE, msg, sendCallBack);
}
}

}

}

38 comments:

  1. Always keep your words soft and sweet, just in case you have to eat them.............................................

    ReplyDelete
  2. 生命中最美麗的報償之一便是幫助他人的同時,也幫助了自己。 ..................................................

    ReplyDelete
  3. Circumstances are the rulers of the weak, instrument of the wise.........................................

    ReplyDelete
  4. 來給你加加油~打打氣!!!更新之餘,也要注意休息哦~~........................................

    ReplyDelete
  5. Better be the head of a dog than the tail of a lion...................................................

    ReplyDelete
  6. 才華在逆境中展現,在順境中被掩藏。..................................................

    ReplyDelete
  7. 很喜歡你的部落格 留言支持你 祝你人氣長紅~~~......................................................................

    ReplyDelete
  8. 在莫非定律中有項笨蛋定律:「一個組織中的笨蛋,恆大於等於三分之二。」.................................................................

    ReplyDelete
  9. 當一個人內心能容納兩樣相互衝突的東西,這個人便開始變得有價值了。............................................................

    ReplyDelete
  10. 你不能決定生命的長度,但你可以控制它的寬度..................................................................

    ReplyDelete
  11. 第一忠誠,第二勤奮,第三專心工作。..................................................

    ReplyDelete
  12. 要在憂患恥辱的環境裡,創造我們自力更生的新生活。..................................................

    ReplyDelete
  13. 一時的錯誤不算什麼,錯而不改才是一生中永遠且最大的錯誤..................................................

    ReplyDelete
  14. 心中醒,口中說,紙上作,不從身上習過,皆無用也。..................................................

    ReplyDelete
  15. 知識可以傳授,智慧卻不行。每個人必須成為他自己。..................................................

    ReplyDelete
  16. 人不能像動物一樣活著,而應該追求知識和美德................. ................................................

    ReplyDelete