/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* 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.
*/
package org.jboss.aop.eclipsesupport;
import org.jboss.aop.AspectManager;
import org.jboss.aop.AspectXmlLoader;
import org.jboss.aop.standalone.AOPTransformer;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.net.URL;
import java.security.ProtectionDomain;
import java.util.Vector;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
/**
* A transformer to weave the main method of the org.eclipse.jdt.internal.junit.runner.RemoteTestRunner, so that we can deploy the correct
* -aop.xml files before the test case class itself is loaded when running within Eclipse
*
* @author <a href="mailto:bill@jboss.org">Bill Burke</a>
* @version $Revision: 44099 $
*/
public class EclipseTestTransformer implements ClassFileTransformer
{
AOPTransformer aopTransformer = new AOPTransformer();
boolean foundRemoteTestRunner;
/**
* The main class when running tests from Eclipse
*/
final static String MAIN_CLASS = "org/eclipse/jdt/internal/junit/runner/RemoteTestRunner";
/**
* If running from within Eclipse with the -javaagent:eclipse-agent.jar switch set, the EclipseTestTransformer weaves the
* org.eclipse.jdt.internal.junit.runner.RemoteTestRunner class to set this system property to the name of the test class
* run.
*/
public final static String CLASSLOADER_DEPLOYED_XML = "jboss.aop.eclipse.test.xml.name";
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException
{
if (!foundRemoteTestRunner && className.equals(MAIN_CLASS))
{
System.out.println("Found class " + className);
return weaveRemoteTestRunner(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
}
return aopTransformer.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
}
private byte[] weaveRemoteTestRunner(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException
{
try
{
AspectManager manager = AspectManager.instance();
ClassPool pool = manager.registerClassLoader(loader);
CtClass remoteTestRunner = pool.get(MAIN_CLASS.replace('/', '.'));
remoteTestRunner.defrost();
CtMethod originalMain = remoteTestRunner.getMethod("main", "([Ljava/lang/String;)V");
System.out.println("-----> Found CtMethod " + (originalMain != null));
CtMethod wrapper = CtNewMethod.copy(originalMain, remoteTestRunner, null);
originalMain.setName("originalMain");
String body =
"{" +
" org.jboss.aop.eclipsesupport.EclipseTestTransformer.recordClassNameAndDeployXml($$);" +
" originalMain($$);" +
"}";
wrapper.setBody(body);
remoteTestRunner.addMethod(wrapper);
remoteTestRunner.debugWriteFile();
return remoteTestRunner.toBytecode();
}
catch (Exception e)
{
// AutoGenerated
System.out.println("====> Exception " + e);
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static void recordClassNameAndDeployXml(String[] args) throws Exception
{
//This code is lifted from RemoteTestRunner
String[] fTestClassNames = null;
for(int i = 0; i < args.length; i++)
{
if(args[i].toLowerCase().equals("-classnames") || args[i].toLowerCase().equals("-classname"))
{
Vector list = new Vector();
for(int j = i + 1; j < args.length; j++)
{
if(args[j].startsWith("-"))
{
break;
}
list.add(args[j]);
}
fTestClassNames = (String[])list.toArray(new String[list.size()]);
}
}
if (fTestClassNames == null || fTestClassNames.length == 0)
{
throw new RuntimeException("No classnames could be found");
}
if (fTestClassNames.length > 1)
{
throw new RuntimeException("Only one class name is supported");
}
deployXmlForEclipse(fTestClassNames[0]);
}
/**
* This will be initiated from the woven RemoteTestRunner classs to deploy the xml for the testcase UNLESS
* the jboss.aop.path system property has been set.
*/
public static void deployXmlForEclipse(String testClass) throws Exception
{
if (System.getProperty("jboss.aop.path") != null)
{
return;
}
//Determine the url of the -aop.xml file depending on test package name
String testName = null;
if (testClass.contains(".regression."))
{
//Handle the regresssion test differently
testName = "regression";
}
else
{
int dot = testClass.lastIndexOf('.');
String packageName = testClass.substring(0, dot);
dot = packageName.lastIndexOf('.');
testName = packageName.substring(dot + 1);
}
testName = "test/" + testName + "/jboss-aop.xml";
URL url = Thread.currentThread().getContextClassLoader().getResource(testName);
if (url != null)
{
System.setProperty(CLASSLOADER_DEPLOYED_XML, testName);
AspectXmlLoader.deployXML(url);
}
}
}