001    package railo.runtime.instrumentation;
002    
003    import java.lang.instrument.Instrumentation;
004    import java.lang.management.ManagementFactory;
005    import java.lang.management.RuntimeMXBean;
006    import java.lang.reflect.Field;
007    import java.lang.reflect.InvocationTargetException;
008    import java.lang.reflect.Method;
009    
010    import org.objectweb.asm.ClassReader;
011    
012    import railo.commons.io.SystemUtil;
013    import railo.commons.io.res.Resource;
014    import railo.commons.io.res.ResourcesImpl;
015    import railo.commons.lang.ClassUtil;
016    import railo.commons.lang.SystemOut;
017    import sun.management.VMManagement;
018    
019    public class InstrumentationFactory {
020            
021            private static Instrumentation inst;
022            private static boolean doInit=true;
023            
024            public static synchronized Instrumentation getInstance() {
025                    if(doInit) {
026                            doInit=false;
027                            
028                            Class agent = ClassUtil.loadClass("railo.runtime.instrumentation.Agent",null);
029                            if(agent==null) {
030                                    SystemOut.printDate("missing class railo.runtime.instrumentation.Agent");
031                                    return null;
032                            }
033                            
034                            // if Agent was loaded at startup there is already a Instrumentation
035                            inst=getInstrumentation(agent);
036                            
037                            // try to load Agent
038                            if(inst==null) {
039                                    SystemOut.printDate("class railo.runtime.instrumentation.Agent.getInstrumentation() is not returning a Instrumentation");
040                                    try {
041                                            String id=getPid();
042                                            String path=getResourcFromLib().getAbsolutePath();
043                                            
044                                            Class vmClass = ClassUtil.loadClass("com.sun.tools.attach.VirtualMachine");
045                                            Object vmObj=attach(vmClass,id);
046                                            loadAgent(vmClass,vmObj,path);
047                                            detach(vmClass,vmObj);
048                                    } 
049                                    catch (Throwable t) {
050                                            //t.printStackTrace();
051                                            return null;
052                                    }
053                                    inst=getInstrumentation(agent);
054                            }
055                            
056                            if(inst!=null)SystemOut.printDate("java.lang.instrument.Instrumentation is used to reload class files");
057                                    
058                    }
059                    return inst;
060            }
061    
062            private static Instrumentation getInstrumentation(Class agent) {
063                    try {
064                            Method getInstrumentation = agent.getMethod("getInstrumentation", new Class[0]);
065                            return (Instrumentation) getInstrumentation.invoke(null, new Object[0]);
066                    } 
067                    catch (Throwable t) {
068                            t.printStackTrace();
069                            return null;
070                    }
071            }
072    
073            private static Object attach(Class vmClass, String id) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
074                    Method attach = vmClass.getMethod("attach", new Class[]{String.class});
075                    return attach.invoke(null, new Object[]{id});
076            }
077            
078            private static void loadAgent(Class vmClass, Object vmObj, String path) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
079                    Method loadAgent = vmClass.getMethod("loadAgent", new Class[]{String.class});
080                    loadAgent.invoke(vmObj, new Object[]{path});
081            }
082            
083            private static void detach(Class vmClass, Object vmObj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
084                    Method detach = vmClass.getMethod("detach", new Class[]{});
085                    detach.invoke(vmObj, new Object[]{});
086            }
087            
088            private static Resource getResourcFromLib() {
089                    Resource[] pathes = SystemUtil.getClassPathes();
090                    Resource res = null;
091                    String name=null;
092                    if(pathes!=null)for(int i=0;i<pathes.length;i++){
093                            name=pathes[i].getName();
094                            if(name.equalsIgnoreCase("railo-instrumentation.jar") || name.equalsIgnoreCase("railo-inst.jar")) {
095                                    res=pathes[i];
096                                    break;
097                            }
098                    }
099                    
100                    if(res==null) {
101                            Class agent = ClassUtil.loadClass("railo.runtime.instrumentation.Agent",null);
102                            if(agent!=null)res=getResourcFromLib(agent);
103                            else res=getResourcFromLib(ClassReader.class);
104                            
105                    }
106                    return res;
107            }
108    
109            private static Resource getResourcFromLib(Class clazz) {
110                    String path=clazz.getClassLoader().getResource(".").getFile();
111                    Resource dir = ResourcesImpl.getFileResourceProvider().getResource(path);
112                    Resource res = dir.getRealResource("railo-instrumentation.jar");
113                    if(!res.exists())res=dir.getRealResource("railo-inst.jar");
114                    if(!res.exists())res=null;
115                    return res;
116            }
117            private static String getPid() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
118                    RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
119                Field jvmField = mxbean.getClass().getDeclaredField("jvm");
120    
121                jvmField.setAccessible(true);
122                VMManagement management = (VMManagement) jvmField.get(mxbean);
123                Method method = management.getClass().getDeclaredMethod("getProcessId");
124                method.setAccessible(true);
125                Integer processId = (Integer) method.invoke(management);
126    
127                return processId.toString();
128            }
129    }