[jboss-svn-commits] JBL Code SVN: r29187 - in labs/jbosstm/workspace/adinn/byteman/trunk: bin and 3 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Fri Sep 4 12:00:06 EDT 2009
Author: adinn
Date: 2009-09-04 12:00:06 -0400 (Fri, 04 Sep 2009)
New Revision: 29187
Added:
labs/jbosstm/workspace/adinn/byteman/trunk/bin/submit.sh
labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Retransformer.java
labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/TransformListener.java
labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/submit/
labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/submit/Submit.java
Modified:
labs/jbosstm/workspace/adinn/byteman/trunk/build.xml
labs/jbosstm/workspace/adinn/byteman/trunk/docs/ProgrammersGuide.odt
labs/jbosstm/workspace/adinn/byteman/trunk/docs/ProgrammersGuide.pdf
labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Main.java
labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/RuleScript.java
labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Transformer.java
Log:
initial draft of dynamic rule upload capability which attempts to fix BYTEMAN-26 and also incorporates a fix for BYTEMAN-25
Added: labs/jbosstm/workspace/adinn/byteman/trunk/bin/submit.sh
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/bin/submit.sh (rev 0)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/bin/submit.sh 2009-09-04 16:00:06 UTC (rev 29187)
@@ -0,0 +1,62 @@
+#!/bin/bash
+#
+# JBoss, Home of Professional Open Source
+# Copyright 2009, 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
+#
+# shell script which submits a request to the Byteman agent listener
+#
+# usage: submit [script1 . . . scriptN]
+#
+# use the root of the path to this file to locate the byteman jar
+BASE=${0%*bin/submit.sh}
+# the binary release puts byteman jar in lib while source puts it in
+# build/lib so add both paths to the classpath just in case
+CP=${BASE}lib/byteman.jar
+CP=${BASE}build/lib/byteman.jar
+# hmm. the asm code should be bundled in the byteman jar?
+CP=${CP}:${BASE}ext/asm-all-3.0.jar
+
+SCRIPT_OPTS=""
+
+if [ $# -gt 0 -a ${1#-*} != ${1} ]; then
+ echo "${1#-*} ${1}"
+ echo "usage: submit [script1 . . . scriptN]"
+ exit
+fi
+
+error=0
+while [ $# -ne 0 ]
+do
+ if [ ! -f $1 -o ! -r $1 ] ; then
+ echo "$1 is not a readable file";
+ error=1
+ fi
+ FILES="${FILES} $1";
+ shift
+done
+
+if [ $error -ne 0 ] ; then
+ exit
+fi
+
+# allow for extra java opts via setting BYTEMAN_JAVA_OPTS
+
+java ${BYTEMAN_JAVA_OPTS} -classpath ${CP} org.jboss.byteman.agent.submit.Submit $FILES
Property changes on: labs/jbosstm/workspace/adinn/byteman/trunk/bin/submit.sh
___________________________________________________________________
Name: svn:executable
+ *
Modified: labs/jbosstm/workspace/adinn/byteman/trunk/build.xml
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/build.xml 2009-09-04 14:54:01 UTC (rev 29186)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/build.xml 2009-09-04 16:00:06 UTC (rev 29187)
@@ -27,7 +27,9 @@
<property name="ext.asm.jars" value="asm-all-3.0.jar"/>
<property name="src.dir" value="src"/>
+ <property name="src.dir.jdk6" value="srcjdk6"/>
<property name="dd.dir" value="dd"/>
+ <property name="dd.dir.jdk6" value="ddjdk6"/>
<property name="dd.grammar.dir" value="${dd.dir}/grammar"/>
<property name="ext.lib.dir" value="ext"/>
<property name="build.dir" value="build"/>
@@ -111,7 +113,7 @@
<target name="jar" depends="compile">
<!--
<unjar src="${ext.lib.dir}/junit.jar" dest="${build.classes.dir}"/>
- -->
+ -->
<unjar src="${ext.lib.dir}/javacuprt.jar" dest="${build.classes.dir}"/>
<unjar src="${ext.lib.dir}/asm-all-3.0.jar" dest="${build.classes.dir}"/>
<jar jarfile="${build.lib.dir}/byteman.jar" manifest="${dd.dir}/META-INF/MANIFEST.MF">
@@ -124,7 +126,7 @@
<fileset dir="${build.dir}" includes="lib/byteman.jar"/>
<fileset dir="." includes="README"/>
<fileset dir="." includes="docs/ProgrammersGuide.pdf"/>
- <fileset dir="." includes="bin/bytemancheck.sh"/>
+ <fileset dir="." includes="bin/bytemancheck.sh" "bin/submit.sh"/>
<fileset dir="." includes="ext/asm-all-3.0.jar"/>
<fileset dir="." includes="ext/third_party_licenses.txt"/>
</zip>
@@ -156,6 +158,7 @@
<fileset dir="${ext.lib.dir}" includes="${ext.javacup.rt.jars}"/>
</classpath>
<fileset dir="${src.dir}" includes="**/*.java"/>
+ <fileset dir="${src.dir.jdk6}" includes="**/*.java"/>
</javadoc>
</target>
Modified: labs/jbosstm/workspace/adinn/byteman/trunk/docs/ProgrammersGuide.odt
===================================================================
(Binary files differ)
Modified: labs/jbosstm/workspace/adinn/byteman/trunk/docs/ProgrammersGuide.pdf
===================================================================
(Binary files differ)
Modified: labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Main.java
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Main.java 2009-09-04 14:54:01 UTC (rev 29186)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Main.java 2009-09-04 16:00:06 UTC (rev 29187)
@@ -39,6 +39,8 @@
public static void premain(String args, Instrumentation inst)
throws Exception
{
+ boolean allowRedefine = false;
+
if (args != null) {
// args are supplied eparated by ',' characters
String[] argsArray = args.split(",");
@@ -48,10 +50,13 @@
bootJarPaths.add(arg.substring(BOOT_PREFIX.length(), arg.length()));
} else if (arg.startsWith(SCRIPT_PREFIX)) {
scriptPaths.add(arg.substring(SCRIPT_PREFIX.length(), arg.length()));
+ } else if (arg.startsWith(REDEFINE_PREFIX)) {
+ String value = arg.substring(REDEFINE_PREFIX.length(), arg.length());
+ allowRedefine = 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> or script:<path-to-scriptr>");
+ " valid arguments are boot:<path-to-jar>, script:<path-to-script> or redefine:<true-or-false>");
}
}
}
@@ -62,7 +67,7 @@
for (String bootJarPath : bootJarPaths) {
try {
JarFile jarfile = new JarFile(new File(bootJarPath));
- // inst.appendToBootstrapClassLoaderSearch(jarfile);
+ inst.appendToBootstrapClassLoaderSearch(jarfile);
} catch (IOException ioe) {
System.err.println("org.jboss.byteman.agent.Main: unable to open boot jar file : " + bootJarPath);
throw ioe;
@@ -90,7 +95,18 @@
// install an instance of Transformer to instrument the bytecode
- inst.addTransformer(new Transformer(inst, scriptPaths, scripts));
+ boolean isRedefine = inst.isRedefineClassesSupported();
+
+ if (allowRedefine && isRedefine) {
+ System.out.println("Adding retransformer");
+ Retransformer retransformer = new Retransformer(inst, scriptPaths, scripts);
+ inst.addTransformer(retransformer, true);
+ retransformer.installBootScripts();
+ } else {
+ System.out.println("Adding transformer");
+ inst.addTransformer(new Transformer(inst, scriptPaths, scripts, isRedefine), isRedefine);
+ }
+
}
/**
@@ -105,6 +121,12 @@
private static final String SCRIPT_PREFIX = "script:";
/**
+ * prefix used to specify transformer type argument for agent
+ */
+
+ private static final String REDEFINE_PREFIX = "redefine:";
+
+ /**
* list of paths to extra bootstrap jars supplied on command line
*/
private static List<String> bootJarPaths = new ArrayList<String>();
@@ -118,4 +140,4 @@
* list of scripts read from script files
*/
private static List<String> scripts = new ArrayList<String>();
-}
+}
\ No newline at end of file
Copied: labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Retransformer.java (from rev 27152, labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Transformer.java)
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Retransformer.java (rev 0)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Retransformer.java 2009-09-04 16:00:06 UTC (rev 29187)
@@ -0,0 +1,243 @@
+/*
+* 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.util.*;
+import java.io.PrintWriter;
+
+/**
+ * byte code transformer used to introduce byteman events into JBoss code
+ */
+public class Retransformer extends Transformer {
+
+ /**
+ * 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 Retransformer(Instrumentation inst, List<String> scriptPaths, List<String> scriptTexts)
+ throws Exception
+ {
+ super(inst, scriptPaths, scriptTexts, true);
+ addTransformListener();
+ }
+
+ protected void installScript(List<String> scriptTexts, List<String> scriptNames) 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 = 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;
+
+ synchronized (nameToScriptMap) {
+ previous = nameToScriptMap.get(name);
+ if (previous != null) {
+ System.out.println("redefining rule " + name);
+ toBeRemoved.add(previous);
+ previous.setDeleted();
+ }
+ nameToScriptMap.put(name, ruleScript);
+ }
+
+ // remove any old scripts and install the new ones to ensure that
+ // automatic loads do the right thing
+
+ synchronized(targetToScriptMap) {
+ List<RuleScript> list = targetToScriptMap.get(className);
+ if (list != null) {
+ if (previous != null) {
+ list.remove(previous);
+ }
+ } else {
+ list = new ArrayList<RuleScript>();
+ targetToScriptMap.put(className, list);
+ }
+ list.add(ruleScript);
+ if (baseName != null) {
+ list = targetToScriptMap.get(baseName);
+ if (list != null) {
+ if (previous != null) {
+ list.remove(previous);
+ }
+ } else {
+ list = new ArrayList<RuleScript>();
+ targetToScriptMap.put(baseName, list);
+ }
+ }
+ }
+ }
+
+
+ // ok, now that we have updated the maps we need to find all classes which match the scripts and
+ // retransform them
+
+ List<Class<?>> transformed = new LinkedList<Class<?>>();
+
+ for (Class clazz : inst.getAllLoadedClasses()) {
+ String name = clazz.getName();
+ int lastDot = name.lastIndexOf('.');
+
+ if (isBytemanClass(name) || !isTransformable(name)) {
+ continue;
+ }
+
+ if (targetToScriptMap.containsKey(name)) {
+ transformed.add(clazz);
+ } else if (lastDot >= 0 && targetToScriptMap.containsKey(name.substring(lastDot+1))) {
+ transformed.add(clazz);
+ }
+ }
+
+ // retransform all classes whose rules have changed
+
+ if (!transformed.isEmpty()) {
+ Class<?>[] transformedArray = new Class<?>[transformed.size()];
+ inst.retransformClasses(transformed.toArray(transformedArray));
+ }
+ }
+
+
+ protected void listScripts(PrintWriter out) throws Exception
+ {
+ synchronized (nameToScriptMap) {
+ Iterator<RuleScript> iterator = nameToScriptMap.values().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);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void addTransformListener()
+ {
+ TransformListener.initialize(this);
+ }
+
+ /**
+ * ensure that scripts which apply to classes loaded before registering the transformer get
+ * are installed by retransforming the relevant classes
+ */
+
+ public void installBootScripts() throws Exception
+ {
+ // check for scrips which apply to classes already loaded during bootstrap and retransform those classes
+ // so that rule triggers are injected
+
+ List<Class<?>> omitted = new LinkedList<Class<?>>();
+
+ Class<?>[] loaded = inst.getAllLoadedClasses();
+ if (isVerbose()) {
+ System.out.println("loaded classes size = " + loaded.length);
+ }
+
+ for (Class clazz : loaded) {
+ String name = clazz.getName();
+ int lastDot = name.lastIndexOf('.');
+
+ if (isBytemanClass(name) || !isTransformable(name)) {
+ continue;
+ }
+
+ boolean found = false;
+
+ // although this is done synchronized a transformation may sneak in between this check and
+ // the retransformClasses call below causing unnecessary redefinition of the some classes
+ // TODO -- see if we can tighten up the synchronization here (probably very tricky :-)
+ synchronized(targetToScriptMap) {
+ List<RuleScript> scripts = targetToScriptMap.get(name);
+ if (scripts != null) {
+ for (RuleScript script : scripts) {
+ System.out.println("Checking script " + script.getName());
+ if (!script.hasTransform(clazz)) {
+ omitted.add(clazz);
+ found = true;
+ if (isVerbose()) {
+ System.out.println("Found script for bootstrap class " + clazz.getName());
+ }
+ break;
+ }
+ }
+ }
+ if (!found && lastDot >= 0) {
+ scripts = targetToScriptMap.get(name.substring(lastDot + 1));
+ if (scripts != null) {
+ for (RuleScript script : scripts) {
+ System.out.println("Checking script " + script.getName());
+ if (!script.hasTransform(clazz)) {
+ omitted.add(clazz);
+ found = true;
+ if (isVerbose()) {
+ System.out.println("Found script for bootstrap class " + clazz.getName());
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // retransform all classes for which we found untransformed rules
+
+ if (!omitted.isEmpty()) {
+ Class<?>[] transformedArray = new Class<?>[omitted.size()];
+ inst.retransformClasses(omitted.toArray(transformedArray));
+ }
+ }
+}
Modified: labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/RuleScript.java
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/RuleScript.java 2009-09-04 14:54:01 UTC (rev 29186)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/RuleScript.java 2009-09-04 16:00:06 UTC (rev 29187)
@@ -96,8 +96,8 @@
}
/**
- * getter for list of transformed applied for this script. must be called synchronized on the script.
- * @return te list of transforms
+ * getter for list of transforms applied for this script. must be called synchronized on the script.
+ * @return the list of transforms
*/
public List<Transform> getTransformed()
{
@@ -105,6 +105,15 @@
}
/**
+ * return a count of the number of transforms applied for this script. must be called synchronized on the script.
+ * @return the size of the list of transforms
+ */
+ public int getTransformedCount()
+ {
+ return (transformed != null ? transformed.size() : 0);
+ }
+
+ /**
* invoked by the retransformer code when a rule is redefined to inhibit further transformations via this script
*/
public synchronized void setDeleted()
@@ -154,6 +163,24 @@
transformed.add(transform);
}
+
+ public synchronized boolean hasTransform(Class<?> clazz)
+ {
+ ClassLoader loader = clazz.getClassLoader();
+
+ if (loader == null) {
+ loader = ClassLoader.getSystemClassLoader();
+ }
+
+ int count = getTransformedCount();
+ for (int i = 0; i < count; i++) {
+ Transform transform = transformed.get(i);
+ if (transform.getLoader() == loader) {
+ return true;
+ }
+ }
+ return false;
+ }
/**
* record the fact that a rule has been compiled wiht or without success
* @param triggerClass the name of the trigger class to which the rule is attached
@@ -163,7 +190,7 @@
*/
public synchronized void recordCompile(String triggerClass, ClassLoader loader, boolean successful, String detail)
{
- int count = transformed.size();
+ int count = getTransformedCount();
for (int i = 0; i < count; i++) {
Transform transform = transformed.get(i);
if (transform.getLoader() == loader) {
Added: labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/TransformListener.java
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/TransformListener.java (rev 0)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/TransformListener.java 2009-09-04 16:00:06 UTC (rev 29187)
@@ -0,0 +1,219 @@
+package org.jboss.byteman.agent;
+
+import org.jboss.byteman.agent.Retransformer;
+
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.InetSocketAddress;
+import java.io.*;
+import java.util.List;
+import java.util.LinkedList;
+
+/**
+ * a socket based listener class which reads scripts from stdin and installs them in the current runtime
+ */
+public class TransformListener extends Thread
+{
+ public static int DEFAULT_PORT = 9091;
+ private static TransformListener theTransformListener = null;
+ private static ServerSocket theServerSocket;
+ private Retransformer retransformer;
+
+ private TransformListener(Retransformer retransformer)
+ {
+ this.retransformer = retransformer;
+ setDaemon(true);
+ }
+
+ public static synchronized boolean initialize(Retransformer retransformer)
+ {
+ if (theTransformListener == null) {
+ try {
+ theServerSocket = new ServerSocket();
+ theServerSocket.bind(new InetSocketAddress("localhost", DEFAULT_PORT));
+ } catch (IOException e) {
+ System.out.println("TransformListener() : unexpected exception opening server socket " + e);
+ e.printStackTrace();
+ return false;
+ }
+ theTransformListener = new TransformListener(retransformer);
+
+ theTransformListener.start();
+ }
+
+ return true;
+ }
+
+ public static synchronized boolean terminate()
+ {
+ if (theTransformListener != null) {
+ try {
+ theServerSocket.close();
+ } catch (IOException e) {
+ // ignore -- the thread should exit anyway
+ }
+ try {
+ theTransformListener.join();
+ } catch (InterruptedException e) {
+ // ignore
+ }
+
+ theTransformListener = null;
+ theServerSocket = null;
+ }
+
+ return true;
+ }
+
+ public void run()
+ {
+ while (true) {
+ if (theServerSocket.isClosed()) {
+ return;
+ }
+ Socket socket = null;
+ try {
+ socket = theServerSocket.accept();
+ } catch (IOException e) {
+ if (!theServerSocket.isClosed()) {
+ System.out.println("TransformListener.run : exception from server socket accept " + e);
+ e.printStackTrace();
+ }
+ return;
+ }
+
+ handleConnection(socket);
+ }
+ }
+
+ private void handleConnection(Socket socket)
+ {
+ InputStream is = null;
+ try {
+ is = socket.getInputStream();
+ } catch (IOException e) {
+ // oops. cannot handle this
+ System.out.println("TransformListener.run : error opening socket input stream " + e);
+ e.printStackTrace();
+ try {
+ socket.close();
+ } catch (IOException e1) {
+ System.out.println("TransformListener.run : exception closing socket after failed input stream open" + e1);
+ e1.printStackTrace();
+ }
+ return;
+ }
+
+ OutputStream os = null;
+ try {
+ os = socket.getOutputStream();
+ } catch (IOException e) {
+ // oops. cannot handle this
+ System.out.println("TransformListener.run : error opening socket output stream " + e);
+ e.printStackTrace();
+ try {
+ socket.close();
+ } catch (IOException e1) {
+ System.out.println("TransformListener.run : exception closing socket after failed output stream open" + e1);
+ e1.printStackTrace();
+ }
+ return;
+ }
+
+ BufferedReader in = new BufferedReader(new InputStreamReader(is));
+ PrintWriter out = new PrintWriter(new OutputStreamWriter(os));
+
+ String line = null;
+ try {
+ line = in.readLine();
+ } catch (IOException e) {
+ System.out.println("TransformListener.run : exception " + e + " while reading command");
+ e.printStackTrace();
+ }
+
+ try {
+ if (line == null) {
+ out.println("ERROR");
+ out.println("Expecting input command");
+ out.println("OK");
+ } else if (line.equals("LOAD")) {
+ loadScripts(in, out);
+ } else if (line.equals("LIST")) {
+ listScripts(in, out);
+ } else {
+ out.println("ERROR");
+ out.println("Unexpected command " + line);
+ out.println("OK");
+ }
+ } catch (Exception e) {
+ System.out.println("TransformListener.run : exception " + e + " processing command " + line);
+ e.printStackTrace();
+ try {
+ socket.close();
+ } catch (IOException e1) {
+ System.out.println("TransformListener.run : exception closing socket " + e1);
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void loadScripts(BufferedReader in, PrintWriter out) 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 (!line.equals("ENDLOAD")) {
+ out.append("ERROR ");
+ out.append("Unexpected end of line reading script " + scriptName + "\n");
+ out.println("OK");
+ out.flush();
+ return;
+ }
+
+ try {
+ retransformer.installScript(scripts, scriptNames);
+ out.println("OK");
+ out.flush();
+ } catch (Exception e) {
+ out.append("EXCEPTION ");
+ out.append(e.toString());
+ out.append('\n');
+ e.printStackTrace(out);
+ out.println("OK");
+ out.flush();
+ }
+ }
+
+ private void listScripts(BufferedReader in, PrintWriter out) throws Exception
+ {
+ retransformer.listScripts(out);
+ out.println("OK");
+ out.flush();
+ }
+}
\ No newline at end of file
Modified: labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Transformer.java
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Transformer.java 2009-09-04 14:54:01 UTC (rev 29186)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/Transformer.java 2009-09-04 16:00:06 UTC (rev 29187)
@@ -58,12 +58,14 @@
*
* @param inst the instrumentation object used to interface to the JVM
*/
- public Transformer(Instrumentation inst, List<String> scriptPaths, List<String> scriptTexts)
+ public Transformer(Instrumentation inst, List<String> scriptPaths, List<String> scriptTexts, boolean isRedefine)
throws Exception
{
theTransformer = this;
this.inst = inst;
+ this.isRedefine = isRedefine;
targetToScriptMap = new HashMap<String, List<RuleScript>>();
+ nameToScriptMap = new HashMap<String, RuleScript>();
Iterator<String> iter = scriptTexts.iterator();
int scriptIdx = 0;
@@ -77,10 +79,10 @@
}
}
- private List<RuleScript> processScripts(String scriptText, String scriptFile) throws Exception
+ protected List<RuleScript> processScripts(String scriptText, String scriptFile) throws Exception
{
List<RuleScript> ruleScripts = new LinkedList<RuleScript>();
-
+
if (scriptText != null) {
// split rules into separate lines
String[] lines = scriptText.split("\n");
@@ -167,8 +169,24 @@
return ruleScripts;
}
- private void indexScriptByTarget(RuleScript ruleScript)
+ protected void indexScriptByName(RuleScript ruleScript) throws Exception
{
+ String name = ruleScript.getName();
+
+ synchronized (nameToScriptMap) {
+ RuleScript old = nameToScriptMap.get(name);
+ if (old != null) {
+ throw new Exception("duplicated rule name " + name +
+ " at ruleScript " + old.getFile() + " line " + old.getLine() +
+ " and ruleScript " + ruleScript.getFile() + " line " + ruleScript.getLine());
+ }
+
+ nameToScriptMap.put(name, ruleScript);
+ }
+ }
+
+ protected void indexScriptByTarget(RuleScript ruleScript)
+ {
String targetClass = ruleScript.getTargetClass();
List<RuleScript> ruleScripts;
@@ -184,7 +202,7 @@
ruleScripts.add(ruleScript);
}
- private void dumpScript(RuleScript ruleScript)
+ protected void dumpScript(RuleScript ruleScript)
{
String file = ruleScript.getFile();
int line = ruleScript.getLine();
@@ -204,13 +222,14 @@
private void addScript(RuleScript ruleScript) throws Exception
{
+ indexScriptByName(ruleScript);
indexScriptByTarget(ruleScript);
if (isVerbose()) {
dumpScript(ruleScript);
}
}
-
+
/**
* The implementation of this method may transform the supplied class file and
* return a new replacement class file.
@@ -284,7 +303,7 @@
}
// TODO-- reconsider this as it is a bit dodgy as far as security is concerned
-
+
if (loader == null) {
loader = ClassLoader.getSystemClassLoader();
}
@@ -496,7 +515,7 @@
* @param className
* @return true if a class is located in the byteman package otherwise return false
*/
- private boolean isBytemanClass(String className)
+ protected boolean isBytemanClass(String className)
{
return className.startsWith(BYTEMAN_PACKAGE_PREFIX) && !className.startsWith(BYTEMAN_TEST_PACKAGE_PREFIX);
}
@@ -551,7 +570,7 @@
* @param className
* @return true if a class is a potential candidate for insertion of event notifications otherwise return false
*/
- private boolean isTransformable(String className)
+ protected boolean isTransformable(String className)
{
/*
* ok, we are now going to allow any code to be transformed so long as it is not in the java.lang package
@@ -566,16 +585,28 @@
/**
* the instrumentation interface to the JVM
*/
- private final Instrumentation inst;
+ protected final Instrumentation inst;
/**
- * a mapping from class names which appear in rule targets to a script object holding the
+ * true if the instrumentor allows redefinition
+ */
+ protected boolean isRedefine;
+
+ /**
+ * a mapping from target class names which appear in rules to a script object holding the
* rule details
*/
- private final HashMap<String, List<RuleScript>> targetToScriptMap;
+ protected final HashMap<String, List<RuleScript>> targetToScriptMap;
/**
+ * a mapping from rule names which appear in rules to a script object holding the
+ * rule details
+ */
+
+ protected final HashMap<String, RuleScript> nameToScriptMap;
+
+ /**
* switch to control verbose output during rule processing
*/
private final static boolean verbose = (System.getProperty(VERBOSE) != null);
Added: labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/submit/Submit.java
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/submit/Submit.java (rev 0)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/submit/Submit.java 2009-09-04 16:00:06 UTC (rev 29187)
@@ -0,0 +1,186 @@
+package org.jboss.byteman.agent.submit;
+
+import org.jboss.byteman.agent.TransformListener;
+
+import java.io.*;
+import java.net.Socket;
+
+/**
+ * Provide a main routine for an app which submits a script to a byteman agent for installation in the JVM runtime
+ * or, with no arguments, lists all currently installed scripts
+ */
+public class Submit
+{
+ /**
+ * main routine which submits a script to the byteman agent
+ * @param args command line arguments specifying the script file(s) to be submitted and, optionally,
+ * the byteman agent listener port to use.
+ * Submit [- port] [scriptfile . . .]
+ */
+ public static void main(String[] args)
+ {
+ int port = TransformListener.DEFAULT_PORT;
+ int startIdx = 0;
+ int maxIdx = args.length;
+
+ if (maxIdx >= 2 && args[0].equals("-p")) {
+ try {
+ port = Integer.valueOf(args[1]);
+ } catch (NumberFormatException e) {
+ System.out.println("Submit : invalid port " + args[1]);
+ System.exit(1);
+ }
+ if (port <= 0) {
+ System.out.println("Submit : invalid port " + args[1]);
+ System.exit(1);
+ }
+ startIdx = 2;
+ }
+ if (startIdx < maxIdx && args[startIdx].startsWith("-")) {
+ usage(1);
+ }
+
+ for (int i = startIdx; i < maxIdx; i++) {
+ File file = new File(args[i]);
+ if (!file.isFile() || !file.canRead()) {
+ System.out.println("Submit : invalid file " + args[i]);
+ System.exit(1);
+ }
+ }
+
+ // ok try to open the socket
+ Socket socket = null;
+
+ try {
+ socket = new Socket("localhost", port);
+ } catch (IOException e) {
+ System.out.println("Submit : error opening socket " + e);
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ InputStream is = null;
+ try {
+ is = socket.getInputStream();
+ } catch (IOException e) {
+ // oops. cannot handle this
+ System.out.println("Submit : error opening socket input stream " + e);
+ e.printStackTrace();
+ try {
+ socket.close();
+ } catch (IOException e1) {
+ System.out.println("Submit : exception closing socket after failed input stream open" + e1);
+ e1.printStackTrace();
+ }
+ System.exit(1);
+ }
+
+ OutputStream os = null;
+ try {
+ os = socket.getOutputStream();
+ } catch (IOException e) {
+ // oops. cannot handle this
+ System.out.println("Submit : error opening socket output stream " + e);
+ e.printStackTrace();
+ try {
+ socket.close();
+ } catch (IOException e1) {
+ System.out.println("Submit : exception closing socket after failed output stream open" + e1);
+ e1.printStackTrace();
+ }
+ System.exit(1);
+ }
+
+ PrintWriter out = null;
+
+ BufferedReader in = new BufferedReader(new InputStreamReader(is));
+ out = new PrintWriter(new OutputStreamWriter(os));
+ final int READ_BUFFER_LENGTH = 1024;
+ char[] readBuffer = new char[READ_BUFFER_LENGTH];
+
+ if (startIdx == maxIdx) {
+ // no args means list all current scripts;
+ // !!! TODO -- invoke list command
+ out.println("LIST");
+ out.flush();
+ try {
+ String line = in.readLine();
+ while (line != null && !line.equals("OK"))
+ {
+ System.out.println(line);
+ line = in.readLine();
+ }
+ socket.close();
+ } catch (IOException e) {
+ System.out.println("Submit : error reading from socket " + e);
+ e.printStackTrace();
+ try {
+ socket.close();
+ } catch (IOException e1) {
+ System.out.println("Submit : exception closing socket after failed read " + e1);
+ e1.printStackTrace();
+ }
+ System.exit(1);
+ }
+ } else {
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append("LOAD\n");
+ for (int i = startIdx; i < maxIdx; i++) {
+ String name = args[i];
+ stringBuffer.append("SCRIPT " + name + "\n");
+ try {
+ FileInputStream fis = new FileInputStream(args[i]);
+ InputStreamReader reader = new InputStreamReader(fis);
+ int read = reader.read(readBuffer);
+ while (read > 0) {
+ stringBuffer.append(readBuffer, 0, read);
+ read = reader.read(readBuffer);
+ }
+ stringBuffer.append("ENDSCRIPT\n");
+ } catch (IOException e) {
+ System.out.println("Submit : error reading from file " + args[i] + " " + e);
+ e.printStackTrace();
+ try {
+ socket.close();
+ } catch (IOException e1) {
+ System.out.println("Submit : exception closing socket after failed file read " + e1);
+ e1.printStackTrace();
+ }
+
+ System.exit(1);
+ }
+ }
+ stringBuffer.append("ENDLOAD\n");
+
+ out.append(stringBuffer);
+ out.flush();
+
+ try {
+ String line = in.readLine();
+ while (line!= null & !line.equals("OK")) {
+ System.out.println(line);
+ line = in.readLine();
+ }
+ } catch (IOException e) {
+ System.out.println("Submit : error reading listener reply "+ e);
+ e.printStackTrace();
+ try {
+ socket.close();
+ } catch (IOException e1) {
+ System.out.println("Submit : exception closing socket after failed listener read " + e1);
+ e1.printStackTrace();
+ }
+
+ System.exit(1);
+ }
+ }
+ }
+
+ public static void usage(int exitCode)
+ {
+ System.out.println("usage : Submit [-p port] [scriptfile . . .]");
+ System.out.println(" -p specifies listener port");
+ System.out.println(" no args means list installed scripts");
+ System.exit(exitCode);
+ }
+}
More information about the jboss-svn-commits
mailing list