public void run() throws IOException {
      final FutureImpl<String> completeFuture = SafeFutureImpl.create();

      // Build HTTP client filter chain
      FilterChainBuilder clientFilterChainBuilder = FilterChainBuilder.newInstance();
      // Add transport filter
      clientFilterChainBuilder.add(new TransportFilter());

      // Add HttpClientFilter, which transforms Buffer <-> HttpContent
      clientFilterChainBuilder.add(new HttpClientFilter());
      // Add ClientFilter
      clientFilterChainBuilder.add(new ClientFilter(completeFuture));

      // Initialize Transport
      final TCPNIOTransport transport = TCPNIOTransportBuilder.newInstance().build();
      // Set filterchain as a Transport Processor
      transport.setFilterChain(clientFilterChainBuilder.build());

      try {
        // start the transport
        transport.start();

        Connection connection = null;

        // Connecting to a remote Web server
        Future<Connection> connectFuture = transport.connect(HOST, PORT);
        try {
          // Wait until the client connect operation will be completed
          // Once connection has been established, the POST will
          // be sent to the server.
          connection = connectFuture.get(10, TimeUnit.SECONDS);

          // Wait no longer than 30 seconds for the response from the
          // server to be complete.
          String result = completeFuture.get(30, TimeUnit.SECONDS);

          // Display the echoed content
          System.out.println("\nEchoed POST Data: " + result + '\n');
        } catch (Exception e) {
          if (connection == null) {
            LOGGER.log(Level.WARNING, "Connection failed.  Server is not listening.");
          } else {
            LOGGER.log(Level.WARNING, "Unexpected error communicating with the server.");
          }
        } finally {
          // Close the client connection
          if (connection != null) {
            connection.closeSilently();
          }
        }
      } finally {
        // shutdownNow the transport
        transport.shutdownNow();
      }
    }
  @Test
  public void testShutdownHandler() throws Exception {
    final FutureImpl<Boolean> shutdownFuture = SafeFutureImpl.create();
    final ShutdownHandler shutDownHandler =
        new ShutdownHandler() {

          @Override
          public void onShutdown(Connection initiator) {
            shutdownFuture.result(true);
          }
        };

    AjpAddOn myAjpAddon =
        new AjpAddOn() {

          @Override
          protected AjpHandlerFilter createAjpHandlerFilter() {
            final AjpHandlerFilter filter = new AjpHandlerFilter();
            filter.addShutdownHandler(shutDownHandler);
            return filter;
          }
        };

    final NetworkListener listener = httpServer.getListener(LISTENER_NAME);

    listener.deregisterAddOn(ajpAddon);
    listener.registerAddOn(myAjpAddon);

    startHttpServer(
        new HttpHandler() {

          @Override
          public void service(Request request, Response response) throws Exception {}
        },
        "/");

    final MemoryManager mm = listener.getTransport().getMemoryManager();
    final Buffer request = mm.allocate(512);
    request.put((byte) 0x12);
    request.put((byte) 0x34);
    request.putShort((short) 1);
    request.put(AjpConstants.JK_AJP13_SHUTDOWN);
    request.flip();

    send("localhost", PORT, request);
    final Boolean b = shutdownFuture.get(10, TimeUnit.SECONDS);
    assertTrue(b);
  }
  @SuppressWarnings("unchecked")
  @Override
  public NextAction handleEvent(final FilterChainContext ctx, final FilterChainEvent event)
      throws IOException {

    final Object type = event.type();
    if (type == ContinueEvent.class) {
      final ContinueEvent continueEvent = (ContinueEvent) event;
      ((ExpectHandler) continueEvent.getContext().getBodyHandler()).finish(ctx);
    } else if (type == TunnelRequestEvent.class) {
      // Disable SSL for the time being...
      ctx.notifyDownstream(new SSLSwitchingEvent(false, ctx.getConnection()));
      ctx.suspend();
      TunnelRequestEvent tunnelRequestEvent = (TunnelRequestEvent) event;
      final ProxyServer proxyServer = tunnelRequestEvent.getProxyServer();
      final URI requestUri = tunnelRequestEvent.getUri();

      RequestBuilder builder = new RequestBuilder();
      builder.setMethod(Method.CONNECT.getMethodString());
      builder.setUrl("http://" + getAuthority(requestUri));
      Request request = builder.build();

      AsyncHandler handler =
          new AsyncCompletionHandler() {
            @Override
            public Object onCompleted(Response response) throws Exception {
              if (response.getStatusCode() != 200) {
                PROXY_AUTH_FAILURE.set(ctx.getConnection(), Boolean.TRUE);
              }
              ctx.notifyDownstream(new SSLSwitchingEvent(true, ctx.getConnection()));
              ctx.notifyDownstream(event);
              return response;
            }
          };
      final GrizzlyResponseFuture future =
          new GrizzlyResponseFuture(grizzlyAsyncHttpProvider, request, handler, proxyServer);
      future.setDelegate(SafeFutureImpl.create());

      grizzlyAsyncHttpProvider.execute(
          ctx.getConnection(), request, handler, future, HttpTxContext.get(ctx));
      return ctx.getSuspendAction();
    }

    return ctx.getStopAction();
  }
  @SuppressWarnings({"unchecked"})
  private Future<Buffer> send(String host, int port, Buffer request) throws Exception {
    final FutureImpl<Buffer> future = SafeFutureImpl.create();

    final FilterChainBuilder builder = FilterChainBuilder.newInstance();
    builder.add(new TransportFilter());

    builder.add(new AjpClientMessageFilter());
    builder.add(new ResultFilter(future));

    SocketConnectorHandler connectorHandler =
        TCPNIOConnectorHandler.builder(
                (TCPNIOTransport) httpServer.getListener(LISTENER_NAME).getTransport())
            .filterChain(builder.build())
            .build();

    Future<Connection> connectFuture = connectorHandler.connect(host, port);
    final Connection connection = connectFuture.get(10, TimeUnit.SECONDS);

    connection.write(request);

    return future;
  }