Skip to content

Instantly share code, notes, and snippets.

@damc-dev
Created September 29, 2014 20:18
Show Gist options
  • Save damc-dev/4be0097ed91ca23b315a to your computer and use it in GitHub Desktop.
Save damc-dev/4be0097ed91ca23b315a to your computer and use it in GitHub Desktop.
Byteman Custom Script Reloading
/*
* JBoss, Home of Professional Open Source
* Copyright 2008-10 Red Hat 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 com.example.proj.agent;
import java.io.InputStream;
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 AgentMain {
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 (AgentMain.class) {
if (firstTime) {
firstTime = false;
} else {
throw new Exception("Main : attempting to load Byteman agent more than once");
}
}
boolean allowRedefine = false;
boolean installPolicy = 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());
// setting host name forces listener on
allowRedefine = true;
} else if (arg.startsWith(PORT_PREFIX)) {
try {
port = Integer.valueOf(arg.substring(PORT_PREFIX.length(), arg.length()));
if (port <= 0) {
System.err.println("Invalid port specified [" + port + "]");
port = null;
} else {
// setting port forces listener on
allowRedefine = true;
}
} 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(RESOURCE_SCRIPT_PREFIX)) {
resourcescriptPaths.add(arg.substring(RESOURCE_SCRIPT_PREFIX.length(), arg.length()));
} else if (arg.startsWith(LISTENER_PREFIX)) {
String value = arg.substring(LISTENER_PREFIX.length(), arg.length());
allowRedefine = Boolean.parseBoolean(value);
// clearing listener when port or host is set should be flagged
if (!allowRedefine && (hostname != null || port != null)) {
System.err.println("listener disabled with host/port set");
}
} 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);
// clearing listener when port or host is set should be flagged
if (!allowRedefine && (hostname != null || port != null)) {
System.err.println("listener disabled with host/port set");
}
} 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 if (arg.startsWith(POLICY_PREFIX)) {
String value = arg.substring(POLICY_PREFIX.length(), arg.length());
installPolicy = Boolean.parseBoolean(value);
} 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;
}
}
// look up rules in any resource script files
for (String scriptPath : resourcescriptPaths) {
try {
InputStream is = ClassLoader.getSystemResourceAsStream(scriptPath);
if (is == null) {
throw new Exception("org.jboss.byteman.agent.Main: could not read rule script resource file : " + scriptPath);
}
byte[] bytes = new byte[is.available()];
is.read(bytes);
String ruleScript = new String(bytes);
scripts.add(ruleScript);
// merge the resource and file script paths into one list
scriptPaths.add(scriptPath);
} catch (IOException ioe) {
System.err.println("org.jboss.byteman.agent.Main: error reading rule script resource 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("com.example.proj.agent.AgentRetransformer");
//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");
method.invoke(transformer);
}
if (installPolicy) {
Method method = transformerClazz.getMethod("installPolicy");
method.invoke(transformer);
}
if (isRedefine) {
Method method = transformerClazz.getMethod("installBootScripts");
method.invoke(transformer);
}
}
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 request installation of an access-all-areas security
* policy at install time for agent code
*/
private static final String POLICY_PREFIX = "policy:";
/**
* prefix used to specify file script argument for agent
*/
private static final String SCRIPT_PREFIX = "script:";
/**
* prefix used to specify resource script argument for agent
*/
private static final String RESOURCE_SCRIPT_PREFIX = "resourcescript:";
/**
* 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 paths to resource script files supplied on command line
*/
private static List<String> resourcescriptPaths = 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;
}
package com.example.proj.agent;
import java.io.PrintWriter;
import java.lang.instrument.Instrumentation;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.jar.JarFile;
import org.jboss.byteman.agent.RuleScript;
import org.jboss.byteman.agent.ScriptRepository;
import org.jboss.byteman.agent.Transform;
import org.jboss.byteman.agent.Transformer;
public class AgentRetransformer extends Transformer {
private Set<String> sysJars = new HashSet<String>(); // jar files that were loaded in the sys CL
private Set<String> bootJars = new HashSet<String>(); // jar files that were loaded in the boot CL
/**
* constructor allowing this transformer to be provided with access to the JVM's instrumentation
* implementation
*
* @param inst the instrumentation object used to interface to the JVM
*/
public AgentRetransformer(Instrumentation inst, List<String> scriptPaths, List<String> scriptTexts, boolean isRedefine)
throws Exception
{
super(inst, scriptPaths, scriptTexts, isRedefine);
//addTransformListener(hostname, port);
}
public void installScript(List<String> scriptTexts, List<String> scriptNames, PrintWriter out) throws Exception
{
int length = scriptTexts.size();
List<RuleScript> toBeAdded = new LinkedList<RuleScript>();
List<RuleScript> toBeRemoved = new LinkedList<RuleScript>();
for (int i = 0; i < length ; i++) {
String scriptText = scriptTexts.get(i);
String scriptName = scriptNames.get(i);
List<RuleScript> ruleScripts = scriptRepository.processScripts(scriptText, scriptName);
toBeAdded.addAll(ruleScripts);
}
for (RuleScript ruleScript : toBeAdded) {
String name = ruleScript.getName();
String className = ruleScript.getTargetClass();
String baseName = null;
int lastDotIdx = className.lastIndexOf('.');
if (lastDotIdx >= 0) {
baseName = className.substring(lastDotIdx + 1);
}
RuleScript previous;
previous = scriptRepository.addScript(ruleScript);
if (previous != null) {
out.println("redefine rule " + name);
toBeRemoved.add(previous);
} else {
out.println("install rule " + name);
}
}
// ok, now that we have updated the indexes we need to find all classes which match the scripts and
// retransform them
// list all class names for the to be aded and to be removed scripts
List<String> deletedClassNames = new LinkedList<String>();
for (RuleScript ruleScript : toBeRemoved) {
List<Transform> transforms = ruleScript.getTransformed();
for (Transform transform : transforms) {
String className = transform.getInternalClassName();
if (!deletedClassNames.contains(className)) {
deletedClassNames.add(className);
}
}
}
// for added scripts we have to transform anything which might be a match
ScriptRepository tmpRepository = new ScriptRepository(skipOverrideRules());
for (RuleScript ruleScript : toBeAdded) {
tmpRepository.addScript(ruleScript);
}
// now look for loaded classes whose names are in the deleted list or which match added rules
List<Class<?>> transformed = new LinkedList<Class<?>>();
for (Class clazz : inst.getAllLoadedClasses()) {
if (isSkipClass(clazz)) {
continue;
}
if (deletedClassNames.contains(clazz.getName())) {
transformed.add(clazz);
} else if (tmpRepository.matchClass(clazz)) {
transformed.add(clazz);
}
}
// retransform all classes whose rules have changed
if (!transformed.isEmpty()) {
Class<?>[] transformedArray = new Class<?>[transformed.size()];
transformed.toArray(transformedArray);
if (Transformer.isVerbose()) {
for (int i = 0; i < transformed.size(); i++) {
System.out.println("retransforming " + transformedArray[i].getName());
}
}
synchronized(this) {
try {
inst.retransformClasses(transformedArray);
} catch(VerifyError ve) {
System.out.println("Retransformer : VerifyError during retransformation : some rules may not have been correctly injected or uninjected!");
ve.printStackTrace();
out.println("VerifyError during retransformation : some rules may not have been correctly injected or uninjected!");
ve.printStackTrace(out);
}
}
}
// now we can safely purge keys for all deleted scripts
for (RuleScript ruleScript : toBeRemoved) {
ruleScript.purge();
}
}
protected void collectAffectedNames(List<RuleScript> ruleScripts, List<String> classList, List<String> interfaceList,
List<String> superClassList, List<String> superInterfaceList)
{
for (RuleScript ruleScript : ruleScripts) {
String targetClassName = ruleScript.getTargetClass();
boolean isOverride = ruleScript.isOverride();
if (ruleScript.isInterface()) {
if (!interfaceList.contains(targetClassName)) {
interfaceList.add(targetClassName);
if (isOverride) {
superInterfaceList.add(targetClassName);
}
}
} else {
if (!classList.contains(targetClassName)) {
classList.add(targetClassName);
if (isOverride) {
superClassList.add(targetClassName);
}
}
}
}
}
protected void listScripts(PrintWriter out) throws Exception
{
Iterator<RuleScript> iterator = scriptRepository.currentRules().iterator();
if (!iterator.hasNext()) {
out.println("no rules installed");
} else {
while (iterator.hasNext()) {
RuleScript ruleScript = iterator.next();
ruleScript.writeTo(out);
synchronized (ruleScript) {
List<Transform> transformed = ruleScript.getTransformed();
if (transformed != null) {
Iterator<Transform> iter = transformed.iterator();
while (iter.hasNext()) {
Transform transform = iter.next();
transform.writeTo(out);
}
}
}
}
}
}
public void addTransformListener()
{
ScriptReload.initialize(this);
}
public void removeScripts(List<String> scriptTexts, PrintWriter out) throws Exception
{
List<RuleScript> toBeRemoved;
if (scriptTexts != null) {
toBeRemoved = new LinkedList<RuleScript>();
int length = scriptTexts.size();
for (int i = 0; i < length ; i++) {
String scriptText = scriptTexts.get(i);
String[] lines = scriptText.split("\n");
for (int j = 0; j < lines.length; j++) {
String line = lines[j].trim();
if (line.startsWith("RULE ")) {
String name = line.substring(5).trim();
RuleScript ruleScript = scriptRepository.scriptForRuleName(name);
if (ruleScript == null) {
out.print("ERROR failed to find loaded rule with name ");
out.println(name);
} else if (toBeRemoved.contains(ruleScript)) {
out.print("WARNING duplicate occurence for rule name ");
out.println(name);
} else {
toBeRemoved.add(ruleScript);
}
}
}
}
} else {
toBeRemoved = scriptRepository.currentRules();
}
if (toBeRemoved.isEmpty()) {
out.println("ERROR No rule scripts to remove");
return;
}
for (RuleScript ruleScript : toBeRemoved) {
if (scriptRepository.removeScript(ruleScript) != ruleScript) {
out.println("ERROR remove failed to find script " + ruleScript.getName());
}
}
// ok, now that we have updated the maps and deleted the scripts
// we need to find all classes which were transformed by
// the scripts and retransform them
// now look for loaded classes whose names are in the list
List<Class<?>> transformed = new LinkedList<Class<?>>();
List<String> deletedClassNames = new LinkedList<String>();
for (RuleScript ruleScript : toBeRemoved) {
List<Transform> transforms = ruleScript.getTransformed();
if (transforms != null) {
for (Transform transform : transforms) {
String className = transform.getInternalClassName();
if (!deletedClassNames.contains(className)) {
deletedClassNames.add(className);
}
}
}
}
for (Class clazz : inst.getAllLoadedClasses()) {
if (isSkipClass(clazz)) {
continue;
}
if (deletedClassNames.contains(clazz.getName())) {
transformed.add(clazz);
}
}
// retransform all classes affected by the change
if (!transformed.isEmpty()) {
Class<?>[] transformedArray = new Class<?>[transformed.size()];
transformed.toArray(transformedArray);
if (Transformer.isVerbose()) {
for (int i = 0; i < transformed.size(); i++) {
System.out.println("retransforming " + transformedArray[i].getName());
}
}
try {
inst.retransformClasses(transformedArray);
} catch(VerifyError ve) {
System.out.println("Retransformer : VerifyError during retransformation : some rules may not have been correctly uninjected!");
ve.printStackTrace();
out.println("VerifyError during retransformation : some rules may not have been correctly uninjected!");
ve.printStackTrace(out);
}
}
// now we can safely purge keys for all the deleted scripts -- we need to do this
// after the retransform because the latter removes the trigger code which uses
// the rule key
for (RuleScript ruleScript : toBeRemoved) {
ruleScript.purge();
out.println("uninstall RULE " + ruleScript.getName());
}
}
public void appendJarFile(PrintWriter out, JarFile jarfile, boolean isBoot) throws Exception
{
if (isBoot) {
inst.appendToBootstrapClassLoaderSearch(jarfile);
bootJars.add(jarfile.getName());
out.println("append boot jar " + jarfile.getName());
} else {
inst.appendToSystemClassLoaderSearch(jarfile);
sysJars.add(jarfile.getName());
out.println("append sys jar " + jarfile.getName());
}
}
/**
* Returns jars that this retransformer was asked to
* {@link #appendJarFile(PrintWriter, JarFile, boolean) add} to the boot classloader.
*
* Note that the returned set will not include those jars that were added to the
* instrumentor object at startup via the -javaagent command line argument.
*
* @return set of jar pathnames for all jars loaded in the boot classloader
*/
public Set<String> getLoadedBootJars() {
return new HashSet<String>(bootJars); // returns a copy
}
/**
* Returns jars that this retransformer was asked to
* {@link #appendJarFile(PrintWriter, JarFile, boolean) add} to the system classloader.
*
* Note that the returned set will not include those jars that were added to the
* instrumentor object at startup via the -javaagent command line argument.
*
* @return set of jar pathnames for all jars loaded in the system classloader
*/
public Set<String> getLoadedSystemJars() {
return new HashSet<String>(sysJars); // returns a copy
}
}
package com.example.proj.agent;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.jar.JarFile;
import org.jboss.byteman.agent.Transformer;
public class ScriptReload extends Thread {
private static ScriptReload scriptReload = null;
private AgentRetransformer retransformer;
private static List<String> scriptTexts;
private static List<String> scriptNames;
ScriptReload(AgentRetransformer agentRetransformer) {
this.retransformer = agentRetransformer;
setDaemon(true);
}
public void run() {
scriptTexts = Arrays.asList("RULE jabber\nCLASS java.lang.Thread\nMETHOD start()\nIF true\nDO traceln(\"*** start for thread: \"+ $0.getName())\nENDRULE\n");
scriptNames = Arrays.asList("newRules.btm");
PrintStream stdout = System.out;
System.setOut(stdout);
PrintWriter printWriter = new PrintWriter(stdout);
while (true) {
try {
Thread.sleep(5000);
/*
* Get new script however you want
*/
System.out.printf("Installing Scripts %s\n", scriptNames.toString());
retransformer.installScript(scriptTexts, scriptNames, printWriter);
} catch(InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static synchronized boolean initialize(AgentRetransformer agentRetransformer) {
if(scriptReload == null) {
scriptReload = new ScriptReload(agentRetransformer);
scriptReload.start();
}
return true;
}
private void getVersion(BufferedReader in, PrintWriter out) {
String version = this.getClass().getPackage().getImplementationVersion();
if (version == null) {
version = "0";
}
out.println(version);
out.println("OK");
out.flush();
}
private void loadScripts(BufferedReader in, PrintWriter out) throws IOException
{
handleScripts(in, out, false);
}
private void loadJars(BufferedReader in, PrintWriter out, boolean isBoot) throws IOException
{
final String endMarker = (isBoot) ? "ENDBOOT" : "ENDSYS";
String line = in.readLine().trim();
while (line != null && !line.equals(endMarker)) {
try {
JarFile jarfile = new JarFile(new File(line));
retransformer.appendJarFile(out, jarfile, isBoot);
} catch (Exception e) {
out.append("EXCEPTION ");
out.append("Unable to add jar file " + line + "\n");
out.append(e.toString());
out.append("\n");
e.printStackTrace(out);
}
line = in.readLine().trim();
}
if (line == null || !line.equals(endMarker)) {
out.append("ERROR\n");
out.append("Unexpected end of line reading " + ((isBoot) ? "boot" : "system") + " jars\n");
}
out.println("OK");
out.flush();
}
private void deleteScripts(BufferedReader in, PrintWriter out) throws IOException
{
handleScripts(in, out, true);
}
private void handleScripts(BufferedReader in, PrintWriter out, boolean doDelete) throws IOException
{
List<String> scripts = new LinkedList<String>();
List<String> scriptNames = new LinkedList<String>();
String line = in.readLine().trim();
String scriptName = "<unknown>";
while (line.startsWith("SCRIPT ")) {
StringBuffer stringBuffer = new StringBuffer();
scriptName = line.substring("SCRIPT ".length());
line = in.readLine();
while (line != null && !line.equals("ENDSCRIPT")) {
stringBuffer.append(line);
stringBuffer.append('\n');
line = in.readLine();
}
if (line == null || !line.equals("ENDSCRIPT")) {
out.append("ERROR\n");
out.append("Unexpected end of line reading script " + scriptName + "\n");
out.append("OK");
out.flush();
return;
}
String script = stringBuffer.toString();
scripts.add(script);
scriptNames.add(scriptName);
line = in.readLine();
}
if ((doDelete && !line.equals("ENDDELETE")) ||
(!doDelete && !line.equals("ENDLOAD"))) {
out.append("ERROR ");
out.append("Unexpected end of line reading script " + scriptName + "\n");
out.println("OK");
out.flush();
return;
}
try {
if (doDelete) {
retransformer.removeScripts(scripts, out);
} else {
retransformer.installScript(scripts, scriptNames, out);
}
} catch (Exception e) {
out.append("EXCEPTION ");
out.append(e.toString());
out.append('\n');
e.printStackTrace(out);
}
out.println("OK");
out.flush();
}
private void purgeScripts(BufferedReader in, PrintWriter out) throws Exception
{
retransformer.removeScripts(null, out);
out.println("OK");
out.flush();
}
private void listScripts(BufferedReader in, PrintWriter out) throws Exception
{
retransformer.listScripts(out);
out.println("OK");
out.flush();
}
private void listBootJars(BufferedReader in, PrintWriter out) throws Exception
{
Set<String> jars = retransformer.getLoadedBootJars();
for (String jar : jars) {
out.println(new File(jar).getAbsolutePath());
}
out.println("OK");
out.flush();
}
private void listSystemJars(BufferedReader in, PrintWriter out) throws Exception
{
Set<String> jars = retransformer.getLoadedSystemJars();
for (String jar : jars) {
out.println(new File(jar).getAbsolutePath());
}
out.println("OK");
out.flush();
}
private void listSystemProperties(BufferedReader in, PrintWriter out) throws Exception
{
Properties sysProps = System.getProperties();
boolean strictMode = false;
if (Boolean.parseBoolean(sysProps.getProperty(Transformer.SYSPROPS_STRICT_MODE, "true"))) {
strictMode = true;
}
for (Map.Entry<Object, Object> entry : sysProps.entrySet()) {
String name = entry.getKey().toString();
if (!strictMode || name.startsWith("org.jboss.byteman.")) {
String value = entry.getValue().toString();
out.println(name + "=" + value.replace("\n", "\\n").replace("\r", "\\r"));
}
}
out.println("OK");
out.flush();
}
private void setSystemProperties(BufferedReader in, PrintWriter out) throws Exception
{
boolean strictMode = false;
if (Boolean.parseBoolean(System.getProperty(Transformer.SYSPROPS_STRICT_MODE, "true"))) {
strictMode = true;
}
final String endMarker = "ENDSETSYSPROPS";
String line = in.readLine().trim();
while (line != null && !line.equals(endMarker)) {
try {
String[] nameValuePair = line.split("=", 2);
if (nameValuePair.length != 2 ) {
throw new Exception("missing '='");
}
String name = nameValuePair[0];
String value = nameValuePair[1];
if (strictMode && !name.startsWith("org.jboss.byteman.")) {
throw new Exception("strict mode is enabled, cannot set non-byteman system property");
}
if (name.equals(Transformer.SYSPROPS_STRICT_MODE) && !value.equals("true")) {
// nice try
throw new Exception("cannot turn off strict mode");
}
// everything looks good and we are allowed to set the system property now
if (value.length() > 0) {
// "some.sys.prop=" means the client wants to delete the system property
System.setProperty(name, value);
out.append("Set system property [" + name + "] to value [" + value + "]\n");
} else {
System.clearProperty(name);
out.append("Deleted system property [" + name + "]\n");
}
// ok, now tell the transformer a property has changed
retransformer.updateConfiguration(name);
} catch (Exception e) {
out.append("EXCEPTION ");
out.append("Unable to set system property [" + line + "]\n");
out.append(e.toString());
out.append("\n");
e.printStackTrace(out);
}
line = in.readLine().trim();
}
if (line == null || !line.equals(endMarker)) {
out.append("ERROR\n");
out.append("Unexpected end of line reading system properties\n");
}
out.println("OK");
out.flush();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment