How do you handle missing DB objects in Ratpack

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

How do you handle missing DB objects in Ratpack

Marek Piechut
Hi.

How do you handle things like missing DB objects in Ratpack?
I want to return 404 status code when something requested by user was not found and to stop chains from processing rest of the code.

What I do now is that i call context.clientError(404) and throw custom NotFound exception to stop handler from further processing.

But I don't like this solution very much and it gives me some netty server errors:

io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
	at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:102)
	at io.netty.handler.codec.http.DefaultFullHttpRequest.release(DefaultFullHttpRequest.java:77)
	at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:68)
	at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:110)
	at ratpack.server.internal.NettyHandlerAdapter.channelRead(NettyHandlerAdapter.java:122)
	at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:326)
	at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
	at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:326)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:326)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:155)
	at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:326)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:116)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:494)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:461)
	at io.netty..nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:378)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:350)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
	at java.lang.Thread.run(Thread.java:744)
rus
Reply | Threaded
Open this post in threaded view
|

Re: How do you handle missing DB objects in Ratpack

rus

I think you just need to do clientError 404, no need to throw any exception. Take a look at example-books where there is an example of this

On 3 Apr 2014 20:39, "Marek Piechut [via Ratpack Forum]" <[hidden email]> wrote:
Hi.

How do you handle things like missing DB objects in Ratpack?
I want to return 404 status code when something requested by user was not found and to stop chains from processing rest of the code.

What I do now is that i call context.clientError(404) and throw custom NotFound exception to stop handler from further processing.

But I don't like this solution very much and it gives me some netty server errors:

io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
	at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:102)
	at io.netty.handler.codec.http.DefaultFullHttpRequest.release(DefaultFullHttpRequest.java:77)
	at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:68)
	at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:110)
	at ratpack.server.internal.NettyHandlerAdapter.channelRead(NettyHandlerAdapter.java:122)
	at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:326)
	at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
	at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:326)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:326)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:155)
	at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:326)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:116)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:494)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:461)
	at io.netty..nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:378)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:350)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
	at java.lang.Thread.run(Thread.java:744)



If you reply to this email, your message will be added to the discussion below:
http://forum.ratpack.io/How-do-you-handle-missing-DB-objects-in-Ratpack-tp402.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: How do you handle missing DB objects in Ratpack

Marek Piechut
But then rest of handler code is executed and what I get is NullPointerException anyway.
I would need a lot of defensive null checking and make code uglier to read.

I thought that maybe there’s a better way to do checks like that.
Maybe something like Playframework:
http://www.playframework.com/documentation/1.1.1/api/play/mvc/Controller.html#notFoundIfNull(java.lang.Object)

rus
Reply | Threaded
Open this post in threaded view
|

Re: How do you handle missing DB objects in Ratpack

rus

Could you post your code?

On 3 Apr 2014 20:59, "Marek Piechut [via Ratpack Forum]" <[hidden email]> wrote:
But then rest of handler code is executed and what I get is NullPointerException anyway.
I would need a lot of defensive null checking and make code uglier to read.

I thought that maybe there’s a better way to do checks like that.
Maybe something like Playframework:
http://www.playframework.com/documentation/1.1.1/api/play/mvc/Controller.html#notFoundIfNull(java.lang.Object)




If you reply to this email, your message will be added to the discussion below:
http://forum.ratpack.io/How-do-you-handle-missing-DB-objects-in-Ratpack-tp402p404.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: How do you handle missing DB objects in Ratpack

rus
In reply to this post by Marek Piechut

I see, you want to replace your own if null check with a method that does the null check and only sends the client error if the object is null

On 3 Apr 2014 20:59, "Marek Piechut [via Ratpack Forum]" <[hidden email]> wrote:
But then rest of handler code is executed and what I get is NullPointerException anyway.
I would need a lot of defensive null checking and make code uglier to read.

I thought that maybe there’s a better way to do checks like that.
Maybe something like Playframework:
http://www.playframework.com/documentation/1.1.1/api/play/mvc/Controller.html#notFoundIfNull(java.lang.Object)




If you reply to this email, your message will be added to the discussion below:
http://forum.ratpack.io/How-do-you-handle-missing-DB-objects-in-Ratpack-tp402p404.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: How do you handle missing DB objects in Ratpack

Marek Piechut
In reply to this post by rus
What I have now looks like this:

