/**
   * This method performs threshold checks and invokes filters before delegating actual logging to
   * the subclasses specific {@link AppenderSkeleton#append} method.
   */
  public synchronized void doAppend(LoggingEvent event) {
    if (closed) {
      LogLog.error("Attempted to append to closed appender named [" + name + "].");
      return;
    }

    if (!isAsSevereAsThreshold(event.getLevel())) {
      return;
    }

    Filter f = this.headFilter;

    FILTER_LOOP:
    while (f != null) {
      switch (f.decide(event)) {
        case Filter.DENY:
          return;
        case Filter.ACCEPT:
          break FILTER_LOOP;
        case Filter.NEUTRAL:
          f = f.getNext();
      }
    }

    this.append(event);
  }
 /**
  * Add a filter to end of the filter list.
  *
  * @since 0.9.0
  */
 public void addFilter(Filter newFilter) {
   if (headFilter == null) {
     headFilter = tailFilter = newFilter;
   } else {
     tailFilter.setNext(newFilter);
     tailFilter = newFilter;
   }
 }
  void parseAppenderFilters(Properties props, String appenderName, Appender appender) {
    // extract filters and filter options from props into a hashtable mapping
    // the property name defining the filter class to a list of pre-parsed
    // name-value pairs associated to that filter
    final String filterPrefix = APPENDER_PREFIX + appenderName + ".filter.";
    int fIdx = filterPrefix.length();
    Hashtable filters = new Hashtable();
    Enumeration e = props.keys();
    String name = "";
    while (e.hasMoreElements()) {
      String key = (String) e.nextElement();
      if (key.startsWith(filterPrefix)) {
        int dotIdx = key.indexOf('.', fIdx);
        String filterKey = key;
        if (dotIdx != -1) {
          filterKey = key.substring(0, dotIdx);
          name = key.substring(dotIdx + 1);
        }
        Vector filterOpts = (Vector) filters.get(filterKey);
        if (filterOpts == null) {
          filterOpts = new Vector();
          filters.put(filterKey, filterOpts);
        }
        if (dotIdx != -1) {
          String value = OptionConverter.findAndSubst(key, props);
          filterOpts.add(new NameValue(name, value));
        }
      }
    }

    // sort filters by IDs, insantiate filters, set filter options,
    // add filters to the appender
    Enumeration g = new SortedKeyEnumeration(filters);
    while (g.hasMoreElements()) {
      String key = (String) g.nextElement();
      String clazz = props.getProperty(key);
      if (clazz != null) {
        LogLog.debug(
            "Filter key: ["
                + key
                + "] class: ["
                + props.getProperty(key)
                + "] props: "
                + filters.get(key));
        Filter filter = (Filter) OptionConverter.instantiateByClassName(clazz, Filter.class, null);
        if (filter != null) {
          PropertySetter propSetter = new PropertySetter(filter);
          Vector v = (Vector) filters.get(key);
          Enumeration filterProps = v.elements();
          while (filterProps.hasMoreElements()) {
            NameValue kv = (NameValue) filterProps.nextElement();
            propSetter.setProperty(kv.key, kv.value);
          }
          propSetter.activate();
          LogLog.debug(
              "Adding filter of type ["
                  + filter.getClass()
                  + "] to appender named ["
                  + appender.getName()
                  + "].");
          appender.addFilter(filter);
        }
      } else {
        LogLog.warn("Missing class definition for filter: [" + key + "]");
      }
    }
  }