Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guava EventBus: How to return result from event handler

I have a web service which receives xml events from another system, process them using specific workflow and sends a list of potentials errors back as HTTP response.

Event processing workflow consists of several handlers (let's say: Preprocessor, Persister and Validator) implemented using Guava's EventBus. Handlers send events to each other. Something like this:

public class RequestHandler {

    @RequestMapping
    public Errors handleRequest(String xmlData) {
        eventBus.post(new XmlReceivedEvent(xmlData));
        ...
        return errors; // how to get errors object from the last handler in chain ? 
    }
}

public class Preprocessor {

    @Subscribe
    public void onXmlReceived(XmlReceivedEvent event) {
       // do some pre-processing
       ...  
       eventBus.post(new PreprocessingCompleteEvent(preprocessingResult)); 
    }
}

public class Persister {

    @Subscribe
    public void onPreprocessingComplete(PreprocessingCompleteEvent event) {
       // do some persistence stuff
       ...    
       eventBus.post(new PersistenceCompleteEvent(persistenceResult)); 
    }
}

public class Validator {

    @Subscribe
    public void onPersistenceComplete(PersistenceCompleteEvent event) {
       // do validation
       ...    
       eventBus.post(new ValidationCompleteEvent(errors)); // errors object created, should be returned back to the RequestHandler 
    }
}

The problem is: how to return the processing result deeply from Validator handler back to the starting point (RequestHandler), so user can receive HTTP response ?

I consider two options:

  1. Set errors object to the initial XmlReceivedEvent and retrieve it after processing complete:

    public class RequestHandler {
    
        @RequestMapping
        public Errors handleRequest(String xmlData) {
            XmlReceivedEvent event = new XmlReceivedEvent(xmlData);
            eventBus.post(event);
            ...
            return event.getErrors(); 
        }
    }
    

However, in that case I will have to pass errors object to each event in the chain to make it available for Validator to fill it with real data.

  1. Subscribe RequestHandler to ValidationCompleteEvent from Validator with populated errors object inside.

    public class RequestHandler {
    
        private Errors errors;
    
        @RequestMapping
        public Errors handleRequest(String xmlData) {
            XmlReceivedEvent event = new XmlReceivedEvent(xmlData);
            eventBus.post(event);
            ...
            return this.errors; // ??? 
        }
    
        @Subscribe
        public void onValidationComplete(ValidationCompleteEvent event) {
            this.errors = event.getErrors();
        }
    }
    

But, unfortunately, RequestHandler is a Spring stateless service (singleton), so I would like to avoid saving any data in class fields.

Appreciate any ideas.

like image 329
stoweesh Avatar asked Dec 27 '22 02:12

stoweesh


1 Answers

If you want a workflow like that, you shouldn't be using a Guava EventBus for it. EventBus is specifically intended to allow events to be posted to subscribers without the event poster knowing or caring about what those subscribers are... as such, you can't return results to the poster of an event from subscribers.

It sounds to me like you should be doing something much more straightforward here, like injecting your preprocessor, persister and validator and calling their methods directly.

like image 99
ColinD Avatar answered Dec 29 '22 16:12

ColinD