Inter-Handler information bus

classic Classic list List threaded Threaded
19 messages Options
Reply | Threaded
Open this post in threaded view
|

Inter-Handler information bus

Neeraj
Hi ,

Ran into a very basic question... and i apologize if there is an obvious answer that i have not been able to grok.
How do handlers communicate their outputs to downstream handlers ?
e.g : Auth handler validates and hydrates User object.Then needs to make it available for subsequent handlers/middleware

Here are a few mechanisms i see possible at this point :

1. Use Context.insert(handlers, registry)* methods to build a chain of handlers that have access to a custom registry. This custom registry could be used to store User object
Cons : Not sure Context.insert* methods are meant for request level processing and if this would even work.. Also the groovy dsl code would be ugly and not very clear due to heavy indentation.

2. AuthHandler decorates Context.request object ('Context.request.metaclass.authUser') to create 'Request' instance scoped metaclass that downstream handlers can access.
Cons: Not sure this is the right way either, since it is difficult to test this code... InvocationBuilder/Invocation do not expose the request object.

3. Use methods out of handlers directly in the groovy DSL(ratpack.groovy)
Cons: It would clutter up the groovy DSL and would also appear to be pointless in not leveraging handler concepts.

Appreciate any help/feedback.
Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Luke Daley
Administrator
The registry is supposed to be the mechanism here. So something like your #1.

At the moment you can't push into the registry for the downstream handlers; you have to push on when you attach the handlers. This allows you to segment and isolate parts of an application. If you're using the Groovy DSL then this does require nesting.

Perhaps what we are missing is just a way to push into the registry without attaching handlers. So something like this…

handlers {
 handler {
   if (hasUser()) {
     insert(new User()) // adds object to registry and implicitly calls next()
   } else {
     next()
   }
 }
 get {
   User user = get(User)
 }
}


That's technically possible.
Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Neeraj
Context.insert(type, obj) would be something i would use...... I do not see my codebase needing to use the mechanism  Context.insert(<handlers>, obj), especially since most of my basic handlers do their work in the 'handle' method and not in the groovy DSL.
Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Luke Daley
Administrator
I've raised an issue for this here: https://github.com/ratpack/ratpack/issues/183
Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Luke Daley
Administrator
Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Neeraj
I am attempting to authenticate a user in a module registered handler, then add it to the registry using the 'next' method. I can successfully access this user from the registry in all other downstream module registered handlers. But I am unable to access this information from handlers defined in ratpack.groovy.

AuthHandler :
void handle(Context context) {
            //Authenticate/fetch user
            User authUser = .....
            if(authUser)
                context.next(registry(User.class, authUser))
            else {
                context.response.status(401, 'Unauthorized').send()
               return
           }
            // proceed to next handler
            ...
}

ratpack.groovy:
 handlers {
       handler('api/test') {
           this.maybeGet(User.class) // returns null
       }
 }

Are handlers in ratpack.groovy not considered downstream to module registered handlers ?


Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Marcin Erdmann

How/where do you register the AuthHandler?

On Feb 2, 2014 4:26 PM, "Neeraj [via Ratpack Forum]" <[hidden email]> wrote:
I am attempting to authenticate a user in a module registered handler, then add it to the registry using the 'next' method. I can successfully access this user from the registry in all other downstream module registered handlers. But I am unable to access this information from handlers defined in ratpack.groovy.

AuthHandler :
void handle(Context context) {
            //Authenticate/fetch user
            User authUser = .....
            if(authUser)
                context.next(registry(User.class, authUser))
            else {
                context.response.status(401, 'Unauthorized').send()
               return
           }
            // proceed to next handler
            ...
}

ratpack.groovy:
 handlers {
       handler('api/test') {
           this.maybeGet(User.class) // returns null
       }
 }

Are handlers in ratpack.groovy not considered downstream to module registered handlers ?





If you reply to this email, your message will be added to the discussion below:
http://forum.ratpack.io/Inter-Handler-information-bus-tp207p344.html
To start a new topic under Ratpack Forum, email [hidden email]
To unsubscribe from Ratpack Forum, click here.
NAML
Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Neeraj
I use a HandlerDecoratingModule impl to create the handler. I need to create different handlers based on environment.

