title: Asynchronous HTTP client with Netty
body: <p>I'm new to netty and still strugling to find my way. I'm looking to create an http client that works asynchronously.
  The netty examples of http only show how to wait for IO operations, and not how to use <em>addListener</em>, and so I've been trying to figure this out for the last few days.</p>
  
  <p>I'm trying to create a request class that will handle all of the different states of a request, from connecting, sending the data, handling the response and then closing of the connection.
  In order to do that my class extends <em>SimpleChannelUpstreamHandler</em> and implements <em>ChannelFutureListener</em>. I use a <em>ChannelPipelineFactory</em> which adds the (this) instance the class (as a <em>SimpleChannelUpstreamHandler</em>) to the pipeline as a handler.</p>
  
  <p>The connection is created like this:</p>
  
  <pre><code>this.state = State.Connecting;
  this.clientBootstrap.connect(this.address).addListener(this);
  </code></pre>
  
  <p>Then the <em>operationComplete</em> method:</p>
  
  <pre><code>@Override
  public void operationComplete(ChannelFuture future) throws Exception {
      State oldState = this.state;
  
      if (!future.isSuccess()) {
          this.status = Status.Failed;
          future.getChannel().disconnect().addListener(this);
      }
      else if (future.isCancelled()) {
          this.status = Status.Canceled;
          future.getChannel().disconnect().addListener(this);
      }
      else switch (this.state) {
          case Connecting:
              this.state = State.Sending;
              Channel channel = future.getChannel();
              channel.write(this.createRequest()).addListener(this);
              break;
  
          case Sending:
              this.state = State.Disconnecting;
              future.getChannel().disconnect().addListener(this);
              break;
  
          case Disconnecting:
              this.state = State.Closing;
              future.getChannel().close().addListener(this);
              break;
  
          case Closing:
              this.state = State.Finished;
              break;
      }
      System.out.println("request operationComplete start state: " + oldState + ", end state: " + this.state + ", status: " + this.status);
  }
  
  private HttpRequest createRequest() {
      String url = this.url.toString();
  
      HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, url);
      request.setHeader(HttpHeaders.Names.HOST, this.url.getHost());
      request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
      request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
  
      return request;
  }
  </code></pre>
  
  <p>The class also overrides the <em>messageReceived</em> method:</p>
  
  <pre><code>@Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
      System.out.println("messageReceived");
      HttpResponse response = (HttpResponse) e.getMessage();
  
      ChannelBuffer content = response.getContent();
      if (content.readable()) {
          System.out.println("CONTENT: " + content.toString(CharsetUtil.UTF_8));
      }
  }
  </code></pre>
  
  <p>The problem is that I get this output:</p>
  
  <pre><code>request operationComplete start state: Connecting, end state: Sending, status: Unknown
  request operationComplete start state: Sending, end state: Disconnecting, status: Unknown
  request operationComplete start state: Closing, end state: Finished, status: Unknown
  request operationComplete start state: Disconnecting, end state: Finished, status: Unknown
  </code></pre>
  
  <p>As you can see the <em>messageReceived</em> of the is not being executed for some reason, even though the pipeline factory adds the instance of this class to the pipeline.</p>
  
  <p>Any ideas what I'm missing here?
  Thanks.</p>
  
  <hr>
  
  <h1>Edit</h1>
  
  <p>I managed to finally get this working thanks to the help of @JestanNirojan, in case someone will be interested in the solution:</p>
  
  <pre><code>public class ClientRequest extends SimpleChannelUpstreamHandler {
  
      ....
  
      public void connect() {
          this.state = State.Connecting;
          System.out.println(this.state);
          this.clientBootstrap.connect(this.address);
      }
  
      @Override
      public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
          this.state = State.Sending;
          System.out.println(this.state);
          ctx.getChannel().write(this.createRequest());
      }
  
      @Override
      public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
          HttpResponse response = (HttpResponse) e.getMessage();
  
          ChannelBuffer content = response.getContent();
          if (content.readable()) {
              System.out.println("CONTENT: " + content.toString(CharsetUtil.UTF_8));
          }
  
          this.state = State.Disconnecting;
          System.out.println(this.state);
      }
  
      @Override
      public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
          this.state = State.Closing;
          System.out.println(this.state);
      }
  
      @Override
      public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
          this.state = State.Finished;
          System.out.println(this.state);
      }
  
      private HttpRequest createRequest() {
          String url = this.url.toString();
  
          HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, url);
          request.setHeader(HttpHeaders.Names.HOST, this.url.getHost());
          request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
          request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
  
          return request;
      }
  }
  </code></pre>