Tuesday, July 14, 2009

How to create a simple chat using GWT and AppEngine - First Part

UPDATED - 2009-07-15 - WEB-INF info

Well, today i will start a series of tutorials about making some stuff in gwt.
We will begin transforming the default project the google eclipse plugin generates.

After installing the google plugin for eclipse (you may find here how to install the plugin), let's create a web application project, by clicking the google blue icon in the toolbar

After you choose your Project Name and the initial package of the project

Also select to use both GWT and App Engine sdks.

This will create a simple project with two main packages:
  • Client
  • Server
In the client package will stay all the code GWT will compile to javascript, and in the server package will stay all the code that will run on the app engine server.

Also the plugin already creates a page with a server communication. It has a textbox and a button, and when you click the button it sends the content of the textbox to the server and get a string to show in the page.

We will also add to this page a list with all the messages sent previously and also update it often using ajax.

So these are the steps we will take:
  1. add a new line to the table in the html
  2. Create a Panel and add it to the line created
  3. Create a model class to represent the message sent - We will call this class "Shout"
  4. Create a service to send this shout to the server
  5. implements the client call to the service

First we will create in the html page (it has the name of the project and stay in the war package) a place to put all of the messages.
We will do this by adding a new line to the table:


what we are doing here is creating a new container to put our panel with the messages.


Now we need to edit the java code to add a new panel in this row.
Open the .java (it is the client package) - We will call this file the EntryPoint, as it implements the EntryPoint interface. We will edit the onModuleLoad method.

Add a new final VerticalPanel and call it messagesPanel

public void onModuleLoad() {

final VerticalPanel messagesPanel = new VerticalPanel();

final Button sendButton = new Button("Send");

final TextBox nameField = new TextBox();


now we will add this panel to the row we created in the html :

// Add the nameField and sendButton to the RootPanel

// Use RootPanel.get() to get the entire body element

RootPanel.get("nameFieldContainer").add(nameField);

RootPanel.get("sendButtonContainer").add(sendButton);

RootPanel.get("messagesContainer").add(messagesPanel);


The RootPanel.get(id) method returns the element in the page with the id we passed, so we can add widgets to it.
Now our panel will be placed right under the textbox and the button.
Well now we need to create the Model class tha will represent the message we are sending.
First let's create a new package under the client package, named "model", and inside this package lets create a new Class, called "Shout".
This class must implements the serialize interface.
Also we need to put some JDO information to be able to save it in the database.
This is the code to the Shout class:

@PersistenceCapable(identityType=IdentityType.APPLICATION)

public class Shout implements Serializable{


@PrimaryKey

@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)

private Long id;

@Persistent

private String message;

public Shout(){}

public Shout(String message){

this.message = message;

}


public String getMessage() {

return message;

}


public void setMessage(String message) {

this.message = message;

}


public Long getId() {

return id;

}

}

The @PersistenceCapable annotation mark this class as persistance and each field that shoud be stored must have the @Persistence annotation on it.

Well now that we have our model we must create a service to send it to the server.
First let's create a ShoutService interface in the client package and also a ShoutServiceAsync interface.
In the first we should add a method that will receive a Shout and return a String, this is the code of the ShoutService:

@RemoteServiceRelativePath("shout")

public interface ShoutService extends RemoteService{


String shoutToServer(Shout s);

}

this interface must extends the RemoteService and also must define the path to access this service using the RemoteServiceRelativePath annottation.

In the ShoutServiceAsync we should add a void method that will receive a Shout object and a AsyncCallback object.
This is the code to the ShoutServiceAsync:

public interface ShoutServiceAsync {


void shoutToServer(Shout s, AsyncCallback callback);

}

Now we need to create the server side service.
Let's create the ShoutServiceImpl in the server package.

@SuppressWarnings("serial")

public class ShoutServiceImpl extends RemoteServiceServlet implements ShoutService{


public String shoutToServer(Shout s){

return s.getMessage();

}

}

this class must extend te RemoteServiceServlet and also implements the interface of the Service we created before. Notice that it implements the Service and not the ServiceAsync.
For now our method will just return the message of the Shout object.
Well, now we are almost there.
Let's change now the behavior of the click of the send button.
Get back to the entrypoint class and create a ShoutServiceAsync final variable:

/**

* Create a remote service proxy to talk to the server-side Greeting service.

*/

private final GreetingServiceAsync greetingService = GWT

.create(GreetingService.class);

private final ShoutServiceAsync shoutService = GWT.create(ShoutService.class);


notice that we declare the service using the Asycn interface, but in the GWT method we use the Service class.

Now, look for the method "sendNameToServer". and remove the code inside it, we wont need it anymore.
next put this code:

sendButton.setEnabled(false);

Shout s = new Shout(nameField.getText());

nameField.setText("");

shoutService.shoutToServer(s, new AsyncCallback(){

public void onFailure(Throwable caught) {};

public void onSuccess(String result) {

messagesPanel.add(new HTML(result));

sendButton.setEnabled(true);

};

});

we are just creating a shout using the text in the textfield, reseting the textfield and calling the service method, passing our shout and the asyncCallback.
In the callback we can do something if the method fails, like by connection reset or a exception in the server using the onFailure method.
In the onSuccess method we put our code to treat the answer of the server.
In this case we are just adding the string into a HTML widget inside the panel. As the panel is a VerticalPanel all this widgets will be placed one under the other.

----UPDATED----------

Also you need to edit the web.xml file inside the WEB-INF directory.
You need to configure your servlets (The ShoutServiceImpl).
Just copy and paste the greetServlet and change the servlet-name to shoutServlet and the servlet-class to your.path.to.ShoutServiceImpl . Also copy and paste the servlet-mapping of the greetServlet and change the servlet-name to shoutServlet and the url-pattern to /[module-name]/shout .
Observe that this /shout is the name we put on the service interface annottation: @RemoteServiceRelativePath("shout").

-----UPDATED-----------

In this is it. In the next post we will save this shout in the database and load the shout list when the page is loaded and keeping updating the list while the page is open.

See you there!

No comments:

Post a Comment