Package org.jboss.byteman.agent

Source Code of org.jboss.byteman.agent.Main

/*
* JBoss, Home of Professional Open Source
* Copyright 2008-9, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
* @authors Andrew Dinn
*/
package org.jboss.byteman.agent;


import java.lang.instrument.Instrumentation;
import java.lang.instrument.ClassFileTransformer;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.jar.JarFile;
import java.util.ArrayList;
import java.util.List;
import java.io.File;
import java.io.IOException;
import java.io.FileInputStream;
import java.net.Socket;

/**
* agent class supplied at JVM startup to install byteman package bytecode transformer
*/
public class Main {
    public static boolean firstTime = true;
    public final static String BYTEMAN_PREFIX = "org.jboss.byteman.";

    public static void premain(String args, Instrumentation inst)
            throws Exception
    {
        // guard against the agent being loaded twice
        synchronized (Main.class) {
            if (firstTime) {
                firstTime = false;
            } else {
                throw new Exception("Main : attempting to load Byteman agent more than once");
            }
        }
        boolean allowRedefine = false;

        if (args != null) {
            // args are supplied eparated by ',' characters
            String[] argsArray = args.split(",");
            // we accept extra jar files to be added to the boot/sys classpaths
            // script files to be scanned for rules
            // listener flag which implies use of a retransformer
            for (String arg : argsArray) {
                if (arg.startsWith(BOOT_PREFIX)) {
                    bootJarPaths.add(arg.substring(BOOT_PREFIX.length(), arg.length()));
                } else if (arg.startsWith(SYS_PREFIX)) {
                    sysJarPaths.add(arg.substring(SYS_PREFIX.length(), arg.length()));
                } else if (arg.startsWith(ADDRESS_PREFIX)) {
                    hostname = arg.substring(ADDRESS_PREFIX.length(), arg.length());
                } else if (arg.startsWith(PORT_PREFIX)) {
                    try {
                        port = Integer.valueOf(arg.substring(PORT_PREFIX.length(), arg.length()));
                    } catch (Exception e) {
                        System.err.println("Invalid port specified [" + arg + "]. Cause: " + e);
                    }
                } else if (arg.startsWith(SCRIPT_PREFIX)) {
                    scriptPaths.add(arg.substring(SCRIPT_PREFIX.length(), arg.length()));
                } else if (arg.startsWith(LISTENER_PREFIX)) {
                    String value = arg.substring(LISTENER_PREFIX.length(), arg.length());
                    allowRedefine = Boolean.parseBoolean(value);
                } else if (arg.startsWith(REDEFINE_PREFIX)) {
                    // this is only for backwards compatibility -- it is the same as listener
                    String value = arg.substring(REDEFINE_PREFIX.length(), arg.length());
                    allowRedefine = Boolean.parseBoolean(value);
                } else if (arg.startsWith(PROP_PREFIX)) {
                    // this can be used to set byteman properties
                    String prop = arg.substring(PROP_PREFIX.length(), arg.length());
                    String value="";
                    if (prop.startsWith(BYTEMAN_PREFIX)) {
                        int index = prop.indexOf('=');
                        if (index > 0) {
                            // need to split off the value
                            if (index == prop.length() - 1)
                            {
                                // value is empty so just drop the =
                                prop = prop.substring(0, index);
                            } else {
                                value = prop.substring(index + 1);
                                prop = prop.substring(0, index);
                            }
                        }
                        System.out.println("Setting " + prop + "=" + value);
                        System.setProperty(prop, value);
                    } else {
                        System.err.println("Invalid property : " +  prop);
                    }
                } else {
                    System.err.println("org.jboss.byteman.agent.Main:\n" +
                            "  illegal agent argument : " + arg + "\n" +
                            "  valid arguments are boot:<path-to-jar>, sys:<path-to-jar>, script:<path-to-script> or listener:<true-or-false>");
                }
            }
        }

        // add any boot jars to the boot class path

        for (String bootJarPath : bootJarPaths) {
            try {
                JarFile jarfile = new JarFile(new File(bootJarPath));
                inst.appendToBootstrapClassLoaderSearch(jarfile);
            } catch (IOException ioe) {
                System.err.println("org.jboss.byteman.agent.Main: unable to open boot jar file : " + bootJarPath);
                throw ioe;
            }
        }

        // add any sys jars to the system class path

        for (String sysJarPath : sysJarPaths) {
            try {
                JarFile jarfile = new JarFile(new File(sysJarPath));
                inst.appendToSystemClassLoaderSearch(jarfile);
            } catch (IOException ioe) {
                System.err.println("org.jboss.byteman.agent.Main: unable to open system jar file : " + sysJarPath);
                throw ioe;
            }
        }
        // create a socket so we can be sure it is loaded before the transformer gets cerated. otherwise
        // we seem to hit a deadlock when trying to instrument socket

        Socket dummy = new Socket();

        // look up rules in any script files

        for (String scriptPath : scriptPaths) {
            try {
                FileInputStream fis = new FileInputStream(scriptPath);
                byte[] bytes = new byte[fis.available()];
                fis.read(bytes);
                String ruleScript = new String(bytes);
                scripts.add(ruleScript);
            } catch (IOException ioe) {
                System.err.println("org.jboss.byteman.agent.Main: unable to read rule script file : " + scriptPath);
                throw ioe;
            }
        }

        // install an instance of Transformer to instrument the bytecode
        // n.b. this is done with boxing gloves on using explicit class loading and method invocation
        // via reflection for a GOOD reason. This class (Main) gets laoded by the System class loader.
        // If we refer to Transformer by name then it also gets loaded va the System class loader.
        // But if we want to transform a bootstrap class we need Transformer (et al) to be visible
        // from the bootstrap class loader. That will not happen until after this method has called
        // inst.appendToBootstrapClassLoaderSearch (see above) to add the byteman jar to the path.
        // Directly referring to Transformer will giveus two versions of Transformer et al. Not only
        // does that cause us class mismathc problem it also means that a new done here will not install
        // the new instance in the static field fo the oneloaded in the bootstrap loader. If instead we
        // use boxing gloves then the byteman code wil get loaded in the bootstrap loader and its constructor
        // will be called.
        //
        // Of course, if the user does not supply boot:byteman.jar as a -javaagent option then class references
        // resolve against the system loader and injection into bootstrap classes fails. But that's still ok
        // because the byteman classes are still only foudn in one place.

        boolean isRedefine = inst.isRedefineClassesSupported();

        ClassFileTransformer transformer;
        ClassLoader loader = ClassLoader.getSystemClassLoader();
        Class transformerClazz;

        if (allowRedefine && isRedefine) {
            transformerClazz = loader.loadClass("org.jboss.byteman.agent.Retransformer");
            //transformer = new Retransformer(inst, scriptPaths, scripts, true);
            Constructor constructor = transformerClazz.getConstructor(Instrumentation.class, List.class, List.class, boolean.class);
            transformer = (ClassFileTransformer)constructor.newInstance(new Object[] { inst, scriptPaths, scripts, isRedefine});
        } else {
            transformerClazz = loader.loadClass("org.jboss.byteman.agent.Transformer");
            //transformer = new Transformer(inst, scriptPaths, scripts, isRedefine);
            Constructor constructor = transformerClazz.getConstructor(Instrumentation.class, List.class, List.class, boolean.class);
            transformer = (ClassFileTransformer)constructor.newInstance(new Object[] { inst, scriptPaths, scripts, isRedefine});
        }

        inst.addTransformer(transformer, true);
       
        if (allowRedefine && isRedefine) {
            Method method = transformerClazz.getMethod("addTransformListener", String.class, Integer.class);
            method.invoke(transformer, hostname, port);
        }

        if (isRedefine) {
            Method method;

            method = transformerClazz.getMethod("installBootScripts");
            method.invoke(transformer);
            //transformer.installBootScripts();
        }
    }

