context.next() confusion.

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

context.next() confusion.

JamesL
Hi,

I may be being very silly but I can't for the life of me understand what is going on here.

This works:

ratpack {
        handlers {
                all {
                        next(single('all'))
                }
                all { String message ->
                        render("message = ${message}")
                }
        }
}

This does not:

ratpack {
        handlers {
                path('test') {
                        next(single('all'))
                }
                all { String message ->
                        render("message = ${message}")
                }
        }
}

I get the following stack:

ratpack.registry.NotInRegistryException: No object for type 'java.lang.String' in registry
        at ratpack.registry.Registry.get(Registry.java:136) ~[ratpack-core-1.1.1.jar:na]
        at ratpack.handling.internal.DefaultContext.get(DefaultContext.java:463) ~[ratpack-core-1.1.1.jar:na]
        at ratpack.handling.internal.Extractions.extract(Extractions.java:50) ~[ratpack-core-1.1.1.jar:na]
        at ratpack.handling.internal.Extractions.extract(Extractions.java:32) ~[ratpack-core-1.1.1.jar:na]


Could anybody shed a little light on what I'm doing wrong please?
Thanks in advance, James.
rus
Reply | Threaded
Open this post in threaded view
|

Re: context.next() confusion.

rus
How are you calling the 2nd example?  You would need to be using http://localhost:5050/test to pass through the path handler and add the item to the registry
Reply | Threaded
Open this post in threaded view
|

Re: context.next() confusion.

JamesL
Hi Rus, thanks for the response. Yeah using http://localhost:8005/test?cmd=GetBackLinkData

I thought there may be something "special" about the path handler but it looks pretty simple internally. The request goes through the handler but doesn't seem to interact with the registry as I thought it would. This is the first time I've tried partitioning the request flow like this but it looks like it should work :(

James.
rus
Reply | Threaded
Open this post in threaded view
|

Re: context.next() confusion.

rus
I'll take a proper look now
rus
Reply | Threaded
Open this post in threaded view
|

Re: context.next() confusion.

rus
In reply to this post by JamesL
Your 2nd example doesn't work because the registry that you're adding the object to is not at the same scope as the handler you're trying to use it in.  If that makes sense :s

If you look in ratpack.path.internal.PathHandler#handle you'll see that if the path matches, it inserts your handler using context.insert.  When you're doing next(single('all')) you make that object available to "all downstream handlers that were part of the same insertion".  Your outer all handler is not part of this insertion and is not downstream of this handler.

This is effectively what happens if it makes it easier to see

      all {
        if (request.path == "test") {
          context.insert(
              Groovy.groovyHandler {
                next(single('all'))
              }
          )
        } else {
          next()
        }
      }

      all {
        String message = get(String)
        render("message = ${message}")
      }

The following would have access to the object

      all {
        if (request.path == "test") {
          context.insert(
              Groovy.groovyHandler {
                next(single('all'))
              },
              Groovy.groovyHandler {
                String message = get(String)
                render("message = ${message}")
              }
          )
        } else {
          next()
        }
      }

      all {
        String message = get(String)
        render("message = ${message}")
      }

To get what you're trying to do to work you would need to do

      all {
        if (request.path == "test") {
          next(single('all'))
        }
        next()
      }

      all {
        String message = get(String)
        render("message = ${message}")
      }

Hope that makes some sense
Reply | Threaded
Open this post in threaded view
|

Re: context.next() confusion.

JamesL
Thank you so much for your time Rus!

I think I understand - so the internal call to context.insert(Handler) is creating a nested scope which is where the registry exists? That makes sense (I should learn to read https://ratpack.io/manual/current/context.html#partitioning)

What I'm trying to do is generate responses to different paths but have a single point of rendering, so:

ratpack {
    handlers {
        path("apple") {
            // generate some output.
            SomeOutput output = ...
            next(single(output));
        }
        path("banana") {
            // generate some output.
            SomeOutput output = ...
            next(single(output));
        }
        all { SomeOutput output ->
            render(bufferChunks('text/xml;charset=UTF-8', output))
        }
    }
}


From what you've explained this is not the Ratpack way and it should may be something like:

ratpack {
    handlers {
        path("apple") {
            // generate some output.
            SomeOutput output = ...
            insert(new OutputRenderingHandler(output));
        }
        path("banana") {
            // generate some output.
            SomeOutput output = ...
            insert(new OutputRenderingHandler(output));
        }
    }
}


class OutputRenderingHandler implements Handler {
    SomeOutput output

    void handle(Context context) {
        context.render(bufferChunks('text/xml;charset=UTF-8', output))
    }
}

Any pointers would be much appreciated. I currently have 2 Ratpack apps running in production but they're request handling is fairly basic so this is new ground for me.


James.
rus
Reply | Threaded
Open this post in threaded view
|

Re: context.next() confusion.

rus
There is also a request scoped registry so you could use that

      get("test") {
        request.add('all')
        next()
      }

      all { String message ->
        render("message = ${message}")
      }
Reply | Threaded
Open this post in threaded view
|

Re: context.next() confusion.

JamesL
Awesome :) Thanks so much for your help Rus.

James.
rus
Reply | Threaded
Open this post in threaded view
|

Re: context.next() confusion.

rus
np

You might find our slack channel good to join too http://slack.ratpack.io/