package railo.runtime.instrumentation; import java.lang.instrument.Instrumentation; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.objectweb.asm.ClassReader; import railo.commons.io.SystemUtil; import railo.commons.io.res.Resource; import railo.commons.io.res.ResourcesImpl; import railo.commons.lang.ClassUtil; import railo.commons.lang.SystemOut; import sun.management.VMManagement; public class InstrumentationFactory { private static Instrumentation inst; private static boolean doInit=true; public static synchronized Instrumentation getInstance() { if(doInit) { doInit=false; Class agent = ClassUtil.loadClass("railo.runtime.instrumentation.Agent",null); if(agent==null) { SystemOut.printDate("missing class railo.runtime.instrumentation.Agent"); return null; } // if Agent was loaded at startup there is already a Instrumentation inst=getInstrumentation(agent); // try to load Agent if(inst==null) { SystemOut.printDate("class railo.runtime.instrumentation.Agent.getInstrumentation() is not returning an Instrumentation"); try { String id=getPid(); String path=getResourcFromLib().getAbsolutePath(); Class vmClass = ClassUtil.loadClass("com.sun.tools.attach.VirtualMachine"); Object vmObj=attach(vmClass,id); loadAgent(vmClass,vmObj,path); detach(vmClass,vmObj); } catch (Throwable t) { //t.printStackTrace(); return null; } inst=getInstrumentation(agent); } if(inst!=null)SystemOut.printDate("java.lang.instrument.Instrumentation is used to reload class files"); } return inst; } private static Instrumentation getInstrumentation(Class agent) { try { Method getInstrumentation = agent.getMethod("getInstrumentation", new Class[0]); return (Instrumentation) getInstrumentation.invoke(null, new Object[0]); } catch (Throwable t) { t.printStackTrace(); return null; } } private static Object attach(Class vmClass, String id) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { Method attach = vmClass.getMethod("attach", new Class[]{String.class}); return attach.invoke(null, new Object[]{id}); } private static void loadAgent(Class vmClass, Object vmObj, String path) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { Method loadAgent = vmClass.getMethod("loadAgent", new Class[]{String.class}); loadAgent.invoke(vmObj, new Object[]{path}); } private static void detach(Class vmClass, Object vmObj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { Method detach = vmClass.getMethod("detach", new Class[]{}); detach.invoke(vmObj, new Object[]{}); } private static Resource getResourcFromLib() { Resource[] pathes = SystemUtil.getClassPathes(); Resource res = null; String name=null; if(pathes!=null)for(int i=0;i<pathes.length;i++){ name=pathes[i].getName(); if(name.equalsIgnoreCase("railo-instrumentation.jar") || name.equalsIgnoreCase("railo-inst.jar")) { res=pathes[i]; break; } } if(res==null) { Class agent = ClassUtil.loadClass("railo.runtime.instrumentation.Agent",null); if(agent!=null)res=getResourcFromLib(agent); else res=getResourcFromLib(ClassReader.class); } return res; } private static Resource getResourcFromLib(Class clazz) { String path=clazz.getClassLoader().getResource(".").getFile(); Resource dir = ResourcesImpl.getFileResourceProvider().getResource(path); Resource res = dir.getRealResource("railo-instrumentation.jar"); if(!res.exists())res=dir.getRealResource("railo-inst.jar"); if(!res.exists())res=null; return res; } private static String getPid() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean(); Field jvmField = mxbean.getClass().getDeclaredField("jvm"); jvmField.setAccessible(true); VMManagement management = (VMManagement) jvmField.get(mxbean); Method method = management.getClass().getDeclaredMethod("getProcessId"); method.setAccessible(true); Integer processId = (Integer) method.invoke(management); return processId.toString(); } }