View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
5    * "License"); you may not use this file except in compliance with the License. You may obtain a
6    * copy of the License at:
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software distributed under the License
11   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing permissions and limitations under
13   * the License.
14   */
15  package io.netty.example.http2.client;
16  
17  import io.netty.buffer.ByteBuf;
18  import io.netty.channel.ChannelHandlerContext;
19  import io.netty.channel.ChannelPromise;
20  import io.netty.channel.SimpleChannelInboundHandler;
21  import io.netty.handler.codec.http.FullHttpResponse;
22  import io.netty.handler.codec.http2.HttpUtil;
23  import io.netty.util.CharsetUtil;
24  
25  import java.util.Iterator;
26  import java.util.Map.Entry;
27  import java.util.SortedMap;
28  import java.util.TreeMap;
29  import java.util.concurrent.TimeUnit;
30  
31  /**
32   * Process {@link FullHttpResponse} translated from HTTP/2 frames
33   */
34  public class HttpResponseHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
35  
36      private SortedMap<Integer, ChannelPromise> streamidPromiseMap;
37  
38      public HttpResponseHandler() {
39          streamidPromiseMap = new TreeMap<Integer, ChannelPromise>();
40      }
41  
42      /**
43       * Create an association between an anticipated response stream id and a {@link ChannelPromise}
44       *
45       * @param streamId The stream for which a response is expected
46       * @param promise The promise object that will be used to wait/notify events
47       * @return The previous object associated with {@code streamId}
48       * @see HttpResponseHandler#awaitResponses(long, TimeUnit)
49       */
50      public ChannelPromise put(int streamId, ChannelPromise promise) {
51          return streamidPromiseMap.put(streamId, promise);
52      }
53  
54      /**
55       * Wait (sequentially) for a time duration for each anticipated response
56       *
57       * @param timeout Value of time to wait for each response
58       * @param unit Units associated with {@code timeout}
59       * @see HttpResponseHandler#put(int, ChannelPromise)
60       */
61      public void awaitResponses(long timeout, TimeUnit unit) {
62          Iterator<Entry<Integer, ChannelPromise>> itr = streamidPromiseMap.entrySet().iterator();
63          while (itr.hasNext()) {
64              Entry<Integer, ChannelPromise> entry = itr.next();
65              ChannelPromise promise = entry.getValue();
66              if (!promise.awaitUninterruptibly(timeout, unit)) {
67                  throw new IllegalStateException("Timed out waiting for response on stream id " + entry.getKey());
68              }
69              if (!promise.isSuccess()) {
70                  throw new RuntimeException(promise.cause());
71              }
72              System.out.println("---Stream id: " + entry.getKey() + " received---");
73              itr.remove();
74          }
75      }
76  
77      @Override
78      protected void messageReceived(ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception {
79          Integer streamId = msg.headers().getInt(HttpUtil.ExtensionHeaderNames.STREAM_ID.text());
80          if (streamId == null) {
81              System.err.println("HttpResponseHandler unexpected message received: " + msg);
82              return;
83          }
84  
85          ChannelPromise promise = streamidPromiseMap.get(streamId);
86          if (promise == null) {
87              System.err.println("Message received for unknown stream id " + streamId);
88          } else {
89              // Do stuff with the message (for now just print it)
90              ByteBuf content = msg.content();
91              if (content.isReadable()) {
92                  int contentLength = content.readableBytes();
93                  byte[] arr = new byte[contentLength];
94                  content.readBytes(arr);
95                  System.out.println(new String(arr, 0, contentLength, CharsetUtil.UTF_8));
96              }
97  
98              promise.setSuccess();
99          }
100     }
101 }