    public static void agentmain(String args, Instrumentation inst) throws Exception
    {
        premain(args, inst);
    }
    /**
     * prefix used to specify port argument for agent
     */
    private static final String PORT_PREFIX = "port:";

    /**
     * prefix used to specify bind address argument for agent
     */
    private static final String ADDRESS_PREFIX = "address:";
   
    /**
     * prefix used to specify boot jar argument for agent
     */
    private static final String BOOT_PREFIX = "boot:";

    /**
     * prefix used to specify system jar argument for agent
     */
    private static final String SYS_PREFIX = "sys:";

    /**
     * prefix used to specify script argument for agent
     */

    private static final String SCRIPT_PREFIX = "script:";

    /**
     * prefix used to specify transformer type argument for agent
     */

    private static final String LISTENER_PREFIX = "listener:";

    /**
     * for backwards compatibiltiy
     */

    private static final String REDEFINE_PREFIX = "redefine:";

    /**
     * prefix used to specify system properties to be set before starting the agent
     */

    private static final String PROP_PREFIX = "prop:";

    /**
     * list of paths to extra bootstrap jars supplied on command line
     */
    private static List<String> bootJarPaths = new ArrayList<String>();

    /**
     * list of paths to extra system jars supplied on command line
     */
    private static List<String> sysJarPaths = new ArrayList<String>();

    /**
     * list of paths to script files supplied on command line
     */
    private static List<String> scriptPaths = new ArrayList<String>();

    /**
     * list of scripts read from script files
     */
    private static List<String> scripts = new ArrayList<String>();
   
    /**
     * The hostname to bind the listener to, supplied on the command line (optional argument)
     */
    private static String hostname = null;
   
    /**
     * The port that the listener will listen to, supplied on the command line (optional argument)
     */
    private static Integer port = null;
}
TOP

Related Classes of org.jboss.byteman.agent.Main

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.