11

RestTemplate example is below.

public class SimpleClient {

    private final String URL;
    private AsyncRestTemplate rest = new AsyncRestTemplate(new Netty4ClientHttpRequestFactory());
    private RestTemplate restTemplate = new RestTemplate(new Netty4ClientHttpRequestFactory());

    public SimpleClient(String url) {
        this.URL = url;
        Netty4ClientHttpRequestFactory nettyFactory = new Netty4ClientHttpRequestFactory();
        try {
                    nettyFactory.setSslContext(SslContextBuilder.forClient().build());
        } catch (SSLException e) {
            e.printStackTrace();
        }
        rest = new AsyncRestTemplate(nettyFactory);
    }

    @Override
    public ResponseEntity<ResponseData> doSendByPOST(RequestData data,Class<ResponseData> clazz) {

        List<HttpMessageConverter<?>> messageConvertors = new ArrayList<>();
        messageConvertors.add(new MappingJackson2HttpMessageConverter());

        rest.setMessageConverters(messageConvertors);
        restTemplate.setMessageConverters(messageConvertors);

        HttpHeaders headers = new HttpHeaders();
        ObjectMapper objectMapper = new ObjectMapper();
        StringWriter writer = new StringWriter();
        try {
            objectMapper.writeValue(writer, data);
        } catch (IOException e) {
            e.printStackTrace();
        }
        headers.set(HttpHeaders.CONTENT_LENGTH,String.valueOf(writer.toString().getBytes(Charset.forName("UTF-8")).length));
        headers.set(HttpHeaders.CONTENT_TYPE,"application/json");
        HttpEntity<ResponseData> request = new HttpEntity<ResponseData>(headers);

        MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
        try {
            parts.add("requestData", objectMapper.writeValueAsString(data));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

//      return restTemplate.exchange(this.URL,HttpMethod.POST ,request, clazz, parts);

        ListenableFuture<ResponseEntity<ResponseData>> entity =  rest.exchange(this.URL,HttpMethod.POST ,request, clazz, parts);
        return extractResponseEntity(entity);
    }
    // ...
}

Netty read data from request channelRead method

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

    if (msg instanceof HttpRequest) {
        DefaultHttpRequest defaultHttpRequest = (DefaultHttpRequest) msg;
        if (EmptyHttpHeaders.is100ContinueExpected(defaultHttpRequest)) {
            ctx.write(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.CONTINUE));
        }

        boolean keepAlive = EmptyHttpHeaders.isKeepAlive(defaultHttpRequest);


        handle = frontController.dispatchRequest(defaultHttpRequest);

    }
    if (msg instanceof HttpContent) {
        HttpContent httpContent = (HttpContent) msg;
        ByteArrayOutputStream body = new ByteArrayOutputStream(64);
        ByteBuf content = httpContent.content();
        if (content.isReadable()) {
            //body.write(content.array());
            content.readBytes(body,content.readableBytes());
            //body.append(content.toString(CharsetUtil.UTF_8));
            FullHttpResponse response = handle.handle(body);
            if(response == null){
                response = prepareDefaultResponse();
            }

            response.headers().set("content-type", "application/json");
            response.headers().set("content-length", response.content().readableBytes());
            response.headers().set("connection", HttpHeaderValues.KEEP_ALIVE);

        }

        if (msg instanceof LastHttpContent) {
            //process request
            ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
        }
    }

The code below is working fine but I guess there is a problem with blocking io and nonblocking io. When the request is dispatched, I can not reach the HttpContent I only get HttpRequest as a msg parameter. Spring resttemplate waits for a response but Netty does not care :)

 if (msg instanceof HttpRequest) {
     DefaultHttpRequest defaultHttpRequest = (DefaultHttpRequest) msg;
     if (EmptyHttpHeaders.is100ContinueExpected(defaultHttpRequest)) {
         ctx.write(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.CONTINUE));
     }

     boolean keepAlive = EmptyHttpHeaders.isKeepAlive(defaultHttpRequest);


     handle = frontController.dispatchRequest(defaultHttpRequest);

 }

My problem is how to get response from netty server by rest template. I have tried many ways to accomplish full req/resp. When restTemplate request to Netty server it hangs the thread so I can not move on the distributed in memory cache implementation.

Hanging in RestTemplate.java Line : 681

Method waits forever when using Netty4ClientHttpRequestFactory.

response = request.execute();
kakabali
  • 3,824
  • 2
  • 29
  • 58
Gurkan İlleez
  • 1,503
  • 1
  • 10
  • 12
  • Do you know what line it hangs on? There is a lot going on there and it might help to have a bit more context on what you are seeng. – Tristan Jan 09 '18 at 15:04
  • I updated my problem. Thread hangs at rest template because it waits for operation to go on communication – Gurkan İlleez Jan 09 '18 at 18:52
  • 3
    You should give the exact line where it hangs, and reduce your code to the parts that are relevant. – tkruse Jan 10 '18 at 03:46
  • I think point is to provide precise information, in a way that others can track the problem. Full code example can be good, since I can put it all, and start tracking, but place where it fails / hangs is also needed. I can place trap there... – Michał Zaborowski Jan 11 '18 at 12:43
  • can you post your extractResponseEntity method? – Wilder Valera Jan 11 '18 at 18:45
  • It is callable so it just extract data. "entity.get(TIMEUNIT.seconds,30)" something like this – Gurkan İlleez Jan 12 '18 at 06:07
  • But if you call entity.get(), you will block then until the answer becomes available (or until the 30s are up) - is this where your thread is blocking? – moilejter Aug 04 '18 at 20:43

1 Answers1

1

From my understanding, you read HTTP post request that from Rest Client as HttpRequest Object lets call it first case so that means you don't even branch on the if (msg instanceof HttpContent) {} case (second one) your HTTP server just writes the default response without any content or header that you're setting in the second case. If this is the cause for the blocking on the client side you have to fill that default response just like on the second case an see what client do.

I think netty API provides this https://netty.io/4.1/api/io/netty/handler/codec/http/DefaultFullHttpResponse.html

Also this example could give you an idea of what could be wrong server side. http://www.seepingmatter.com/2016/03/30/a-simple-standalone-http-server-with-netty.html

Alican Beydemir
  • 343
  • 2
  • 13