package kanela.agent.util.classloader;

import lombok.val;
import net.bytebuddy.matcher.ElementMatcher;

import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class ScalaCompilerClassLoaderMatcher extends ElementMatcher.Junction.AbstractBase<ClassLoader> {

  @Override
  public boolean matches(ClassLoader classLoader) {
    return isScalaCompilerClassLoader(classLoader);
  }

  private static Set<ClassLoader> knownScalaClassLoaders = Collections.newSetFromMap(new ConcurrentHashMap<>());

  /**
   * Tries to determine whether the ClassLoader causing errors belongs to the Scala Compiler on SBT. Since there is
   * no special naming or treatment of this particular ClassLoader it is impossible to filter it out from the
   * instrumentation process, but given that the jars found on it are quite particular (the compiler and jline) we can
   * assume that any instrumentation errors happening on that ClassLoader should be dismissed.
   *
   * We are doing this check here instead of using a ClassLoaderNameMatcher because this is a relatively expensive
   * check which might only be necessary in a few cases, so we rather filter the error than putting the burden of this
   * check on every single class load.
   */
  public static boolean isScalaCompilerClassLoader(ClassLoader classLoader) {
    if(classLoader instanceof URLClassLoader) {
      if(knownScalaClassLoaders.contains(classLoader))
        return true;
      else {
        val urlClassLoader = (URLClassLoader) classLoader;
        boolean foundScalaCompiler = false;
        boolean foundJLine = false;

        for (URL url : urlClassLoader.getURLs()) {
          if (url.getFile().contains("scala-compiler"))
            foundScalaCompiler = true;
          if (url.getFile().contains("jline"))
            foundJLine = true;
        }

        val isScalaCompiler = foundScalaCompiler && foundJLine;
        if (isScalaCompiler)
          knownScalaClassLoaders.add(classLoader);

        return isScalaCompiler;
      }
    } else return false;
  }

}

@@ -172,41 +172,11 @@
 til.
-Collections;%0Aimport java.util.Set
+Map
 ;%0Aim
@@ -465,19 +465,19 @@
  static 
-Set
+Map
 %3CClassLo
@@ -484,20 +484,24 @@
 ader
+, Boolean
 %3E known
-Scala
 Clas
@@ -515,34 +515,8 @@
 s = 
-Collections.newSetFromMap(
 new 
@@ -536,17 +536,16 @@
 hMap%3C%3E()
-)
 ;%0A%0A  /**
@@ -577,19 +577,17 @@
 whether 
-the
+a
  ClassLo
@@ -595,33 +595,10 @@
 der 
-causing errors belongs to
+is
  the
@@ -613,16 +613,28 @@
 ompiler 
+ClassLoader 
 on SBT. 
@@ -647,21 +647,16 @@
 there is
-%0A   *
  no spec
@@ -665,16 +665,21 @@
 l naming
+%0A   *
  or trea
@@ -735,16 +735,44 @@
 ible to 
+have a 100%25 reliable way to 
 filter i
@@ -902,108 +902,258 @@
 ne) 
-we c
 an
+d
 %0A   * 
-assume that any instrumentation errors happening on that ClassLoader should be dismissed
+there are usually just a handful of jars in that ClassLoader, we can have a level of certainty that if a%0A   * ClassLoader has less than 6 jars and some of those are the compiler-related libraries then it must be the compiler%0A   * ClassLoader
 .%0A  
@@ -1570,76 +1570,153 @@
     
-if(knownScalaClassLoaders.contains(classLoader))%0A        return true
+Boolean isScalaCompilerLoader = knownClassLoaders.get(classLoader);%0A%0A      if(isScalaCompilerLoader != null)%0A        return isScalaCompilerLoader
 ;%0A  
@@ -1865,17 +1865,126 @@
  false;%0A
-%0A
+        boolean hasLessThanSixJars = urlClassLoader.getURLs().length %3C 6;%0A%0A        if(hasLessThanSixJars) %7B%0A  
         
@@ -2028,32 +2028,34 @@
 ()) %7B%0A          
+ 
+ 
 if (url.getFile(
@@ -2092,24 +2092,26 @@
             
+  
 foundScalaCo
@@ -2117,32 +2117,34 @@
 ompiler = true;%0A
+%0A 
           if (ur
@@ -2129,32 +2129,33 @@
 ue;%0A%0A           
+ 
 if (url.getFile(
@@ -2183,24 +2183,26 @@
             
+  
 foundJLine =
@@ -2208,16 +2208,28 @@
 = true;%0A
+          %7D%0A
         
@@ -2260,16 +2260,38 @@
 mpiler =
+ hasLessThanSixJars &&
  foundSc
@@ -2329,49 +2329,13 @@
     
-if (isScalaCompiler)%0A          knownScala
+known
 Clas
@@ -2347,11 +2347,11 @@
 ers.
-add
+put
 (cla
@@ -2354,28 +2354,44 @@
 (classLoader
+, isScalaCompiler
 );%0A
-%0A
         retu

improve the SBT Scala Compiler detection code