/******************************************************************************* * Copyright (c) 2006 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Andy Clement - initial implementation *******************************************************************************/ package org.aspectj.systemtest.ajc152; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.PrintStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import junit.framework.Test; import org.aspectj.apache.bcel.classfile.JavaClass; import org.aspectj.apache.bcel.classfile.Method; import org.aspectj.asm.AsmManager; import org.aspectj.asm.IProgramElement; import org.aspectj.asm.IRelationship; import org.aspectj.testing.XMLBasedAjcTestCase; import org.aspectj.testing.util.TestUtil; import org.aspectj.testing.util.TestUtil.LineStream; import org.aspectj.weaver.ReferenceType; import org.aspectj.weaver.ResolvedType; import org.aspectj.weaver.World; import org.aspectj.weaver.bcel.BcelObjectType; import org.aspectj.weaver.bcel.BcelWorld; import org.aspectj.weaver.bcel.LazyClassGen; import org.aspectj.weaver.bcel.LazyMethodGen; /** * Method transformation, example: public synchronized void m(); Code: Stack=2, Locals=1, Args_size=1 0: getstatic #2; //Field java/lang/System.err:Ljava/io/PrintStream; 3: ldc #3; //String hello 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: getstatic #2; //Field java/lang/System.err:Ljava/io/PrintStream; 11: ldc #5; //String world 13: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 16: return LineNumberTable: line 4: 0 line 5: 8 line 6: 16 public void m2(); Code: Stack=2, Locals=3, Args_size=1 0: aload_0 1: dup 2: astore_1 3: monitorenter 4: getstatic #2; //Field java/lang/System.err:Ljava/io/PrintStream; 7: ldc #3; //String hello 9: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 12: getstatic #2; //Field java/lang/System.err:Ljava/io/PrintStream; 15: ldc #5; //String world 17: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 20: aload_1 21: monitorexit 22: goto 30 25: astore_2 26: aload_1 27: monitorexit 28: aload_2 29: athrow 30: return Exception table: from to target type 4 22 25 any 25 28 25 any */ public class SynchronizationTransformTests extends XMLBasedAjcTestCase { private static boolean regenerate; static { regenerate = false; } private World world; public void testInvestigatingTransforming() { runTest("investigation"); checkMethod("Investigation","b"); // similar output to One.b checkMethod("Investigation","c"); checkMethod("Investigation","d"); checkMethod("Investigation","e"); } public void testTransform1() { runTest("One"); checkMethod("One","b"); checkMethod("One","c"); checkMethod("One","e"); } // before() on execution jp public void testTransform2() { runTest("Two"); checkMethod("C","ma"); } // after() returning/after() throwing on execution jp // after() returning -> make all returns go through the same exit point and make // it call the advice // after() throwing -> add a catch block that calls the advice public void testTransform3() { runTest("Three"); checkMethod("C","m3"); checkMethod("C","m32"); checkMethod("C","m33"); // like m() but synchronized block checkMethod("C","m34"); // like m2() but synchronized block } // like testTransform3() but pointcuts explicitly specify synchronized public void testTransform4() { runTest("Four"); checkMethod("C","m"); checkMethod("C","m2"); } // Java5 variant public void testStaticSynchronizedMethodTransformJava5() { runTest("Five - Java5"); checkMethod("C","b"); } // < Java5 variant public void testStaticSynchronizedMethodTransformPreJava5() { runTest("Six - preJava5"); checkMethod("C","bbb"); } public void testLockPcdOnTransformedNonStaticMethod() { runTest("lock pcd on transformed non-static method"); } public void testUnlockPcdOnTransformedNonStaticMethod() { runTest("unlock pcd on transformed non-static method"); } public void testLockPcdOnTransformedStaticMethod() { runTest("lock pcd on transformed static method - J5"); } public void testUnlockPcdOnTransformedStaticMethod() { runTest("unlock pcd on transformed static method - J5"); } public void testLockPcdOnTransformedStaticMethodPreJ5() { runTest("lock pcd on transformed static method - preJ5"); } public void testUnlockPcdOnTransformedStaticMethodPreJ5() { runTest("unlock pcd on transformed static method - preJ5"); } public void testJoinpointsEnabledButNoLock() { runTest("joinpoints enabled but no lock"); } public void testTransformWithLTW() { runTest("transform with LTW"); } public void testTransformStaticMethodPreJava5() { runTest("transform static method - preJ5"); } public void testTransformStaticMethodPreJava5_2() { runTest("transform static method - packages - preJ5"); } // more complex code sequences... public void testOtherTargeters() { runTest("other targeters"); } // --- infrastructure below private void checkMethod(String typename,String methodname) { LazyMethodGen m = getMethod(typename,methodname); File expectedF = new File(".."+File.separator+"tests"+File.separator+"features152"+File.separator+"synchronization"+File.separator+ "transformed"+File.separator+"expected"+File.separator+ typename+"."+methodname+".txt"); if (regenerate) { saveMethod(expectedF, m); } else { compareMethod(expectedF, m); } } private LazyMethodGen getMethod(String typename,String methodname) { BcelObjectType type = getBcelObjectFor(typename); LazyClassGen lcg = type.getLazyClassGen(); List /*LazyMethodGen*/ methods = lcg.getMethodGens(); for (Iterator iter = methods.iterator(); iter.hasNext();) { LazyMethodGen element = (LazyMethodGen) iter.next(); if (element.getName().equals(methodname)) { return element; } } return null; } private BcelObjectType getBcelObjectFor(String clazzname) { ensureWorldSetup(); ResolvedType rt = world.resolve(clazzname); if (rt==null) fail("Couldn't find class "+clazzname); ReferenceType rtt = (ReferenceType)rt; BcelObjectType bot = (BcelObjectType)rtt.getDelegate(); return bot; } private void ensureWorldSetup() { if (world == null) { world = new BcelWorld( getSandboxDirectory()+File.pathSeparator+ System.getProperty("java.class.path")); world.setFastDelegateSupport(false); } } protected Method getMethod(JavaClass cl,String methodname) { Method[] methods = cl.getMethods(); for (int i = 0; i < methods.length; i++) { Method m = methods[i]; if (m.getName().equals(methodname)) { return m; } } return null; } public void dump(String title,String[] strs) { System.err.println(title); for (int i = 0; i < strs.length; i++) { System.err.println(i+") "+strs[i]); } } private void compareMethod(File f,LazyMethodGen m) { BufferedReader fr; if (!f.exists()) { fail("Can't find expected output file "+f); } try { // Load the file in fr = new BufferedReader(new FileReader(f)); String line = null; List originalFileContents = new ArrayList(); while ((line=fr.readLine())!=null) originalFileContents.add(line); String[] fileContents = (String[])originalFileContents.toArray(new String[]{}); LineStream ls = new TestUtil.LineStream(); m.print(ls,null); String[] lines = ls.getLines(); for (int i = 0; i < lines.length; i++) { String existingLine = lines[i]; if (fileContents[i].indexOf("MethodDeclarationLineNumber")==-1 && !fileContents[i].equals(existingLine)) { dump("File contents:",fileContents); dump("Actual:",lines); fail("\nDifference in method "+m.getName()+" on line "+i+" between the expected:\n"+fileContents[i]+ "\nand the found:\n"+existingLine); } } } catch (Exception e) { fail("Unexpected exception saving weaving messages:"+e); } } private String stringify(List l) { StringBuffer result = new StringBuffer(); for (Iterator iter = l.iterator(); iter.hasNext();) { String str = (String) iter.next(); result.append(str);result.append("\n"); } return result.toString(); } private void saveMethod(File f,LazyMethodGen m) { System.out.println("Saving method into "+f.getName()); try { m.print(new PrintStream(new FileOutputStream(f)),null); } catch (FileNotFoundException e) { e.printStackTrace(); fail("Couldn't store the method in file "+f); } } // --- helpers // Half finished - could check there is only one relationship for unlock() rather than two - but // that seems to be the case anyway (peculiar...) private void checkModel1() { // Verifies only one unlock relationship, not two IProgramElement unlockNode = AsmManager.getDefault().getHierarchy().findElementForLabel(AsmManager.getDefault().getHierarchy().getRoot(), IProgramElement.Kind.CODE,"unlock(void java.lang.Object.(java.lang.Object))"); assertTrue("Couldn't find the unlock node",unlockNode!=null); List l = AsmManager.getDefault().getRelationshipMap().get(unlockNode); assertTrue("should be one entry :"+l,l!=null && l.size()==1); IRelationship ir = (IRelationship)l.get(0); System.err.println(ir); List targs = ir.getTargets(); System.err.println(targs.size()); System.err.println(targs.get(0)); } // --- public static Test suite() { return XMLBasedAjcTestCase.loadSuite(SynchronizationTransformTests.class); } protected File getSpecFile() { return new File("../tests/src/org/aspectj/systemtest/ajc152/synchronization.xml"); } public void tearDown() { world = null; } }