001package org.nuxeo.runtime.javaagent; 002 003import java.io.File; 004import java.io.FilenameFilter; 005import java.io.IOException; 006import java.lang.management.ManagementFactory; 007import java.lang.reflect.Field; 008import java.lang.reflect.InvocationTargetException; 009import java.net.MalformedURLException; 010import java.net.URISyntaxException; 011import java.net.URL; 012import java.nio.file.Paths; 013 014import org.nuxeo.runtime.api.Framework; 015 016import com.sun.tools.attach.VirtualMachine; 017 018public class AgentLoader { 019 020 public static final AgentLoader INSTANCE = new AgentLoader(); 021 022 protected Object agent = load(); 023 024 protected ObjectSizer sizer = AgentHandler.newHandler(ObjectSizer.class, agent); 025 026 public ObjectSizer getSizer() { 027 return sizer; 028 } 029 030 protected <I> I getAgent(Class<I> type) { 031 return AgentHandler.newHandler(type, agent); 032 } 033 034 protected Object load() { 035 try { 036 loadAgentIfNeeded(); 037 } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException 038 | InvocationTargetException | MalformedURLException | URISyntaxException cause) { 039 throw new RuntimeException("Cannot load nuxeo agent jar in virtual machine", cause); 040 } 041 try { 042 return loadInstance(); 043 } catch (ClassNotFoundException | NoSuchFieldException | SecurityException | IllegalArgumentException 044 | IllegalAccessException cause) { 045 throw new RuntimeException("Cannot load nuxeo agent", cause); 046 } 047 } 048 049 protected Object loadInstance() throws ClassNotFoundException, NoSuchFieldException, SecurityException, 050 IllegalArgumentException, IllegalAccessException { 051 Class<?> clazz = AgentLoader.class.getClassLoader().loadClass("org.nuxeo.runtime.javaagent.NuxeoAgent"); 052 Field agentField = clazz.getDeclaredField("agent"); 053 agentField.setAccessible(true); 054 return agentField.get(null); 055 } 056 057 protected void loadAgentIfNeeded() throws NoSuchMethodException, SecurityException, IllegalAccessException, 058 IllegalArgumentException, InvocationTargetException, MalformedURLException, URISyntaxException { 059 try { 060 AgentLoader.class.getClassLoader().loadClass("org.nuxeo.runtime.javaagent.NuxeoAgent"); 061 } catch (ClassNotFoundException e) { 062 loadAgent(); 063 } 064 } 065 066 protected void loadAgent() throws NoSuchMethodException, SecurityException, IllegalAccessException, 067 IllegalArgumentException, InvocationTargetException, MalformedURLException, URISyntaxException { 068 String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName(); 069 int p = nameOfRunningVM.indexOf('@'); 070 String pid = nameOfRunningVM.substring(0, p); 071 072 File home; 073 try { 074 home = Framework.getRuntime().getHome().getCanonicalFile(); 075 } catch (IOException cause) { 076 throw new RuntimeException("cannot normalize runtime home path", cause); 077 } 078 File jarParentFolder = new File(home.getParentFile(), "bin"); 079 String jarLocation = locateAgentJar(jarParentFolder); 080 081 if (jarLocation == null) { 082 boolean isUnderTest = Boolean.parseBoolean(Framework.getProperty("org.nuxeo.runtime.testing", "false")); 083 if (!isUnderTest) { 084 throw new RuntimeException("Cannot locate nuxeo agent jar in bin folder"); 085 } 086 URL testResource = AgentLoader.class.getResource("/"); 087 File testClasses = Paths.get(testResource.toURI()).toFile(); 088 File mainProject = new File(testClasses.getParentFile().getParentFile().getParentFile(), "main"); 089 File target = new File(mainProject, "target"); 090 jarLocation = locateAgentJar(target); 091 if (jarLocation == null) { 092 throw new RuntimeException("Cannot locate nuxeo agent jar in target folder " + target 093 + ", did you forgot to run package target"); 094 } 095 } 096 try { 097 VirtualMachine vm = VirtualMachine.attach(pid); 098 vm.loadAgent(jarLocation, ""); 099 vm.detach(); 100 } catch (Exception e) { 101 throw new RuntimeException(e); 102 } 103 } 104 105 protected String locateAgentJar(File dir) { 106 File[] jars = dir.listFiles(new FilenameFilter() { 107 108 @Override 109 public boolean accept(File dir, String name) { 110 return name.startsWith("nuxeo-javaagent-main") && name.endsWith(".jar"); 111 } 112 }); 113 if (jars.length == 0) { 114 return null; 115 } 116 return jars[0].getPath(); 117 } 118}