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                            // try to load Agent
037                            if(inst==null) {
038                                    try {
039                                            
040                                            String id=getPid();
041                                            String path=getResourcFromLib().getAbsolutePath();
042                                            
043                                            Class vmClass = ClassUtil.loadClass("com.sun.tools.attach.VirtualMachine");
044                                            Object vmObj=attach(vmClass,id);
045                                            loadAgent(vmClass,vmObj,path);
046                                            detach(vmClass,vmObj);
047                                    } 
048                                    catch (Throwable t) {
049                                            t.printStackTrace();
050                                            return null;
051                                    }
052                                    inst=getInstrumentation(agent);
053                            }
054                            
055                            if(inst!=null)SystemOut.printDate("java.lang.instrument.Instrumentation is used to reload class files");
056                                    
057                    }
058                    return inst;
059            }
060    
061            private static Instrumentation getInstrumentation(Class agent) {
062                    try {
063                            Method getInstrumentation = agent.getMethod("getInstrumentation", new Class[0]);
064                            return (Instrumentation) getInstrumentation.invoke(null, new Object[0]);
065                    } 
066                    catch (Throwable t) {
067                            t.printStackTrace();
068                            return null;
069                    }
070            }
071    
072            private static Object attach(Class vmClass, String id) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
073                    Method attach = vmClass.getMethod("attach", new Class[]{String.class});
074                    return attach.invoke(null, new Object[]{id});
075            }
076            
077            private static void loadAgent(Class vmClass, Object vmObj, String path) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
078                    Method loadAgent = vmClass.getMethod("loadAgent", new Class[]{String.class});
079                    loadAgent.invoke(vmObj, new Object[]{path});
080            }
081            
082            private static void detach(Class vmClass, Object vmObj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
083                    Method detach = vmClass.getMethod("detach", new Class[]{});
084                    detach.invoke(vmObj, new Object[]{});
085            }
086            
087            private static Resource getResourcFromLib() {
088                    Resource[] pathes = SystemUtil.getClassPathes();
089                    Resource res = null;
090                    String name=null;
091                    if(pathes!=null)for(int i=0;i<pathes.length;i++){
092                            name=pathes[i].getName();
093                            if(name.equalsIgnoreCase("railo-instrumentation.jar") || name.equalsIgnoreCase("railo-inst.jar")) {
094                                    res=pathes[i];
095                                    break;
096                            }
097                    }
098                    
099                    if(res==null) {
100                            Class agent = ClassUtil.loadClass("railo.runtime.instrumentation.Agent",null);
101                            if(agent!=null)res=getResourcFromLib(agent);
102                            else res=getResourcFromLib(ClassReader.class);
103                            
104                    }
105                    return res;
106            }
107    
108            private static Resource getResourcFromLib(Class clazz) {
109                    String path=clazz.getClassLoader().getResource(".").getFile();
110                    Resource dir = ResourcesImpl.getFileResourceProvider().getResource(path);
111                    Resource res = dir.getRealResource("railo-instrumentation.jar");
112                    if(!res.exists())res=dir.getRealResource("railo-inst.jar");
113                    if(!res.exists())res=null;
114                    return res;
115            }
116            private static String getPid() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
117                    RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
118                Field jvmField = mxbean.getClass().getDeclaredField("jvm");
119    
120                jvmField.setAccessible(true);
121                VMManagement management = (VMManagement) jvmField.get(mxbean);
122                Method method = management.getClass().getDeclaredMethod("getProcessId");
123                method.setAccessible(true);
124                Integer processId = (Integer) method.invoke(management);
125    
126                return processId.toString();
127            }
128    }