Chain:
get(':webId/peers') { UserService users ->
            def user = users.findByWebId(pathTokens.webId)
            notFoundIfNull(context, user)
            def peers = users.findPeers(user)
            def result = peers.collect { k, v -> [discipline: k, peers: v] }
            render json(result)
        }

class Responses {
    static final notFoundIfNull(context, object) {
        if (object == null) {
            context.clientError(SC_NOT_FOUND)
            throw new NotFound()
        }
    }

    static class NotFound extends RuntimeException {}
}
rus
Reply | Threaded
Open this post in threaded view
|

Re: How do you handle missing DB objects in Ratpack

rus

Hmmm, I find that less clear actually. As a reader of that code its not obvious that processing stops if the object is null. You certainly don't want to be throwing an exception there. I think to get what you're trying to work you'd need your method to accept a closure of what to do if the object isn't null and do your if null else check in the class

On 3 Apr 2014 21:04, "Marek Piechut [via Ratpack Forum]" <[hidden email]> wrote:
What I have now looks like this:

Chain:
get(':webId/peers') { UserService users ->
            def user = users.findByWebId(pathTokens.webId)
            notFoundIfNull(context, user)
            def peers = users.findPeers(user)
            def result = peers.collect { k, v -> [discipline: k, peers: v] }
            render json(result)
        }

class Responses {
    static final notFoundIfNull(context, object) {
        if (object == null) {
            context.clientError(SC_NOT_FOUND)
            throw new NotFound()
        }
    }

    static class NotFound extends RuntimeException {}
}



If you reply to this email, your message will be added to the discussion below:
http://forum.ratpack.io/How-do-you-handle-missing-DB-objects-in-Ratpack-tp402p407.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: How do you handle missing DB objects in Ratpack

Marek Piechut
Good idea.
What I did now is:

Add ifFound method to GroovyContext expando:
GroovyContext.metaClass.ifFound = { object, closure ->
    Responses.ifFound(delegate, object, closure)
}

and got code like this in chain:
get(':webId/peers') { UserService users ->
    def user = users.findByWebId(pathTokens.webId)
    ifFound(user) {
        def peers = users.findPeers(user)
        def result = peers.collect { k, v -> [discipline: k, peers: v] }
        render json(result)
    }
}

I think it looks quite nice. What do you think?
Reply | Threaded
Open this post in threaded view
|

Re: How do you handle missing DB objects in Ratpack

Luke Daley
Administrator
I agree we need to do something here. I have been considering adding a special ClientException that users can throw to trigger client exceptions. One problem with this though is that there is a performance penalty when throwing exceptions. We could probably design around this though. I like the idea of a method that continues if not null. We could add this to Context…
void <T> ifNotNull(T thing, Action<? super T> action);
Would allow code like this…
ifNotNull(db.findPerson3) {
  render it.name
}
Would be worth considering a promise/chaining like API here too. Also need to consider what role observables could play here.
Reply | Threaded
Open this post in threaded view
|

Re: How do you handle missing DB objects in Ratpack

Marek Piechut
I’ve been messing with it little bit more, and it starts looking not that good when mixing with RxJava.

About exceptions, you could limit penalty by not constructing stack traces in exceptions:

but I’m not sure if exceptions are best way to handle things like this. On the other side it is an exceptional situation when user requested something nonexistent or passed in some invalid data.

On 04 Apr 2014, at 00:22, Luke Daley [via Ratpack Forum] <[hidden email]> wrote:

I agree we need to do something here. I have been considering adding a special ClientException that users can throw to trigger client exceptions. One problem with this though is that there is a performance penalty when throwing exceptions. We could probably design around this though. I like the idea of a method that continues if not null. We could add this to Context…
void <T> ifNotNull(T thing, Action<? super T> action);
Would allow code like this…
ifNotNull(db.findPerson3) {
  render it.name
}
Would be worth considering a promise/chaining like API here too. Also need to consider what role observables could play here.


If you reply to this email, your message will be added to the discussion below:
http://forum.ratpack.io/How-do-you-handle-missing-DB-objects-in-Ratpack-tp402p410.html
To unsubscribe from How do you handle missing DB objects in Ratpack, click here.
NAML

Reply | Threaded
Open this post in threaded view
|

Re: How do you handle missing DB objects in Ratpack

Luke Daley
Administrator
I'm liking the idea of ClientException more and more.