All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mill.kotlinlib.KotlinWorkerManagerImpl.scala Maven / Gradle / Ivy

/*
 * Copyright 2020-Present Original lefou/mill-kotlin repository contributors.
 */

package mill.kotlinlib

import mill.PathRef
import mill.api.Ctx
import mill.kotlinlib.worker.api.KotlinWorker

import java.net.{URL, URLClassLoader}

class KotlinWorkerManagerImpl(ctx: Ctx) extends KotlinWorkerManager with AutoCloseable {

  private[this] var workerCache: Map[Seq[PathRef], (KotlinWorker, Int)] = Map.empty

  override def get(toolsClasspath: Seq[PathRef])(implicit ctx: Ctx): KotlinWorker = {
    val toolsCp = toolsClasspath.distinct
    val (worker, count) = workerCache.get(toolsCp) match {
      case Some((w, count)) =>
        ctx.log.debug(s"Reusing existing AspectjWorker for classpath: ${toolsCp}")
        w -> count
      case None =>
        ctx.log.debug(s"Creating Classloader with classpath: [${toolsCp}]")
        val classLoader = new URLClassLoader(
          toolsCp.map(_.path.toNIO.toUri().toURL()).toArray[URL],
          getClass().getClassLoader()
        )

        val className =
          classOf[KotlinWorker].getPackage().getName().split("\\.").dropRight(1).mkString(
            "."
          ) + ".impl." + classOf[KotlinWorker].getSimpleName() + "Impl"
        ctx.log.debug(s"Creating ${className} from classpath: ${toolsCp}")
        val impl = classLoader.loadClass(className)
        val worker = impl.getConstructor().newInstance().asInstanceOf[KotlinWorker]
        if (worker.getClass().getClassLoader() != classLoader) {
          ctx.log.error(
            """Worker not loaded from worker classloader.
              |You should not add the mill-kotlin-worker JAR to the mill build classpath""".stripMargin
          )
        }
        if (worker.getClass().getClassLoader() == classOf[KotlinWorker].getClassLoader()) {
          ctx.log.error("Worker classloader used to load interface and implementation")
        }
        worker -> 0
    }
    workerCache += toolsCp -> (worker -> (1 + count))
    ctx.log.debug(stats())
    worker
  }

  def stats(): String = {
    s"""Cache statistics of ${this.toString()}:
       |${
        workerCache.map { case (cp, (worker, count)) =>
          s"""- worker: ${worker.toString()}
             |  used: ${count}
             |""".stripMargin
        }.mkString
      }""".stripMargin
  }

  override def close(): Unit = {
    ctx.log.debug(stats())

    // We drop cached worker instances
    workerCache = Map.empty
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy