mardi 22 mars 2011

Push to individual users with atmosphere framework and GWT

Warning
This is really a draft. It is just working but I'm sure there is better way to do that. Need approving from more experimented atmosphere developers.


The idea behind pushing to individual user is to assign a broadcaster with an id (you get the id from the request parameter for example) to atmosphere resource representing a user (browser). The broadcaster need to be added to the broadcaster factory. Now, at anytime you can get this broadcaster by issuing a lookup by id.


In the previous post we have seen how to setup atmosphere-gwt-demo project under Eclipse. When your run the atmosphere-gwt-demo project you get a window that shows 6 buttons: post request, poll, broadcast, open child window, send to the child window and a stop comet button.


In this post, I'll describes steps I followed to find my way to push to individual users.

The scenario is simple:

An external server send notifications as http post request with one parameter that identifies the target user, the atmosphereHandler receives the notification and send a message to the appropriate browser (The one that has login with the same id)

AtmosphereClient initialization

AtmosphereClient initialization happens in the GWT entry point
org.atmosphere.samples.client.GWTDemo

In the onModuleLoad we call the initialize() method:

public void initialize() {

        MyCometListener cometListener = new MyCometListener();

        AtmosphereGWTSerializer serializer = GWT.create(EventSerializer.class);
        // set a small length parameter to force refreshes
        // normally you should remove the length parameter
        System.out.println("Client url is "+GWT.getModuleBaseURL());
        
//retrieve the login from the browser GET request 
        String login = com.google.gwt.user.client.Window.Location.getParameter("login");
        client = new AtmosphereClient(GWT.getModuleBaseURL()+"gwtComet"+"?login="+login, serializer, cometListener);
        
        client.start();
    }

The AtmosphereClient establish a connection with an atmosphereHandler at this url
GWT.getModuleBaseURL()+"gwtComet
We are using a cometListener which listens to events coming from the atmosphereHandler through the onMessage(), onHeartbeat(), onError(), etc...

I've add the login request parameter to identify each browser(user)

The server side: The atmosphereHandler

When you call client.start(), the onRequest() method of the atmosphereHandler get called

@Override
public void onRequest(AtmosphereResource resource) throws IOException {
HttpServletRequest request = resource.getRequest();


String login_key = "login";
String login_value = request.getParameter(login_key);
if(login_value != null){
    //add this broadcaster to the broadcasterFactory
    addBroadcasterToFactory(resource, login_value);
}


//external server request
if (request.getMethod().equalsIgnoreCase("POST")) {
 String for_key="for";
 String for_value = request.getParameter(for_key);
 
 if(for_value != null && for_value.length() > 0){
  System.out.println("Received a notification, going to notify user "+for_value);
  
  // Single Connection/Session
  Broadcaster singleBroadcaster= BroadcasterFactory.getDefault().lookup(DefaultBroadcaster.class, for_value);
            
  singleBroadcaster.broadcast("My first push. User "+for_value);
  
  return;
 }
}

super.onRequest(resource);
}
In this method we are trying to add a broadcaster to the BroadcasterFactory with the id of the user being login in.

In the other hand, if the request is a post (Notification from external server) we lookup the broadcaster then push something.

The addBroadcasterToFactory is as follow:

public void addBroadcasterToFactory(AtmosphereResource resource, String broadcasterID){
     
  Broadcaster singleBroadcaster= BroadcasterFactory.getDefault().lookup(DefaultBroadcaster.class, bdct);
  if(singleBroadcaster != null){
   resource.setBroadcaster(singleBroadcaster); //each browser opened by this user will receive the same push message
   return false;
  }
     
     Broadcaster selfBroadcaster = new DefaultBroadcaster(broadcasterID);
     selfBroadcaster.setID(broadcasterID);
     resource.setBroadcaster(selfBroadcaster);

     boolean added = BroadcasterFactory.getDefault().add(selfBroadcaster, broadcasterID);
     System.out.println("Was broadcaster added? "+added);
}
In this method we created a defaultBroadcaster with the broadcasterID (user id) and assign it the atmosphere resource.

Running our example:

Open a browser and enter the following url:

http://localhost:8888/gwtDemo/gwtDemo.jsp?login=reda&gwt.codesvr=127.0.0.1:9997
This browser will listen to push request.

Send notification:

Make the following post request (I used chrome with Client REST simple extension)
http://localhost:8888/gwtDemo/gwtComet?for=reda&gwt.codesvr=127.0.0.1:9997

You should now see a notification on the client browser.


Hope this helps someone who tries to achieve the same. There may be better ways of doing this. I think I will have to use this approach until someone suggests a better solution.

Aucun commentaire:

Enregistrer un commentaire