Wednesday, July 15, 2009

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

Now comes the second part of the tutorial to create a basic chat.

In the last part we created the base of the interface and the base of the server.
Now we will create the Persistence Manager.

Create a new package under the server package named persist.

Now create a Class named PMF. Here is the code:

public final class PMF {


private static final PersistenceManagerFactory pmfInstance = JDOHelper.getPersistenceManagerFactory("transactions-optional");


private PMF(){ }

public static final PersistenceManagerFactory getFactory(){

return pmfInstance;

}

public static final PersistenceManager getManager(){

return getFactory().getPersistenceManager();

}

public static final void saveObject(Object obj){

getManager().makePersistent(obj);

}

}

This class uses the PersistenceManagerFactory to get a PersistenceManager. This manager is responsable for saving, updating and deleting the objects. (Notice that this class is very simple just to explain this example).
Now open the Shout class. We need to set the time that the message was sent.
Add the Date field sentAt to it.

@Persistent

private Date sentAt;

also great the get and set for this field.
Now change the shoutToServer method of the ShoutServiceImpl class. This is the code:

public String shoutToServer(Shout s){

s.setSentAt(new Date());

PMF.saveObject(s);

return s.getMessage();

}

we just set the date to today and save the message.
Now all of our messages been saved. We need now to display them on the browser.
Create a method getAllShouts in the ShoutServiceImpl class. This is the code:

public List getAllShouts() {

Query query = PMF.getManager().newQuery(Shout.class);

query.setOrdering("sentAt ascending");

List resultset = (List)query.execute();

return resultset;

}

Here we get the PersistenceManager and create a new query based on the Shout class.
next we order the results acording to the sentAt field.
This will return all the messages in the server.
Next we need to create a method that will return only messages newer than a date we will pass.
Create a method called get getNewerThan that will receive a Date parameter. This is the code:

public List getNewerThan(Date now) {

PersistenceManager manager = PMF.getManager();

Query q = manager.newQuery(Shout.class);

ArrayList result = new ArrayList();

List resultset = (List)q.execute();

for (Shout a: resultset){

if (a.getSentAt().after(now)){

result.add(a);

}

}

return result;

}

Here we filter the messages to the ones that were sent only after some specific date. We will need this to update the browser with new messages.
Now we need to update the ShoutService and ShoutServiceAsync with this methods too. Here are the codes:
ShoutService:

public List getAllShouts();

public List getNewerThan(Date now);

ShoutServiceAsycn:

void getAllShouts(AsyncCallback> callback);

void getNewerThan(Date now, AsyncCallback> callback);

Now that your interfaces are updated let's change the EntryPoint (The .java).

First create a Date attribute called lastUpdatedAt and a Timer attribute caled t.
Here is the code:

final VerticalPanel messagesPanel = new VerticalPanel();

private Date lastUpdatedAt;

Timer t;

private void checkMessages(){

t.schedule(1000);

}

private void configureTimers(){

t = new Timer(){

@Override

public void run() {

shoutService.getNewerThan(lastUpdatedAt, new AsyncCallback>(){

public void onFailure(Throwable caught) {

checkMessages();

}

public void onSuccess(List result) {

if (result.size() > 0){

for (Shout i: result){

messagesPanel.add(new HTML(i.getMessage()));

}

lastUpdatedAt = result.get(result.size()-1).getSentAt();

}

checkMessages();

};

});

}

};

}

Here we created the Timer and the Date attributes and also changed the scope of the messagesPanel, making it accessible to all methods in the class.
In the checkMessages() method we just start the Timer, and the timer will get all the messages that were sent after the last message received.
Don't forget to remove the messagesPanel from inside the onModuleLoad method.

Finally add this to the end of the onModuleLoad method:

configureTimers();

shoutService.getAllShouts(new AsyncCallback>(){

public void onFailure(Throwable caught) {

checkMessages();

}

public void onSuccess(List result) {

for (Shout i: result){

messagesPanel.add(new HTML(i.getMessage()));

if (i.getSentAt().after(lastUpdatedAt)){

lastUpdatedAt = i.getSentAt();

}

}

checkMessages();

}

});

this will configure the timer object and also get all the messages that were sent before opening the page.
This will also start the Timer, that will loop now forever.

Here we got our chat. Later you may add a name's field to identify who is sending the message if you want.

That's all folks!
Next i will teach how to send this project online to Google AppEngine.

Until there!

1 comment:

  1. I know this is an old post of yours but I set about making something similar to this using dates at the method for which messages should be sent back but I have a method which will get the date for the client from the server.

    public date getDate(){
    call an async call to get the server date
    }

    and I pass this back to the server asking for messages after this date. I did this to remove the complications with different clients having different dates set on their machines. The problem is in a local environment this works perfectly but when hosted on the app server no chat messages are displayed!

    ReplyDelete