/**
   * Returns a collection of composite sniffers that recognized some parts of the passed archive as
   * components their container handle.
   *
   * <p>If no sniffer recognize the passed archive, an empty collection is returned.
   *
   * @param context deployment context
   * @return possibly empty collection of sniffers that handle the passed archive.
   */
  public Collection<CompositeSniffer> getCompositeSniffers(DeploymentContext context) {
    // it is important to keep an ordered sequence here to keep sniffers
    // in their natural order.

    List<CompositeSniffer> appSniffers =
        getApplicableSniffers(context, getCompositeSniffers(), false);

    // call handles method of the sniffers
    for (CompositeSniffer sniffer : getCompositeSniffers()) {
      if (!appSniffers.contains(sniffer) && sniffer.handles(context)) {
        appSniffers.add(sniffer);
      }
    }
    return appSniffers;
  }
  public Collection<Sniffer> getSniffers(DeploymentContext context, List<URI> uris, Types types) {
    // it is important to keep an ordered sequence here to keep sniffers
    // in their natural order.
    List<Sniffer> regularSniffers = new ArrayList<Sniffer>();
    for (Sniffer sniffer : getSniffers()) {
      if (!(sniffer instanceof CompositeSniffer)) regularSniffers.add(sniffer);
    }

    // scan for registered annotations and retrieve applicable sniffers
    List<Sniffer> appSniffers = this.getApplicableSniffers(uris, types, regularSniffers, true);

    // call handles method of the sniffers
    for (Sniffer sniffer : regularSniffers) {
      if (!appSniffers.contains(sniffer) && sniffer.handles(context)) {
        appSniffers.add(sniffer);
      }
    }
    return appSniffers;
  }
  /**
   * Returns all the presently registered sniffers
   *
   * @return Collection (possibly empty but never null) of Sniffer
   */
  public Collection<Sniffer> getSniffers() {
    // this is a little bit of a hack, sniffers are now ordered by their names
    // which is useful since connector is before ejb which is before web so if
    // a standalone module happens to implement the three types of components,
    // they will be naturally ordered correctly. We might want to revisit this
    // later and formalize the ordering of sniffers. The hard thing as usual
    // is that sniffers are highly pluggable so you never know which sniffers
    // set you are working with depending on the distribution
    List<Sniffer> sniffers = new ArrayList<Sniffer>();
    sniffers.addAll(habitat.getAllByContract(Sniffer.class));
    Collections.sort(
        sniffers,
        new Comparator<Sniffer>() {
          public int compare(Sniffer o1, Sniffer o2) {
            return o1.getModuleType().compareTo(o2.getModuleType());
          }
        });

    return sniffers;
  }
  private <T extends Sniffer> List<T> getApplicableSniffers(
      List<URI> uris, Types types, Collection<T> sniffers, boolean checkPath) {
    if (sniffers == null || sniffers.isEmpty()) {
      return Collections.emptyList();
    }

    List<T> result = new ArrayList<T>();
    for (T sniffer : sniffers) {
      Class<? extends Annotation>[] annotations = sniffer.getAnnotationTypes();
      if (annotations == null) continue;
      for (Class<? extends Annotation> annotationType : annotations) {
        if (types != null) {
          Type type = types.getBy(annotationType.getName());
          if (type instanceof AnnotationType) {
            Collection<AnnotatedElement> elements = ((AnnotationType) type).allAnnotatedTypes();
            for (AnnotatedElement element : elements) {
              if (checkPath) {
                Type t =
                    (element instanceof Member
                        ? ((Member) element).getDeclaringType()
                        : (Type) element);
                if (t.wasDefinedIn(uris)) {
                  result.add(sniffer);
                  break;
                }
              } else {
                result.add(sniffer);
                break;
              }
            }
          }
        }
      }
    }
    return result;
  }