@Override
  public void bind(InetSocketAddress addr, int backlog) throws IOException {
    // check if there is already a connector listening
    Collection<NetworkConnector> connectors = _server.getBeans(NetworkConnector.class);
    if (connectors != null) {
      for (NetworkConnector connector : connectors) {
        if (connector.getPort() == addr.getPort()) {
          if (LOG.isDebugEnabled())
            LOG.debug("server already bound to port " + addr.getPort() + ", no need to rebind");
          return;
        }
      }
    }

    if (_serverShared) throw new IOException("jetty server is not bound to port " + addr.getPort());

    this._addr = addr;

    if (LOG.isDebugEnabled()) LOG.debug("binding server to port " + addr.getPort());
    ServerConnector connector = new ServerConnector(_server);
    connector.setPort(addr.getPort());
    connector.setHost(addr.getHostName());
    _server.addConnector(connector);

    _connectors.put(addr.getHostName() + addr.getPort(), connector);
  }
  @Test
  public void testGracefulShutdown() throws Exception {
    ObjectMapper objectMapper = Jackson.newObjectMapper();
    Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
    MetricRegistry metricRegistry = new MetricRegistry();
    Environment environment =
        new Environment(
            "test", objectMapper, validator, metricRegistry, ClassLoader.getSystemClassLoader());

    CountDownLatch requestReceived = new CountDownLatch(1);
    CountDownLatch shutdownInvoked = new CountDownLatch(1);

    environment.jersey().register(new TestResource(requestReceived, shutdownInvoked));

    final ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
    final Server server = http.build(environment);

    ((AbstractNetworkConnector) server.getConnectors()[0]).setPort(0);

    ScheduledFuture<Void> cleanup =
        executor.schedule(
            new Callable<Void>() {
              @Override
              public Void call() throws Exception {
                if (!server.isStopped()) {
                  server.stop();
                }
                executor.shutdownNow();
                return null;
              }
            },
            5,
            TimeUnit.SECONDS);

    server.start();

    final int port = ((AbstractNetworkConnector) server.getConnectors()[0]).getLocalPort();

    Future<String> futureResult =
        executor.submit(
            new Callable<String>() {
              @Override
              public String call() throws Exception {
                URL url = new URL("http://localhost:" + port + "/app/test");
                URLConnection connection = url.openConnection();
                connection.connect();
                return CharStreams.toString(new InputStreamReader(connection.getInputStream()));
              }
            });

    requestReceived.await();

    Future<Void> serverStopped =
        executor.submit(
            new Callable<Void>() {
              @Override
              public Void call() throws Exception {
                server.stop();
                return null;
              }
            });

    Connector[] connectors = server.getConnectors();
    assertThat(connectors).isNotEmpty();
    assertThat(connectors[0]).isInstanceOf(NetworkConnector.class);
    NetworkConnector connector = (NetworkConnector) connectors[0];

    // wait for server to close the connectors
    while (true) {
      if (!connector.isOpen()) {
        shutdownInvoked.countDown();
        break;
      }
      Thread.sleep(5);
    }

    String result = futureResult.get();
    assertThat(result).isEqualTo("test");

    serverStopped.get();

    // cancel the cleanup future since everything succeeded
    cleanup.cancel(false);
    executor.shutdownNow();
  }