code: package org.gridkit.jvmtool.stacktrace.analytics;
  
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  import org.gridkit.jvmtool.stacktrace.StackFrame;
  
  /**
   * This filter factory is introducing hit cache on frame
   * matcher level. It also reusing matcher instance.
   * <br/>
   * These optimizations are not thread safe.
   *
   * @author Alexey Ragozin (alexey.ragozin@gmail.com)
   */
  public class CachingFilterFactory extends BasicFilterFactory {
  
      @Override
      public StackFrameMatcher patternFrameMatcher(Collection<String> patterns) {
          if (patterns.isEmpty()) {
              throw new IllegalArgumentException("Pattern list is empty");
          }
          return new CachingPatternFrameMatcher(patterns);
      }
  
      protected static class CachingPatternFrameMatcher implements StackFrameMatcher {
  
          private final Matcher regEx;
          private final Map<StackFrame, Boolean> hitCahce = new HashMap<StackFrame, Boolean>();
  
          CachingPatternFrameMatcher(Collection<String> patterns) {
              StringBuilder sb = new StringBuilder();
              sb.append('(');
              for(String pattern: patterns) {
                  sb.append(wildCardTranslate(pattern));
                  sb.append('|');
              }
              sb.setCharAt(sb.length() - 1, ')');
              regEx = Pattern.compile(sb.toString()).matcher("");
          }
  
          @Override
          public boolean evaluate(StackFrame frame) {
              Boolean hit =  hitCahce.get(frame);
              if (hit != null) {
                  return hit;
              }
              else {
                  regEx.reset(frame);
                  hit = regEx.lookingAt();
                  hitCahce.put(frame, hit);
              }
              return hit;
          }
      }
  }
  