Refactor transport-http response delivery
[netconf.git] / transport / transport-http / src / main / java / org / opendaylight / netconf / transport / http / ClientHttp1RequestDispatcher.java
1 /*
2  * Copyright (c) 2024 PANTHEON.tech s.r.o. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netconf.transport.http;
9
10 import com.google.common.util.concurrent.FutureCallback;
11 import io.netty.channel.Channel;
12 import io.netty.channel.ChannelHandlerContext;
13 import io.netty.handler.codec.http.FullHttpRequest;
14 import io.netty.handler.codec.http.FullHttpResponse;
15 import java.util.Queue;
16 import java.util.concurrent.ConcurrentLinkedQueue;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
19
20 /**
21  * Client side {@link RequestDispatcher} implementation for HTTP 1.1.
22  *
23  * <p>
24  * Serves as gateway to Netty {@link Channel}, performs sending requests to server, returns server responses associated.
25  * Uses request to response mapping via queue -- first accepted response is associated with first request sent.
26  */
27 final class ClientHttp1RequestDispatcher extends ClientRequestDispatcher {
28     private static final Logger LOG = LoggerFactory.getLogger(ClientHttp1RequestDispatcher.class);
29
30     // TODO: we access the queue only from Netty callbacks: can we use a plain ArrayDeque?
31     private final Queue<FutureCallback<FullHttpResponse>> queue = new ConcurrentLinkedQueue<>();
32
33     @Override
34     public void dispatch(final Channel channel, final FullHttpRequest request,
35             final FutureCallback<FullHttpResponse> callback) {
36         channel.writeAndFlush(request).addListener(sent -> {
37             final var cause = sent.cause();
38             if (cause == null) {
39                 queue.add(callback);
40             } else {
41                 callback.onFailure(cause);
42             }
43         });
44     }
45
46     @Override
47     protected void channelRead0(final ChannelHandlerContext ctx, final FullHttpResponse response) {
48         final var callback = queue.poll();
49         if (callback != null) {
50             callback.onSuccess(response);
51         } else {
52             LOG.warn("Unexpected response while no future associated -- Dropping response object {}", response);
53         }
54     }
55 }