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

io.gatling.app.classloader.FileSystemBackedClassLoader.scala Maven / Gradle / Ivy

/**
 * Copyright 2011-2016 GatlingCorp (http://gatling.io)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gatling.app.classloader

import java.net.{ URL, URLConnection, URLStreamHandler }
import java.nio.file.Path
import java.security.cert.Certificate
import java.security.{ CodeSource, ProtectionDomain }

import scala.collection.mutable

import io.gatling.commons.util.Io._
import io.gatling.commons.util.PathHelper._

private[classloader] class FileSystemBackedClassLoader(root: Path, parent: ClassLoader)
    extends ClassLoader(parent) {

  def classNameToPath(name: String): Path =
    if (name endsWith ".class") name
    else name.replace('.', '/') + ".class"

  def dirNameToPath(name: String): Path =
    name.replace('.', '/')

  def findPath(path: Path): Option[Path] = {
    val fullPath = root / path
    if (fullPath.exists) Some(fullPath) else None
  }

  override def findResource(name: String) = findPath(name).map { path =>
    new URL(null, "repldir:" + path, new URLStreamHandler {
      override def openConnection(url: URL): URLConnection = new URLConnection(url) {
        override def connect(): Unit = ()
        override def getInputStream = path.inputStream
      }
    })
  }.orNull

  override def getResourceAsStream(name: String) = findPath(name) match {
    case Some(path) => path.inputStream
    case None       => super.getResourceAsStream(name)
  }

  def classAsStream(className: String) =
    Option(getResourceAsStream(className.replaceAll("""\.""", "/") + ".class"))

  def classBytes(name: String): Array[Byte] = findPath(classNameToPath(name)) match {
    case Some(path) => path.inputStream.toByteArray()
    case None => classAsStream(name) match {
      case Some(stream) => stream.toByteArray()
      case None         => Array.empty
    }
  }

  override def findClass(name: String): Class[_] = {
    val bytes = classBytes(name)
    if (bytes.length == 0) throw new ClassNotFoundException(name)
    else defineClass(name, bytes, 0, bytes.length, protectionDomain)
  }

  private val packages = mutable.Map[String, Package]()

  lazy val protectionDomain = {
    val cl = Thread.currentThread.getContextClassLoader
    val resource = cl.getResource("scala/runtime/package.class")
    if (resource == null || resource.getProtocol != "jar") null else {
      val s = resource.getPath
      val n = s.lastIndexOf('!')
      if (n < 0) null else {
        val path = s.substring(0, n)
        new ProtectionDomain(new CodeSource(new URL(path), null.asInstanceOf[Array[Certificate]]), null, this, null)
      }
    }
  }

  override def definePackage(name: String, specTitle: String,
                             specVersion: String, specVendor: String,
                             implTitle: String, implVersion: String,
                             implVendor: String, sealBase: URL) = {
    throw new UnsupportedOperationException()
  }

  override def getPackage(name: String) = findPath(dirNameToPath(name)) match {
    case Some(path) => packages.getOrElseUpdate(name, {
      val ctor = classOf[Package].getDeclaredConstructor(
        classOf[String], classOf[String], classOf[String],
        classOf[String], classOf[String], classOf[String],
        classOf[String], classOf[URL], classOf[ClassLoader]
      )
      ctor.setAccessible(true)
      ctor.newInstance(name, null, null, null, null, null, null, null, this)
    })
    case None => super.getPackage(name)
  }

  override def getPackages =
    root.deepDirs.map(path => getPackage(path.toString)).toArray

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy