/**
   * Scan jars in WEB-INF/lib
   *
   * @param context
   * @param parser
   * @throws Exception
   */
  public void parseWebInfLib(final WebAppContext context, final AnnotationParser parser)
      throws Exception {
    List<FragmentDescriptor> frags = context.getMetaData().getFragments();

    // email from Rajiv Mordani jsrs 315 7 April 2010
    // jars that do not have a web-fragment.xml are still considered fragments
    // they have to participate in the ordering
    ArrayList<URI> webInfUris = new ArrayList<URI>();

    List<Resource> jars = context.getMetaData().getOrderedWebInfJars();

    // No ordering just use the jars in any order
    if (jars == null || jars.isEmpty()) jars = context.getMetaData().getWebInfJars();

    _webInfLibStats = new CounterStatistic();

    for (Resource r : jars) {
      // for each jar, we decide which set of annotations we need to parse for
      final Set<Handler> handlers = new HashSet<Handler>();

      FragmentDescriptor f = getFragmentFromJar(r, frags);

      // if its from a fragment jar that is metadata complete, we should skip scanning for
      // @webservlet etc
      // but yet we still need to do the scanning for the classes on behalf of  the
      // servletcontainerinitializers
      // if a jar has no web-fragment.xml we scan it (because it is not excluded by the ordering)
      // or if it has a fragment we scan it if it is not metadata complete
      if (f == null
          || !isMetaDataComplete(f)
          || _classInheritanceHandler != null
          || !_containerInitializerAnnotationHandlers.isEmpty()) {
        // register the classinheritance handler if there is one
        if (_classInheritanceHandler != null) handlers.add(_classInheritanceHandler);

        // register the handlers for the @HandlesTypes values that are themselves annotations if
        // there are any
        handlers.addAll(_containerInitializerAnnotationHandlers);

        // only register the discoverable annotation handlers if this fragment is not metadata
        // complete, or has no fragment descriptor
        if (f == null || !isMetaDataComplete(f)) handlers.addAll(_discoverableAnnotationHandlers);

        if (_parserTasks != null) {
          ParserTask task = new ParserTask(parser, handlers, r, _webAppClassNameResolver);
          _parserTasks.add(task);
          _webInfLibStats.increment();
          if (LOG.isDebugEnabled()) task.setStatistic(new TimeStatistic());
        }
      }
    }
  }
  /**
   * Scan classes in WEB-INF/classes
   *
   * @param context
   * @param parser
   * @throws Exception
   */
  public void parseWebInfClasses(final WebAppContext context, final AnnotationParser parser)
      throws Exception {
    Set<Handler> handlers = new HashSet<Handler>();
    handlers.addAll(_discoverableAnnotationHandlers);
    if (_classInheritanceHandler != null) handlers.add(_classInheritanceHandler);
    handlers.addAll(_containerInitializerAnnotationHandlers);

    _webInfClassesStats = new CounterStatistic();

    for (Resource dir : context.getMetaData().getWebInfClassesDirs()) {
      if (_parserTasks != null) {
        ParserTask task = new ParserTask(parser, handlers, dir, _webAppClassNameResolver);
        _parserTasks.add(task);
        _webInfClassesStats.increment();
        if (LOG.isDebugEnabled()) task.setStatistic(new TimeStatistic());
      }
    }
  }
  /**
   * Scan jars on container path.
   *
   * @param context
   * @param parser
   * @throws Exception
   */
  public void parseContainerPath(final WebAppContext context, final AnnotationParser parser)
      throws Exception {
    // always parse for discoverable annotations as well as class hierarchy and
    // servletcontainerinitializer related annotations
    final Set<Handler> handlers = new HashSet<Handler>();
    handlers.addAll(_discoverableAnnotationHandlers);
    handlers.addAll(_containerInitializerAnnotationHandlers);
    if (_classInheritanceHandler != null) handlers.add(_classInheritanceHandler);

    _containerPathStats = new CounterStatistic();

    for (Resource r : context.getMetaData().getContainerResources()) {
      // queue it up for scanning if using multithreaded mode
      if (_parserTasks != null) {
        ParserTask task = new ParserTask(parser, handlers, r, _containerClassNameResolver);
        _parserTasks.add(task);
        _containerPathStats.increment();
        if (LOG.isDebugEnabled()) task.setStatistic(new TimeStatistic());
      }
    }
  }
  /**
   * 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();
  }
 /**
  * @see org.eclipse.jetty.server.session.AbstractSessionCache#doPutIfAbsent(java.lang.String,
  *     org.eclipse.jetty.server.session.Session)
  */
 @Override
 public Session doPutIfAbsent(String id, Session session) {
   Session s = _sessions.putIfAbsent(id, session);
   if (s == null && !(session instanceof PlaceHolderSession)) _stats.increment();
   return s;
 }
 /** @see org.eclipse.jetty.server.session.AbstractSessionCache#doDelete(java.lang.String) */
 @Override
 public Session doDelete(String id) {
   Session s = _sessions.remove(id);
   if (s != null && !(s instanceof PlaceHolderSession)) _stats.decrement();
   return s;
 }
 public void resetStats() {
   _stats.reset();
 }
 /** @return a running total of sessions in the cache */
 public long getSessionsTotal() {
   return _stats.getTotal();
 }
 /** @return the max number of sessions in the cache */
 public long getSessionsMax() {
   return _stats.getMax();
 }
 /** @return the number of sessions in the cache */
 public long getSessionsCurrent() {
   return _stats.getCurrent();
 }
 /**
  * @see org.eclipse.jetty.server.session.AbstractSessionCache#doReplace(java.lang.String,
  *     org.eclipse.jetty.server.session.Session, org.eclipse.jetty.server.session.Session)
  */
 @Override
 public boolean doReplace(String id, Session oldValue, Session newValue) {
   boolean result = _sessions.replace(id, oldValue, newValue);
   if (result && (oldValue instanceof PlaceHolderSession)) _stats.increment();
   return result;
 }