code: public final ChannelFuture handshake(Channel channel, final ChannelPromise promise) {
          FullHttpRequest request =  newHandshakeRequest();
  
          HttpResponseDecoder decoder = channel.pipeline().get(HttpResponseDecoder.class);
          if (decoder == null) {
              HttpClientCodec codec = channel.pipeline().get(HttpClientCodec.class);
              if (codec == null) {
                 promise.setFailure(new IllegalStateException("ChannelPipeline does not contain " +
                         "a HttpResponseDecoder or HttpClientCodec"));
                 return promise;
              }
          }
  
          channel.writeAndFlush(request).addListener(new ChannelFutureListener() {
              @Override
              public void operationComplete(ChannelFuture future) {
                  if (future.isSuccess()) {
                      ChannelPipeline p = future.channel().pipeline();
                      ChannelHandlerContext ctx = p.context(HttpRequestEncoder.class);
                      if (ctx == null) {
                          ctx = p.context(HttpClientCodec.class);
                      }
                      if (ctx == null) {
                          promise.setFailure(new IllegalStateException("ChannelPipeline does not contain " +
                                  "a HttpRequestEncoder or HttpClientCodec"));
                          return;
                      }
                      p.addAfter(ctx.name(), "ws-encoder", newWebSocketEncoder());
  
                      promise.setSuccess();
                  } else {
                      promise.setFailure(future.cause());
                  }
              }
          });
          return promise;
      }
docs: Begins the opening handshake
  
  @param channel
  Channel
  @param promise
  the {@link ChannelPromise} to be notified when the opening handshake is sent