001/* 002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Stephane Lacoin 018 */ 019package org.nuxeo.runtime.javaagent; 020 021import java.io.File; 022import java.io.FilenameFilter; 023import java.io.IOException; 024import java.lang.management.ManagementFactory; 025import java.lang.reflect.Field; 026import java.lang.reflect.InvocationTargetException; 027import java.net.MalformedURLException; 028import java.net.URISyntaxException; 029import java.net.URL; 030import java.nio.file.Paths; 031 032import org.nuxeo.runtime.api.Framework; 033 034import com.sun.tools.attach.VirtualMachine; 035 036public class AgentLoader { 037 038 public static final AgentLoader INSTANCE = new AgentLoader(); 039 040 protected Object agent = load(); 041 042 protected ObjectSizer sizer = AgentHandler.newHandler(ObjectSizer.class, agent); 043 044 public ObjectSizer getSizer() { 045 return sizer; 046 } 047 048 protected <I> I getAgent(Class<I> type) { 049 return AgentHandler.newHandler(type, agent); 050 } 051 052 protected Object load() { 053 try { 054 loadAgentIfNeeded(); 055 } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException 056 | InvocationTargetException | MalformedURLException | URISyntaxException cause) { 057 throw new RuntimeException("Cannot load nuxeo agent jar in virtual machine", cause); 058 } 059 try { 060 return loadInstance(); 061 } catch (ClassNotFoundException | NoSuchFieldException | SecurityException | IllegalArgumentException 062 | IllegalAccessException cause) { 063 throw new RuntimeException("Cannot load nuxeo agent", cause); 064 } 065 } 066 067 protected Object loadInstance() throws ClassNotFoundException, NoSuchFieldException, SecurityException, 068 IllegalArgumentException, IllegalAccessException { 069 Class<?> clazz = AgentLoader.class.getClassLoader().loadClass("org.nuxeo.runtime.javaagent.NuxeoAgent"); 070 Field agentField = clazz.getDeclaredField("agent"); 071 agentField.setAccessible(true); 072 return agentField.get(null); 073 } 074 075 protected void loadAgentIfNeeded() throws NoSuchMethodException, SecurityException, IllegalAccessException, 076 IllegalArgumentException, InvocationTargetException, MalformedURLException, URISyntaxException { 077 try { 078 AgentLoader.class.getClassLoader().loadClass("org.nuxeo.runtime.javaagent.NuxeoAgent"); 079 } catch (ClassNotFoundException e) { 080 loadAgent(); 081 } 082 } 083 084 protected void loadAgent() throws NoSuchMethodException, SecurityException, IllegalAccessException, 085 IllegalArgumentException, InvocationTargetException, MalformedURLException, URISyntaxException { 086 String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName(); 087 int p = nameOfRunningVM.indexOf('@'); 088 String pid = nameOfRunningVM.substring(0, p); 089 090 File home; 091 try { 092 home = Framework.getRuntime().getHome().getCanonicalFile(); 093 } catch (IOException cause) { 094 throw new RuntimeException("cannot normalize runtime home path", cause); 095 } 096 File jarParentFolder = new File(home.getParentFile(), "bin"); 097 String jarLocation = locateAgentJar(jarParentFolder); 098 099 if (jarLocation == null) { 100 boolean isUnderTest = Boolean.parseBoolean(Framework.getProperty("org.nuxeo.runtime.testing", "false")); 101 if (!isUnderTest) { 102 throw new RuntimeException("Cannot locate nuxeo agent jar in bin folder"); 103 } 104 URL testResource = AgentLoader.class.getResource("/"); 105 File testClasses = Paths.get(testResource.toURI()).toFile(); 106 File mainProject = new File(testClasses.getParentFile().getParentFile().getParentFile(), "main"); 107 File target = new File(mainProject, "target"); 108 jarLocation = locateAgentJar(target); 109 if (jarLocation == null) { 110 throw new RuntimeException("Cannot locate nuxeo agent jar in target folder " + target 111 + ", did you forgot to run package target"); 112 } 113 } 114 try { 115 VirtualMachine vm = VirtualMachine.attach(pid); 116 vm.loadAgent(jarLocation, ""); 117 vm.detach(); 118 } catch (Exception e) { 119 throw new RuntimeException(e); 120 } 121 } 122 123 protected String locateAgentJar(File dir) { 124 File[] jars = dir.listFiles(new FilenameFilter() { 125 126 @Override 127 public boolean accept(File dir, String name) { 128 return name.startsWith("nuxeo-javaagent-main") && name.endsWith(".jar"); 129 } 130 }); 131 if (jars.length == 0) { 132 return null; 133 } 134 return jars[0].getPath(); 135 } 136}