aboutsummaryrefslogtreecommitdiff
path: root/kamon-autoweave/src/main/scala
diff options
context:
space:
mode:
authorDiego <diegolparra@gmail.com>2016-02-07 23:54:43 -0300
committerDiego <diegolparra@gmail.com>2016-02-07 23:54:43 -0300
commit783464d24f8e5a1877fc893eb991d0842c8128d7 (patch)
treec8133f25f2cb76e31c350517066c5bf339c2e740 /kamon-autoweave/src/main/scala
parentc90bb9467628f841040003d55f20969abd79958f (diff)
downloadKamon-783464d24f8e5a1877fc893eb991d0842c8128d7.tar.gz
Kamon-783464d24f8e5a1877fc893eb991d0842c8128d7.tar.bz2
Kamon-783464d24f8e5a1877fc893eb991d0842c8128d7.zip
= kamon-autoweave: refactor in order to load the com.sun.tools.attach.VirtualMachine from tools.jar
Diffstat (limited to 'kamon-autoweave/src/main/scala')
-rw-r--r--kamon-autoweave/src/main/scala/kamon/autoweave/loader/AgentLoader.scala136
-rw-r--r--kamon-autoweave/src/main/scala/kamon/autoweave/loader/AttachmentProviders.scala69
2 files changed, 91 insertions, 114 deletions
diff --git a/kamon-autoweave/src/main/scala/kamon/autoweave/loader/AgentLoader.scala b/kamon-autoweave/src/main/scala/kamon/autoweave/loader/AgentLoader.scala
index eb0c46df..2f26a39d 100644
--- a/kamon-autoweave/src/main/scala/kamon/autoweave/loader/AgentLoader.scala
+++ b/kamon-autoweave/src/main/scala/kamon/autoweave/loader/AgentLoader.scala
@@ -15,20 +15,12 @@
package kamon.autoweave.loader
-import java.io.{File, FileOutputStream, InputStream}
+import java.io.{ File, FileOutputStream, InputStream }
import java.lang.management.ManagementFactory
-import java.lang.reflect.Constructor
-import java.util
import java.util.jar.Attributes.Name
-import java.util.jar.{JarEntry, JarOutputStream, Manifest}
-
-import com.sun.tools.attach.spi.AttachProvider
-import com.sun.tools.attach.{VirtualMachine, VirtualMachineDescriptor}
-import kamon.autoweave.loader.resolver.OsResolver._
-import sun.tools.attach._
+import java.util.jar.{ JarEntry, JarOutputStream, Manifest }
import scala.util.control.NoStackTrace
-import scala.util.{Failure, Success, Try}
object AgentLoader {
@@ -47,14 +39,10 @@ object AgentLoader {
/**
* Loads an agent into a JVM.
*
- * @param agent The main agent class.
+ * @param agent The main agent class.
* @param resources Array of classes to be included with agent.
*/
- def attachAgentToJVM(agent: Class[_], resources: Seq[Class[_]] = Seq.empty): Unit = {
- val vm = attachToRunningJVM()
- vm.loadAgent(generateAgentJar(agent, resources).getAbsolutePath)
- vm.detach()
- }
+ def attachAgentToJVM(agent: Class[_], resources: Seq[Class[_]] = Seq.empty): Unit = attachToRunningJVM(agent, resources)
/**
* Java variant
@@ -81,6 +69,7 @@ object AgentLoader {
mainAttributes.put(new Name("Agent-Class"), agent.getName)
mainAttributes.put(new Name("Can-Retransform-Classes"), "true")
mainAttributes.put(new Name("Can-Redefine-Classes"), "true")
+ mainAttributes.put(new Name("Can-Set-Native-Method-Prefix"), "true")
val jos = new JarOutputStream(new FileOutputStream(jarFile), manifest)
@@ -101,6 +90,23 @@ object AgentLoader {
}
/**
+ * Attach to the running JVM.
+ *
+ * @return
+ * Returns the attached VirtualMachine
+ */
+ private def attachToRunningJVM(agent: Class[_], resources: Seq[Class[_]]): Unit = {
+ AttachmentProviders.resolve() match {
+ case Some(virtualMachine) ⇒
+ val virtualMachineInstance = virtualMachine.getDeclaredMethod("attach", classOf[String]).invoke(null, getPidFromRuntimeMBean)
+ virtualMachine.getDeclaredMethod("loadAgent", classOf[String], classOf[String])
+ .invoke(virtualMachineInstance, generateAgentJar(agent, resources).getAbsolutePath, "")
+ virtualMachine.getDeclaredMethod("detach").invoke(virtualMachineInstance)
+ case None ⇒ throw new RuntimeException(s"Error trying to use Attach API") with NoStackTrace
+ }
+ }
+
+ /**
* Gets bytes from InputStream.
*
* @param stream
@@ -113,103 +119,5 @@ object AgentLoader {
}
private def unqualify(clazz: Class[_]): String = clazz.getName.replace('.', '/') + ".class"
-
- /**
- * Gets the current HotSpotVirtualMachine implementation otherwise a failure.
- *
- * @return
- * Returns the HotSpotVirtualMachine implementation of the running JVM.
- */
- private def findVirtualMachineImplementation(): Try[Class[_ <: HotSpotVirtualMachine]] = currentOs match {
- case Windows(_, _, _) ⇒ Success(classOf[WindowsVirtualMachine])
- case Mac(_, _, _) ⇒ Success(classOf[BsdVirtualMachine])
- case Solaris(_, _, _) ⇒ Success(classOf[SolarisVirtualMachine])
- case Linux(_, _, _) ⇒ Success(classOf[LinuxVirtualMachine])
- case UnknownOs(name, arch, version) ⇒
- Failure(new RuntimeException(s"Cannot use Attach API on unknown OS: $name Arch: $arch Version: $version") with NoStackTrace)
- }
-
- /**
- * Attach to the running JVM.
- *
- * @return
- * Returns the attached VirtualMachine
- */
- private def attachToRunningJVM(): VirtualMachine = {
- val AttachProvider = new AttachProvider() {
- override def name(): String = null
- override def `type`(): String = null
- override def attachVirtualMachine(id: String): VirtualMachine = null
- override def listVirtualMachines(): util.List[VirtualMachineDescriptor] = null
- }
-
- findVirtualMachineImplementation() match {
- case Success(vmClass) ⇒
- val pid = getPidFromRuntimeMBean
- // This is only done with Reflection to avoid the JVM pre-loading all the XyzVirtualMachine classes.
- val newVM = vmConstructor(vmClass).newInstance(AttachProvider, pid)
- newVM.asInstanceOf[VirtualMachine]
- case Failure(reason) ⇒ throw reason
- }
- }
-
- /**
- * `BsdVirtualMachine`, used when your platform is Mac - vmClass parameter, has the constructor
- * without modifier (by default is `package-private`), so `AgentLoader` can not instance it, for that reason
- * we need to set accessible that constructor via reflection.
- *
- * @param vmClass
- * @return
- */
- private def vmConstructor(vmClass: Class[_ <: HotSpotVirtualMachine]): Constructor[_] = {
- currentOs match {
- case Mac(_, _, _) ⇒
- val vmC = vmClass.getDeclaredConstructor(classOf[AttachProvider], classOf[String])
- vmC.setAccessible(true)
- vmC
-
- case _ ⇒ vmClass.getConstructor(classOf[AttachProvider], classOf[String])
- }
- }
}
-package object resolver {
-
- /* OS RESOLVERS */
- private[loader] object OsResolver {
- private[resolver] trait OsIdentifiable {
- def name: String
- def arch: String
- def version: String
- }
-
- private[loader] case class Windows(name: String, arch: String, version: String) extends OsIdentifiable
- private[loader] case class Mac(name: String, arch: String, version: String) extends OsIdentifiable
- private[loader] case class Solaris(name: String, arch: String, version: String) extends OsIdentifiable
- private[loader] case class Linux(name: String, arch: String, version: String) extends OsIdentifiable
- private[loader] case class UnknownOs(name: String, arch: String, version: String) extends OsIdentifiable
-
- private[resolver] val osName = System.getProperty("os.name")
- private[resolver] val osArch = System.getProperty("os.arch")
- private[resolver] val osVersion = System.getProperty("os.version")
-
- private[this] val defaultWindowsName = "Windows"
- private[this] val defaultMacName = "Mac OS X"
- private[this] val defaultSolarisName = "Solaris"
- private[this] val defaultLinuxName = "Linux"
- private[this] val defaultLinuxUpperCaseName = defaultLinuxName.toUpperCase
-
- /**
- * Resolver OS based on java properties.
- */
- val currentOs: OsIdentifiable = osName match {
- case os if os.startsWith(defaultWindowsName) ⇒ Windows(os, osArch, osVersion)
- case os if os.startsWith(defaultMacName) ⇒ Mac(os, osArch, osVersion)
- case os if os.startsWith(defaultSolarisName) ⇒ Solaris(os, osArch, osVersion)
- case os if os.startsWith(defaultLinuxName) || os.startsWith(defaultLinuxUpperCaseName) ⇒ Linux(os, osArch, osVersion)
- case other ⇒ UnknownOs(other, osArch, osVersion)
- }
- }
- /* OS RESOLVERS */
-
-}
diff --git a/kamon-autoweave/src/main/scala/kamon/autoweave/loader/AttachmentProviders.scala b/kamon-autoweave/src/main/scala/kamon/autoweave/loader/AttachmentProviders.scala
new file mode 100644
index 00000000..40f58502
--- /dev/null
+++ b/kamon-autoweave/src/main/scala/kamon/autoweave/loader/AttachmentProviders.scala
@@ -0,0 +1,69 @@
+/* =========================================================================================
+ * Copyright © 2013-2016 the kamon project <http://kamon.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 kamon.autoweave.loader
+
+import java.io.File
+import java.net.{ URL, URLClassLoader }
+import java.security.{ PrivilegedAction, AccessController }
+
+object AttachmentProviders extends {
+
+ val VirtualMachineTyeName = "com.sun.tools.attach.VirtualMachine"
+
+ sealed trait AttachmentProvider {
+ def toolsJarPath: String
+
+ /**
+ * Gets the current HotSpotVirtualMachine implementation otherwise a None.
+ *
+ * @return
+ * Returns the HotSpotVirtualMachine implementation of the running JVM.
+ */
+ def resolve(): Option[Class[_]] = {
+ val toolsJar = new File(System.getProperty("java.home").replace('\\', '/') + "/../" + toolsJarPath)
+ if (toolsJar.isFile && toolsJar.canRead)
+ Some(AccessController.doPrivileged(new ClassLoaderCreationAction(toolsJar)).loadClass(VirtualMachineTyeName))
+ else None
+ }
+ }
+
+ case object JVM extends AttachmentProvider { val toolsJarPath = "../lib/tools.jar" }
+ case object JDK extends AttachmentProvider { val toolsJarPath = "lib/tools.jar" }
+ case object MAC extends AttachmentProvider { val toolsJarPath = "../Classes/classes.jar" }
+
+ private val providers = Seq(JVM, JDK, MAC)
+
+ private final class ClassLoaderCreationAction(toolsJar: File) extends PrivilegedAction[ClassLoader] {
+ override def run(): ClassLoader = new URLClassLoader(Array[URL](toolsJar.toURI.toURL), null)
+ }
+
+ def resolve(): Option[Class[_]] = {
+ import scala.util.control.Breaks._
+
+ var vmClazz: Option[Class[_]] = None
+
+ breakable {
+ for (provider ← providers) {
+ val vmClass = provider.resolve()
+ if (vmClass.isDefined) {
+ vmClazz = vmClass
+ break
+ }
+ }
+ }
+ vmClazz
+ }
+}