/* ------------------------------------------------------------ */
  @Override
  protected void doStart() throws Exception {
    if (getStopAtShutdown()) ShutdownThread.register(this);

    LOG.info("jetty-" + __version);
    HttpGenerator.setServerVersion(__version);
    MultiException mex = new MultiException();

    if (_threadPool == null) setThreadPool(new QueuedThreadPool());

    try {
      super.doStart();
    } catch (Throwable e) {
      mex.add(e);
    }

    if (_connectors != null) {
      for (int i = 0; i < _connectors.length; i++) {
        try {
          _connectors[i].start();
        } catch (Throwable e) {
          mex.add(e);
        }
      }
    }

    if (isDumpAfterStart()) dumpStdErr();

    mex.ifExceptionThrow();
  }
  /* ------------------------------------------------------------ */
  @Override
  protected void doStop() throws Exception {
    if (isDumpBeforeStop()) dumpStdErr();

    MultiException mex = new MultiException();

    if (_graceful > 0) {
      if (_connectors != null) {
        for (int i = _connectors.length; i-- > 0; ) {
          LOG.info("Graceful shutdown {}", _connectors[i]);
          try {
            _connectors[i].close();
          } catch (Throwable e) {
            mex.add(e);
          }
        }
      }

      Handler[] contexts = getChildHandlersByClass(Graceful.class);
      for (int c = 0; c < contexts.length; c++) {
        Graceful context = (Graceful) contexts[c];
        LOG.info("Graceful shutdown {}", context);
        context.setShutdown(true);
      }
      Thread.sleep(_graceful);
    }

    if (_connectors != null) {
      for (int i = _connectors.length; i-- > 0; )
        try {
          _connectors[i].stop();
        } catch (Throwable e) {
          mex.add(e);
        }
    }

    try {
      super.doStop();
    } catch (Throwable e) {
      mex.add(e);
    }

    mex.ifExceptionThrow();

    if (getStopAtShutdown()) ShutdownThread.deregister(this);
  }
  /**
   * @throws GridException If failed.
   * @return {@code True} if Jetty started.
   */
  @SuppressWarnings("IfMayBeConditional")
  private boolean startJetty() throws GridException {
    try {
      httpSrv.start();

      if (httpSrv.isStarted()) {
        for (Connector con : httpSrv.getConnectors()) {
          int connPort = ((NetworkConnector) con).getPort();

          if (connPort > 0) ctx.ports().registerPort(connPort, TCP, getClass());
        }

        return true;
      }

      return false;
    } catch (SocketException ignore) {
      if (log.isDebugEnabled()) log.debug("Failed to bind HTTP server to configured port.");

      stopJetty();

      return false;
    } catch (MultiException e) {
      if (log.isDebugEnabled()) log.debug("Caught multi exception: " + e);

      for (Object obj : e.getThrowables())
        if (!(obj instanceof SocketException))
          throw new GridException("Failed to start Jetty HTTP server.", e);

      if (log.isDebugEnabled()) log.debug("Failed to bind HTTP server to configured port.");

      stopJetty();

      return false;
    } catch (Exception e) {
      throw new GridException("Failed to start Jetty HTTP server.", e);
    }
  }
  /**
   * Perform scanning of classes for annotations
   *
   * @param context
   * @throws Exception
   */
  protected void scanForAnnotations(WebAppContext context) throws Exception {
    AnnotationParser parser = createAnnotationParser();
    _parserTasks = new ArrayList<ParserTask>();

    long start = 0;

    if (LOG.isDebugEnabled())
      LOG.debug(
          "Annotation scanning commencing: webxml={}, metadatacomplete={}, configurationDiscovered={}, multiThreaded={}, maxScanWait={}",
          context.getServletContext().getEffectiveMajorVersion(),
          context.getMetaData().isMetaDataComplete(),
          context.isConfigurationDiscovered(),
          isUseMultiThreading(context),
          getMaxScanWait(context));

    parseContainerPath(context, parser);
    // email from Rajiv Mordani jsrs 315 7 April 2010
    //    If there is a <others/> then the ordering should be
    //          WEB-INF/classes the order of the declared elements + others.
    //    In case there is no others then it is
    //          WEB-INF/classes + order of the elements.
    parseWebInfClasses(context, parser);
    parseWebInfLib(context, parser);

    start = System.nanoTime();

    // execute scan, either effectively synchronously (1 thread only), or asynchronously (limited by
    // number of processors available)
    final Semaphore task_limit =
        (isUseMultiThreading(context)
            ? new Semaphore(Runtime.getRuntime().availableProcessors())
            : new Semaphore(1));
    final CountDownLatch latch = new CountDownLatch(_parserTasks.size());
    final MultiException me = new MultiException();

    for (final ParserTask p : _parserTasks) {
      task_limit.acquire();
      context
          .getServer()
          .getThreadPool()
          .execute(
              new Runnable() {
                @Override
                public void run() {
                  try {
                    p.call();
                  } catch (Exception e) {
                    me.add(e);
                  } finally {
                    task_limit.release();
                    latch.countDown();
                  }
                }
              });
    }

    boolean timeout = !latch.await(getMaxScanWait(context), TimeUnit.SECONDS);

    if (LOG.isDebugEnabled()) {
      for (ParserTask p : _parserTasks)
        LOG.debug(
            "Scanned {} in {}ms",
            p.getResource(),
            TimeUnit.MILLISECONDS.convert(p.getStatistic().getElapsed(), TimeUnit.NANOSECONDS));

      LOG.debug(
          "Scanned {} container path jars, {} WEB-INF/lib jars, {} WEB-INF/classes dirs in {}ms for context {}",
          _containerPathStats.getTotal(),
          _webInfLibStats.getTotal(),
          _webInfClassesStats.getTotal(),
          (TimeUnit.MILLISECONDS.convert(System.nanoTime() - start, TimeUnit.NANOSECONDS)),
          context);
    }

    if (timeout) me.add(new Exception("Timeout scanning annotations"));
    me.ifExceptionThrow();
  }