Emmanuel John
Emmanuel John

Reputation: 2340

Using JMS messages in grails controller

I have a simple JMS setup. See the following code:

class ProcessingService{
    def jmsService
    def theMethod(){
        jmsService.send(service:'listening', value);
    }
}


 @Transactional
 static scope = "session"
 class ListeningService {
     static expose = ['jms']
     private int value;
     def onMessage(message) {
         value = message;
         println "Completed ${message}"
     }
     int getValue(){
         return value;
     }
}

My question is how do I use the messages delivered from a controller?

Currently I have the following code but I'm not sure this is right since services are designed to be stateless:

class ConsumingController{
    def listeningService
    def method(){
        while(notTimeout){
            log.info(listeningService.getValue())
        }
    }
}

This is my first jms app so please forgive me if the answer seem obvious

Upvotes: 1

Views: 493

Answers (2)

Emmanuel John
Emmanuel John

Reputation: 2340

An alternative that I got to work for me is using the grails-platform-core plugin using the events api.

http://grailsrocks.github.io/grails-platform-core/

and

http://grails.org/plugin/platform-core

Here's what I'm currently doing:

class ExcelService{
    def processMethod(){
         while(not done){
             //do some processing
             event("excelUpdates", completed)
         }

    }
}

//the controller
class ExcelProcessorService {
    @grails.events.Listener
    def excelUpdates(Float completed){
        println "${completed}% of excel processing task completed"
    }
}

I'm not sure how to push the updates to the browser yet or what to do the page is refresh (How to cancel the task) but would post update when I get it done.

Upvotes: 0

Amit
Amit

Reputation: 606

I would prefer using websockets in this case. Check http://grails.org/plugin/atmosphere

Otherwise I would suggest that you push the data to the database and check the database from the controller instead of checking the service.

Since, you experienced problems in getting atmosphere to work, I would to try to explain how I got it working.

  1. Installed the grails atmosphere plugin to get the dependencies.
  2. Added jquery.atmosphere.js to the frontend.
  3. Added a AtmosphereService class (look at the sendData method)

    class AtmosphereService implements AtmosphereHandler{

    static exposes = ['jms']
    
    static transactional = false
    static atmosphere = [mapping: '/atmosphere']
    
    public void sendData(int value, long userId){
        Map result = [value: value];
    
        String broadcastChannel = "/$userId/value";
    
        Broadcaster broadcaster = BroadcasterFactory.default.lookup(broadcastChannel, true);
        broadcaster.broadcast((result as JSON) as String);
    }
    
    public void onRequest(AtmosphereResource resource) throws IOException {
        try {
            AtmosphereRequest req = resource.request
            if (req.method.equalsIgnoreCase("GET")) {
                resource.broadcaster = BroadcasterFactory.default.lookup(req.pathInfo, true);
                resource.suspend();
            } else if (req.method.equalsIgnoreCase("POST")) {
                String stuff = req.reader.readLine().trim()
                resource.broadcaster = BroadcasterFactory.default.lookup(req.pathInfo, true);
                resource.broadcaster.broadcast(stuff);
            }
        } catch (Exception e) {
            log.error("Error in Atmosphere.onRequest", e);
        }
    }
    
    public void onStateChange(AtmosphereResourceEvent event) throws IOException {
        AtmosphereResource r = event.resource
        AtmosphereResponse res = r.response
    
        try {
            if (event.isSuspended()) {
                String body = (event.message) as String;
                res.writer.write( body );
    
                switch (r.transport()) {
                    case TRANSPORT.JSONP:
                    case TRANSPORT.LONG_POLLING:
                        event.resource.resume()
                        break
                    default:
                        res.writer.flush()
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("ERROR in onStateChange", e);
        }
    }
    
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    
    }
    

    }

  4. Add the following js code to listen to the channel "/$userId/value" (Look at the request.onMessage handler)

    var contentType = "application/json";
    var userId = 12312;
    var logLevel = 'debug';
    var shared = 'true';
    var transport = 'websocket';
    var fallbackTransport = 'long-polling';
    var socket = $.atmosphere;
    var partialUpdateRequest=null;
    var atmosphereUrl = BASE_HREF+'/atmosphere';
    var request = { url: atmosphereUrl +"/"+userId+"/value",
                contentType : contentType,
                logLevel : logLevel,
                shared : shared,
                transport : transport,
                fallbackTransport: fallbackTransport
    };
    
    request.onMessage = function (response) {
        var message = response.responseBody;
        try {
            var json = jQuery.parseJSON(message);
            // do your stuff here.
        }catch (e) {
            //return;
        }
    };
    socket.subscribe(request);
    

Upvotes: 1

Related Questions