class AuthModule extends AbstractModule implements HandlerDecoratingModule {

 @Override
    protected void configure() {
        bind(AuthenticationService).to(AuthenticationService)
        bind(TestAuthenticationService)
    }

    @Override
    Handler decorate(Injector injector, Handler handler) {
        def env = injector.getInstance(Key.get(String.class, Names.named("ENVIRONMENT")))
        if(env == 'dev') {
            new AuthHandler(rest: handler, authService: injector.getInstance(TestAuthenticationService))
        } else {
            new AuthHandler(rest: handler, authService: injector.getInstance(AuthenticationService))
        }
    }
}
Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Marcin Erdmann
As you are decorating the root handler you probably want to use insert (http://www.ratpack.io/manual/0.9.1/api/ratpack/handling/Context.html#insert(ratpack.registry.Registry, ratpack.handling.Handler...)) instead of next() to put a user instance in registry. See ratpack-session (https://github.com/ratpack/ratpack/blob/master/ratpack-session/src/main/java/ratpack/session/internal/SessionBindingHandler.java) for an example of how to put something in the registry for downstream handlers.


On Sun, Feb 2, 2014 at 4:39 PM, Neeraj [via Ratpack Forum] <[hidden email]> wrote:
I use a HandlerDecoratingModule impl to create the handler. I need to create different handlers based on environment.

class AuthModule extends AbstractModule implements HandlerDecoratingModule {

 @Override
    protected void configure() {
        bind(AuthenticationService).to(AuthenticationService)
        bind(TestAuthenticationService)
    }

    @Override
    Handler decorate(Injector injector, Handler handler) {
        def env = injector.getInstance(Key.get(String.class, Names.named("ENVIRONMENT")))
        if(env == 'dev') {
            new AuthHandler(rest: handler, authService: injector.getInstance(TestAuthenticationService))
        } else {
            new AuthHandler(rest: handler, authService: injector.getInstance(AuthenticationService))
        }
    }
}


If you reply to this email, your message will be added to the discussion below:
http://forum.ratpack.io/Inter-Handler-information-bus-tp207p346.html
To start a new topic under Ratpack Forum, email [hidden email]
To unsubscribe from Ratpack Forum, click here.
NAML

Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Neeraj

Just to clarify, i require an arbitrary object to be added to the registry and be accessible by downstream handlers. If you look up the chain of this thread, Luke added the 'next'  method to satisfy this particular need.

sample usage from documentation for context.next :    

    upstreamhandler:
          context.next(registry(SomeThing.class, new SomeThingImpl()));

   downstreamhandler :
          SomeThing someThing = context.get(SomeThing.class); // instance provided upstream

Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Marcin Erdmann
It depends on what you describe as downstream handlers. You can partition your application in two ways and Luke tries to describe it here: http://www.ratpack.io/manual/0.9.1/context.html#partitioning.

Basically what you were asking about before was for a usecase that involved passing something down to chained handlers as you were doing it in the dsl - handlers that are next in the chain but not part of the same insertion. When using HandlerDecoratingModule on the other hand you are dealing with the root handler only, you decorate that handler and there isn't a next handler. That's why you should use insert just as the SessionBindingHandler does. This concept is very hard to explain (next vs inject) and Luke had problems with explaining it to me as well. When you get it it's obvious but it's very hard to get there.


On Sun, Feb 2, 2014 at 5:45 PM, Neeraj [via Ratpack Forum] <[hidden email]> wrote:

Just to clarify, i require an arbitrary object to be added to the registry and be accessible by downstream handlers. If you look up the chain of this thread, Luke added the 'next'  method to satisfy this particular need.

sample usage from documentation for context.next :    

    upstreamhandler:
          context.next(registry(SomeThing.class, new SomeThingImpl()));

   downstreamhandler :
          SomeThing someThing = context.get(SomeThing.class); // instance provided upstream




If you reply to this email, your message will be added to the discussion below:
http://forum.ratpack.io/Inter-Handler-information-bus-tp207p348.html
To start a new topic under Ratpack Forum, email [hidden email]
To unsubscribe from Ratpack Forum, click here.
NAML

rus
Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

rus
In reply to this post by Neeraj
Take a look at this handler which is also added via HandlerDecoratingModule https://github.com/ratpack/ratpack/blob/master/ratpack-codahale-metrics/src/main/java/ratpack/codahale/metrics/internal/RequestTimingHandler.java

Even though it doesnt need to add anything into the registry, notice how it uses insert instead of next to add the rest of the handlers.
Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Neeraj
After changing my code to use insert :

    context.insert(registry(User, authUser), handler)

i can now access this authUser object from the groovy dsl.

I am still a little confused between the difference between 'next' and 'insert' and how the registry is propagated in either case.

'Insert' uses the next handler as a new chain starting point(index = 0) and passes on a union of existing registry and new registry passed in.

'next' passes on the union of registries to the next handler. It appears that the 'nextIndex' is (wrongly?) assigned to the ClientErrorForwardingHandler rather than the real 'next' handler.

I would think the difference in behavior of 'next' vs 'insert' would be more along the lines of

next : ability to continue path of execution down the chain, with handlers decorating the registry WITHOUT needing to create new sub-chains.

insert: ability to create new sub-chains dynamically with new registry entries scoped to these sub-chains.

thank you for the help.
Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Luke Daley
Administrator
You need to use insert() because you're using a decorating handler, which fundamentally has to insert.

HandlerDecoratingModule implementation receive a Handler impl which represents the “rest” of the handlers, which is effectively everything described in ratpack.groovy handlers {}. All you can do here is return a new handler that inserts this “rest” handler. next() doesn't work because the next handler for the handler returned by the module is going to be the 404 (end of processing handler).

Pushing into the registry on next() is more useful when you are laying out handlers using the DSL, because there you actually will have a next.
                     

rus
Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

rus
In reply to this post by Neeraj
I've been thinking a bit more about this and Google Guice doesn't really recommend putting conditional logic into Modules like this.  From what I've seen they promote more of a Module per implementation approach.

Also, using HandlerDecoratingModule means you haven't got much control over where this auth handler is within the chain.  What if you need to have unsecured handlers?

Another approach I've experimented with is using the Ratpack JustInTimeInjectorRegistry along with using a property to define the implementation class I wish to use.  So I have a property

    other.auth.impl=foo.AuthHandler2

and my handler chain looks like this

  handlers {

      def authHandlerImpl = launchConfig.getOther("auth.impl", "foo.AuthHandler1")
      handler(registry.get(Class.forName(authHandlerImpl)))

      handler {
          def user = get(FooUser.class)
          render user.username
      }

    }

and my Handler looks like this

    class AuthHandler2 extends GroovyHandler {

        @Override
        protected void handle(GroovyContext context) {
            def user = new FooUser(username: "Mike")
            context.next(registry(FooUser.class, user))
        }

    }

 I can then change the property value for each environment.

Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Neeraj
In reply to this post by Luke Daley
That makes sense. Appreciate the clarification.

The documentation for HandlerDecoratingModule should probably explain the level at which it operates(or maybe it already does).

Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Neeraj
In reply to this post by rus
In my use-case all paths are secured. But yes, i see your point.

My assumption was that all handlers registered from HandlerDecoratingModules are executed in the order of module registration. Is this not right ?

I like the use of JustInTimeInjectorRegistry and will try that out as a better alternative.

Thank you for the suggestions.
Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Luke Daley
Administrator
> My assumption was that all handlers registered from HandlerDecoratingModules are executed in the order of module registration. Is this not right ?

That's correct. If that's not happening it's a bug.

Reply | Threaded
Open this post in threaded view
|

Re: Inter-Handler information bus

Luke Daley
Administrator
In reply to this post by Neeraj

> The documentation for HandlerDecoratingModule should probably explain the level at which it operates(or maybe it already does).

That's a fair point. I'll add something.