You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BcelWeaver.java 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.bcel;
  13. import java.io.ByteArrayInputStream;
  14. import java.io.File;
  15. import java.io.FileFilter;
  16. import java.io.FileInputStream;
  17. import java.io.FileNotFoundException;
  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.io.OutputStream;
  21. import java.util.ArrayList;
  22. import java.util.Collection;
  23. import java.util.Collections;
  24. import java.util.Comparator;
  25. import java.util.Enumeration;
  26. import java.util.HashSet;
  27. import java.util.Iterator;
  28. import java.util.List;
  29. import java.util.Set;
  30. import java.util.jar.Attributes;
  31. import java.util.jar.Attributes.Name;
  32. import java.util.jar.JarEntry;
  33. import java.util.jar.JarFile;
  34. import java.util.jar.JarInputStream;
  35. import java.util.jar.Manifest;
  36. import java.util.zip.ZipEntry;
  37. import java.util.zip.ZipInputStream;
  38. import java.util.zip.ZipOutputStream;
  39. import org.apache.bcel.classfile.ClassParser;
  40. import org.apache.bcel.classfile.JavaClass;
  41. import org.aspectj.bridge.IMessage;
  42. import org.aspectj.bridge.IProgressListener;
  43. import org.aspectj.bridge.Message;
  44. import org.aspectj.bridge.SourceLocation;
  45. import org.aspectj.util.FileUtil;
  46. import org.aspectj.weaver.ConcreteTypeMunger;
  47. import org.aspectj.weaver.CrosscuttingMembersSet;
  48. import org.aspectj.weaver.IClassFileProvider;
  49. import org.aspectj.weaver.IWeaveRequestor;
  50. import org.aspectj.weaver.IWeaver;
  51. import org.aspectj.weaver.NewParentTypeMunger;
  52. import org.aspectj.weaver.ResolvedTypeMunger;
  53. import org.aspectj.weaver.ResolvedTypeX;
  54. import org.aspectj.weaver.ShadowMunger;
  55. import org.aspectj.weaver.TypeX;
  56. import org.aspectj.weaver.WeaverMessages;
  57. import org.aspectj.weaver.WeaverStateInfo;
  58. import org.aspectj.weaver.patterns.DeclareParents;
  59. import org.aspectj.weaver.patterns.FastMatchInfo;
  60. public class BcelWeaver implements IWeaver {
  61. private BcelWorld world;
  62. private CrosscuttingMembersSet xcutSet;
  63. private IProgressListener progressListener = null;
  64. private double progressMade;
  65. private double progressPerClassFile;
  66. private boolean inReweavableMode = false;
  67. public BcelWeaver(BcelWorld world) {
  68. super();
  69. this.world = world;
  70. this.xcutSet = world.getCrosscuttingMembersSet();
  71. }
  72. public BcelWeaver() {
  73. this(new BcelWorld());
  74. }
  75. // ---- fields
  76. // private Map sourceJavaClasses = new HashMap(); /* String -> UnwovenClassFile */
  77. private List addedClasses = new ArrayList(); /* List<UnovenClassFile> */
  78. private List deletedTypenames = new ArrayList(); /* List<String> */
  79. // private Map resources = new HashMap(); /* String -> UnwovenClassFile */
  80. private Manifest manifest = null;
  81. private boolean needToReweaveWorld = false;
  82. private List shadowMungerList = null; // setup by prepareForWeave
  83. private List typeMungerList = null; // setup by prepareForWeave
  84. private List declareParentsList = null; // setup by prepareForWeave
  85. private ZipOutputStream zipOutputStream;
  86. // ----
  87. // only called for testing
  88. public void setShadowMungers(List l) {
  89. shadowMungerList = l;
  90. }
  91. public void addLibraryAspect(String aspectName) {
  92. ResolvedTypeX type = world.resolve(aspectName);
  93. //System.out.println("type: " + type + " for " + aspectName);
  94. if (type.isAspect()) {
  95. xcutSet.addOrReplaceAspect(type);
  96. } else {
  97. throw new RuntimeException("unimplemented");
  98. }
  99. }
  100. public void addLibraryJarFile(File inFile) throws IOException {
  101. ZipInputStream inStream = new ZipInputStream(new FileInputStream(inFile)); //??? buffered
  102. List addedAspects = new ArrayList();
  103. while (true) {
  104. ZipEntry entry = inStream.getNextEntry();
  105. if (entry == null) break;
  106. if (entry.isDirectory() || !entry.getName().endsWith(".class")) {
  107. continue;
  108. }
  109. ClassParser parser = new ClassParser(new ByteArrayInputStream(FileUtil.readAsByteArray(inStream)), entry.getName());
  110. JavaClass jc = parser.parse();
  111. inStream.closeEntry();
  112. ResolvedTypeX type = world.addSourceObjectType(jc).getResolvedTypeX();
  113. if (type.isAspect()) {
  114. addedAspects.add(type);
  115. }
  116. }
  117. inStream.close();
  118. for (Iterator i = addedAspects.iterator(); i.hasNext();) {
  119. ResolvedTypeX aspectX = (ResolvedTypeX) i.next();
  120. xcutSet.addOrReplaceAspect(aspectX);
  121. }
  122. }
  123. // // The ANT copy task should be used to copy resources across.
  124. // private final static boolean CopyResourcesFromInpathDirectoriesToOutput=false;
  125. private Set alreadyConfirmedReweavableState;
  126. /**
  127. * Add any .class files in the directory to the outdir. Anything other than .class files in
  128. * the directory (or its subdirectories) are considered resources and are also copied.
  129. *
  130. */
  131. public List addDirectoryContents(File inFile,File outDir) throws IOException {
  132. List addedClassFiles = new ArrayList();
  133. // Get a list of all files (i.e. everything that isnt a directory)
  134. File[] files = FileUtil.listFiles(inFile,new FileFilter() {
  135. public boolean accept(File f) {
  136. boolean accept = !f.isDirectory();
  137. return accept;
  138. }
  139. });
  140. // For each file, add it either as a real .class file or as a resource
  141. for (int i = 0; i < files.length; i++) {
  142. addedClassFiles.add(addClassFile(files[i],inFile,outDir));
  143. }
  144. return addedClassFiles;
  145. }
  146. /** Adds all class files in the jar
  147. */
  148. public List addJarFile(File inFile, File outDir, boolean canBeDirectory){
  149. // System.err.println("? addJarFile(" + inFile + ", " + outDir + ")");
  150. List addedClassFiles = new ArrayList();
  151. needToReweaveWorld = true;
  152. JarFile inJar = null;
  153. try {
  154. // Is this a directory we are looking at?
  155. if (inFile.isDirectory() && canBeDirectory) {
  156. addedClassFiles.addAll(addDirectoryContents(inFile,outDir));
  157. } else {
  158. inJar = new JarFile(inFile);
  159. addManifest(inJar.getManifest());
  160. Enumeration entries = inJar.entries();
  161. while (entries.hasMoreElements()) {
  162. JarEntry entry = (JarEntry)entries.nextElement();
  163. InputStream inStream = inJar.getInputStream(entry);
  164. byte[] bytes = FileUtil.readAsByteArray(inStream);
  165. String filename = entry.getName();
  166. // System.out.println("? addJarFile() filename='" + filename + "'");
  167. UnwovenClassFile classFile = new UnwovenClassFile(new File(outDir, filename).getAbsolutePath(), bytes);
  168. if (filename.endsWith(".class")) {
  169. this.addClassFile(classFile);
  170. addedClassFiles.add(classFile);
  171. }
  172. // else if (!entry.isDirectory()) {
  173. //
  174. // /* bug-44190 Copy meta-data */
  175. // addResource(filename,classFile);
  176. // }
  177. inStream.close();
  178. }
  179. inJar.close();
  180. }
  181. } catch (FileNotFoundException ex) {
  182. IMessage message = new Message(
  183. "Could not find input jar file " + inFile.getPath() + ", ignoring",
  184. new SourceLocation(inFile,0),
  185. false);
  186. world.getMessageHandler().handleMessage(message);
  187. } catch (IOException ex) {
  188. IMessage message = new Message(
  189. "Could not read input jar file " + inFile.getPath() + "(" + ex.getMessage() + ")",
  190. new SourceLocation(inFile,0),
  191. true);
  192. world.getMessageHandler().handleMessage(message);
  193. } finally {
  194. if (inJar != null) {
  195. try {inJar.close();}
  196. catch (IOException ex) {
  197. IMessage message = new Message(
  198. "Could not close input jar file " + inFile.getPath() + "(" + ex.getMessage() + ")",
  199. new SourceLocation(inFile,0),
  200. true);
  201. world.getMessageHandler().handleMessage(message);
  202. }
  203. }
  204. }
  205. return addedClassFiles;
  206. }
  207. // public void addResource(String name, File inPath, File outDir) throws IOException {
  208. //
  209. // /* Eliminate CVS files. Relative paths use "/" */
  210. // if (!name.startsWith("CVS/") && (-1 == name.indexOf("/CVS/")) && !name.endsWith("/CVS")) {
  211. //// System.err.println("? addResource('" + name + "')");
  212. //// BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(inPath));
  213. //// byte[] bytes = new byte[(int)inPath.length()];
  214. //// inStream.read(bytes);
  215. //// inStream.close();
  216. // byte[] bytes = FileUtil.readAsByteArray(inPath);
  217. // UnwovenClassFile resourceFile = new UnwovenClassFile(new File(outDir, name).getAbsolutePath(), bytes);
  218. // addResource(name,resourceFile);
  219. // }
  220. // }
  221. public boolean needToReweaveWorld() {
  222. return needToReweaveWorld;
  223. }
  224. /** Should be addOrReplace
  225. */
  226. public void addClassFile(UnwovenClassFile classFile) {
  227. addedClasses.add(classFile);
  228. // if (null != sourceJavaClasses.put(classFile.getClassName(), classFile)) {
  229. //// throw new RuntimeException(classFile.getClassName());
  230. // }
  231. world.addSourceObjectType(classFile.getJavaClass());
  232. }
  233. public UnwovenClassFile addClassFile(File classFile, File inPathDir, File outDir) throws IOException {
  234. FileInputStream fis = new FileInputStream(classFile);
  235. byte[] bytes = FileUtil.readAsByteArray(fis);
  236. // String relativePath = files[i].getPath();
  237. // ASSERT: files[i].getAbsolutePath().startsWith(inFile.getAbsolutePath()
  238. // or we are in trouble...
  239. String filename = classFile.getAbsolutePath().substring(
  240. inPathDir.getAbsolutePath().length()+1);
  241. UnwovenClassFile ucf = new UnwovenClassFile(new File(outDir,filename).getAbsolutePath(),bytes);
  242. if (filename.endsWith(".class")) {
  243. // System.err.println("BCELWeaver: processing class from input directory "+classFile);
  244. this.addClassFile(ucf);
  245. }
  246. fis.close();
  247. return ucf;
  248. }
  249. public void deleteClassFile(String typename) {
  250. deletedTypenames.add(typename);
  251. // sourceJavaClasses.remove(typename);
  252. world.deleteSourceObjectType(TypeX.forName(typename));
  253. }
  254. // public void addResource (String name, UnwovenClassFile resourceFile) {
  255. // /* bug-44190 Change error to warning and copy first resource */
  256. // if (!resources.containsKey(name)) {
  257. // resources.put(name, resourceFile);
  258. // }
  259. // else {
  260. // world.showMessage(IMessage.WARNING, "duplicate resource: '" + name + "'",
  261. // null, null);
  262. // }
  263. // }
  264. // ---- weave preparation
  265. public void prepareForWeave() {
  266. needToReweaveWorld = false;
  267. // update mungers
  268. for (Iterator i = addedClasses.iterator(); i.hasNext(); ) {
  269. UnwovenClassFile jc = (UnwovenClassFile)i.next();
  270. String name = jc.getClassName();
  271. ResolvedTypeX type = world.resolve(name);
  272. //System.err.println("added: " + type + " aspect? " + type.isAspect());
  273. if (type.isAspect()) {
  274. needToReweaveWorld |= xcutSet.addOrReplaceAspect(type);
  275. }
  276. }
  277. for (Iterator i = deletedTypenames.iterator(); i.hasNext(); ) {
  278. String name = (String)i.next();
  279. if (xcutSet.deleteAspect(TypeX.forName(name))) needToReweaveWorld = true;
  280. }
  281. shadowMungerList = xcutSet.getShadowMungers();
  282. typeMungerList = xcutSet.getTypeMungers();
  283. declareParentsList = xcutSet.getDeclareParents();
  284. //XXX this gets us a stable (but completely meaningless) order
  285. Collections.sort(
  286. shadowMungerList,
  287. new Comparator() {
  288. public int compare(Object o1, Object o2) {
  289. return o1.toString().compareTo(o2.toString());
  290. }
  291. });
  292. }
  293. // public void dumpUnwoven(File file) throws IOException {
  294. // BufferedOutputStream os = FileUtil.makeOutputStream(file);
  295. // this.zipOutputStream = new ZipOutputStream(os);
  296. // dumpUnwoven();
  297. // /* BUG 40943*/
  298. // dumpResourcesToOutJar();
  299. // zipOutputStream.close(); //this flushes and closes the acutal file
  300. // }
  301. //
  302. //
  303. // public void dumpUnwoven() throws IOException {
  304. // Collection filesToDump = new HashSet(sourceJavaClasses.values());
  305. // for (Iterator i = filesToDump.iterator(); i.hasNext(); ) {
  306. // UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  307. // dumpUnchanged(classFile);
  308. // }
  309. // }
  310. // public void dumpResourcesToOutPath() throws IOException {
  311. //// System.err.println("? dumpResourcesToOutPath() resources=" + resources.keySet());
  312. // Iterator i = resources.keySet().iterator();
  313. // while (i.hasNext()) {
  314. // UnwovenClassFile res = (UnwovenClassFile)resources.get(i.next());
  315. // dumpUnchanged(res);
  316. // }
  317. // //resources = new HashMap();
  318. // }
  319. //
  320. /* BUG #40943 */
  321. // public void dumpResourcesToOutJar() throws IOException {
  322. //// System.err.println("? dumpResourcesToOutJar() resources=" + resources.keySet());
  323. // Iterator i = resources.keySet().iterator();
  324. // while (i.hasNext()) {
  325. // String name = (String)i.next();
  326. // UnwovenClassFile res = (UnwovenClassFile)resources.get(name);
  327. // writeZipEntry(name,res.getBytes());
  328. // }
  329. // resources = new HashMap();
  330. // }
  331. //
  332. // // halfway house for when the jar is managed outside of the weaver, but the resources
  333. // // to be copied are known in the weaver.
  334. // public void dumpResourcesToOutJar(ZipOutputStream zos) throws IOException {
  335. // this.zipOutputStream = zos;
  336. // dumpResourcesToOutJar();
  337. // }
  338. public void addManifest (Manifest newManifest) {
  339. // System.out.println("? addManifest() newManifest=" + newManifest);
  340. if (manifest == null) {
  341. manifest = newManifest;
  342. }
  343. }
  344. public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
  345. private static final String WEAVER_MANIFEST_VERSION = "1.0";
  346. private static final Attributes.Name CREATED_BY = new Name("Created-By");
  347. private static final String WEAVER_CREATED_BY = "AspectJ Compiler";
  348. public Manifest getManifest (boolean shouldCreate) {
  349. if (manifest == null && shouldCreate) {
  350. manifest = new Manifest();
  351. Attributes attributes = manifest.getMainAttributes();
  352. attributes.put(Name.MANIFEST_VERSION,WEAVER_MANIFEST_VERSION);
  353. attributes.put(CREATED_BY,WEAVER_CREATED_BY);
  354. }
  355. return manifest;
  356. }
  357. // ---- weaving
  358. // Used by some test cases only...
  359. public Collection weave(File file) throws IOException {
  360. OutputStream os = FileUtil.makeOutputStream(file);
  361. this.zipOutputStream = new ZipOutputStream(os);
  362. prepareForWeave();
  363. Collection c = weave( new IClassFileProvider() {
  364. public Iterator getClassFileIterator() {
  365. return addedClasses.iterator();
  366. }
  367. public IWeaveRequestor getRequestor() {
  368. return new IWeaveRequestor() {
  369. public void acceptResult(UnwovenClassFile result) {
  370. try {
  371. writeZipEntry(result.filename, result.bytes);
  372. } catch(IOException ex) {}
  373. }
  374. public void processingReweavableState() {}
  375. public void addingTypeMungers() {}
  376. public void weavingAspects() {}
  377. public void weavingClasses() {}
  378. public void weaveCompleted() {}
  379. };
  380. }
  381. });
  382. // /* BUG 40943*/
  383. // dumpResourcesToOutJar();
  384. zipOutputStream.close(); //this flushes and closes the acutal file
  385. return c;
  386. }
  387. // public Collection weave() throws IOException {
  388. // prepareForWeave();
  389. // Collection filesToWeave;
  390. //
  391. // if (needToReweaveWorld) {
  392. // filesToWeave = sourceJavaClasses.values();
  393. // } else {
  394. // filesToWeave = addedClasses;
  395. // }
  396. //
  397. // Collection wovenClassNames = new ArrayList();
  398. // world.showMessage(IMessage.INFO, "might need to weave " + filesToWeave +
  399. // "(world=" + needToReweaveWorld + ")", null, null);
  400. //
  401. //
  402. // //System.err.println("typeMungers: " + typeMungerList);
  403. //
  404. // prepareToProcessReweavableState();
  405. // // clear all state from files we'll be reweaving
  406. // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
  407. // UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  408. // String className = classFile.getClassName();
  409. // BcelObjectType classType = getClassType(className);
  410. // processReweavableStateIfPresent(className, classType);
  411. // }
  412. //
  413. //
  414. //
  415. // //XXX this isn't quite the right place for this...
  416. // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
  417. // UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  418. // String className = classFile.getClassName();
  419. // addTypeMungers(className);
  420. // }
  421. //
  422. // // first weave into aspects
  423. // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
  424. // UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  425. // String className = classFile.getClassName();
  426. // BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
  427. // if (classType.isAspect()) {
  428. // weave(classFile, classType);
  429. // wovenClassNames.add(className);
  430. // }
  431. // }
  432. //
  433. // // then weave into non-aspects
  434. // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
  435. // UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  436. // String className = classFile.getClassName();
  437. // BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
  438. // if (! classType.isAspect()) {
  439. // weave(classFile, classType);
  440. // wovenClassNames.add(className);
  441. // }
  442. // }
  443. //
  444. // if (zipOutputStream != null && !needToReweaveWorld) {
  445. // Collection filesToDump = new HashSet(sourceJavaClasses.values());
  446. // filesToDump.removeAll(filesToWeave);
  447. // for (Iterator i = filesToDump.iterator(); i.hasNext(); ) {
  448. // UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  449. // dumpUnchanged(classFile);
  450. // }
  451. // }
  452. //
  453. // addedClasses = new ArrayList();
  454. // deletedTypenames = new ArrayList();
  455. //
  456. // return wovenClassNames;
  457. // }
  458. // variation of "weave" that sources class files from an external source.
  459. public Collection weave(IClassFileProvider input) throws IOException {
  460. Collection wovenClassNames = new ArrayList();
  461. IWeaveRequestor requestor = input.getRequestor();
  462. requestor.processingReweavableState();
  463. prepareToProcessReweavableState();
  464. // clear all state from files we'll be reweaving
  465. for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
  466. UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  467. String className = classFile.getClassName();
  468. BcelObjectType classType = getClassType(className);
  469. processReweavableStateIfPresent(className, classType);
  470. }
  471. requestor.addingTypeMungers();
  472. //XXX this isn't quite the right place for this...
  473. for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
  474. UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  475. String className = classFile.getClassName();
  476. addTypeMungers(className);
  477. }
  478. requestor.weavingAspects();
  479. // first weave into aspects
  480. for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
  481. UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  482. String className = classFile.getClassName();
  483. BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
  484. if (classType.isAspect()) {
  485. weaveAndNotify(classFile, classType,requestor);
  486. wovenClassNames.add(className);
  487. }
  488. }
  489. requestor.weavingClasses();
  490. // then weave into non-aspects
  491. for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
  492. UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  493. String className = classFile.getClassName();
  494. BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
  495. if (! classType.isAspect()) {
  496. weaveAndNotify(classFile, classType, requestor);
  497. wovenClassNames.add(className);
  498. }
  499. }
  500. addedClasses = new ArrayList();
  501. deletedTypenames = new ArrayList();
  502. requestor.weaveCompleted();
  503. return wovenClassNames;
  504. }
  505. public void prepareToProcessReweavableState() {
  506. if (inReweavableMode)
  507. world.showMessage(IMessage.INFO,
  508. WeaverMessages.format(WeaverMessages.REWEAVABLE_MODE),
  509. null, null);
  510. alreadyConfirmedReweavableState = new HashSet();
  511. }
  512. public void processReweavableStateIfPresent(String className, BcelObjectType classType) {
  513. // If the class is marked reweavable, check any aspects around when it was built are in this world
  514. WeaverStateInfo wsi = classType.getWeaverState();
  515. if (wsi!=null && wsi.isReweavable()) { // Check all necessary types are around!
  516. world.showMessage(IMessage.INFO,
  517. WeaverMessages.format(WeaverMessages.PROCESSING_REWEAVABLE,className,classType.getSourceLocation().getSourceFile()),
  518. null,null);
  519. Set aspectsPreviouslyInWorld = wsi.getAspectsAffectingType();
  520. if (aspectsPreviouslyInWorld!=null) {
  521. for (Iterator iter = aspectsPreviouslyInWorld.iterator(); iter.hasNext();) {
  522. String requiredTypeName = (String) iter.next();
  523. if (!alreadyConfirmedReweavableState.contains(requiredTypeName)) {
  524. ResolvedTypeX rtx = world.resolve(TypeX.forName(requiredTypeName),true);
  525. boolean exists = rtx!=ResolvedTypeX.MISSING;
  526. if (!exists) {
  527. world.showMessage(IMessage.ERROR,
  528. WeaverMessages.format(WeaverMessages.MISSING_REWEAVABLE_TYPE,requiredTypeName,className),
  529. classType.getSourceLocation(), null);
  530. } else {
  531. if (!world.getMessageHandler().isIgnoring(IMessage.INFO))
  532. world.showMessage(IMessage.INFO,
  533. WeaverMessages.format(WeaverMessages.VERIFIED_REWEAVABLE_TYPE,requiredTypeName,rtx.getSourceLocation().getSourceFile()),
  534. null,null);
  535. alreadyConfirmedReweavableState.add(requiredTypeName);
  536. }
  537. }
  538. }
  539. }
  540. classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData()));
  541. } else {
  542. classType.resetState();
  543. }
  544. }
  545. private void weaveAndNotify(UnwovenClassFile classFile, BcelObjectType classType,
  546. IWeaveRequestor requestor) throws IOException {
  547. LazyClassGen clazz = weaveWithoutDump(classFile,classType);
  548. classType.finishedWith();
  549. //clazz is null if the classfile was unchanged by weaving...
  550. if (clazz != null) {
  551. UnwovenClassFile[] newClasses = getClassFilesFor(clazz);
  552. for (int i = 0; i < newClasses.length; i++) {
  553. requestor.acceptResult(newClasses[i]);
  554. }
  555. } else {
  556. requestor.acceptResult(classFile);
  557. }
  558. }
  559. // helper method
  560. public BcelObjectType getClassType(String forClass) {
  561. return BcelWorld.getBcelObjectType(world.resolve(forClass));
  562. }
  563. public void addTypeMungers(String typeName) {
  564. weave(world.resolve(typeName));
  565. }
  566. public UnwovenClassFile[] getClassFilesFor(LazyClassGen clazz) {
  567. List childClasses = clazz.getChildClasses(world);
  568. UnwovenClassFile[] ret = new UnwovenClassFile[1 + childClasses.size()];
  569. ret[0] = new UnwovenClassFile(clazz.getFileName(),clazz.getJavaClass(world).getBytes());
  570. int index = 1;
  571. for (Iterator iter = childClasses.iterator(); iter.hasNext();) {
  572. UnwovenClassFile.ChildClass element = (UnwovenClassFile.ChildClass) iter.next();
  573. UnwovenClassFile childClass = new UnwovenClassFile(clazz.getFileName() + "$" + element.name, element.bytes);
  574. ret[index++] = childClass;
  575. }
  576. return ret;
  577. }
  578. public void weave(ResolvedTypeX onType) {
  579. onType.clearInterTypeMungers();
  580. // need to do any declare parents before the matching below
  581. for (Iterator i = declareParentsList.iterator(); i.hasNext(); ) {
  582. DeclareParents p = (DeclareParents)i.next();
  583. List newParents = p.findMatchingNewParents(onType);
  584. if (!newParents.isEmpty()) {
  585. BcelObjectType classType = BcelWorld.getBcelObjectType(onType);
  586. //System.err.println("need to do declare parents for: " + onType);
  587. for (Iterator j = newParents.iterator(); j.hasNext(); ) {
  588. ResolvedTypeX newParent = (ResolvedTypeX)j.next();
  589. if (newParent.isClass()) {
  590. world.showMessage(IMessage.ERROR,
  591. WeaverMessages.format(WeaverMessages.DECP_BINARY_LIMITATION,onType.getName()),
  592. p.getSourceLocation(), null);
  593. continue;
  594. }
  595. classType.addParent(newParent);
  596. ResolvedTypeMunger newParentMunger = new NewParentTypeMunger(newParent);
  597. onType.addInterTypeMunger(new BcelTypeMunger(newParentMunger, xcutSet.findAspectDeclaringParents(p)));
  598. }
  599. }
  600. }
  601. for (Iterator i = typeMungerList.iterator(); i.hasNext(); ) {
  602. ConcreteTypeMunger m = (ConcreteTypeMunger)i.next();
  603. if (m.matches(onType)) {
  604. onType.addInterTypeMunger(m);
  605. }
  606. }
  607. }
  608. // exposed for ClassLoader dynamic weaving
  609. public LazyClassGen weaveWithoutDump(UnwovenClassFile classFile, BcelObjectType classType) throws IOException {
  610. return weave(classFile, classType, false);
  611. }
  612. // non-private for testing
  613. LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType) throws IOException {
  614. LazyClassGen ret = weave(classFile, classType, true);
  615. if (progressListener != null) {
  616. progressMade += progressPerClassFile;
  617. progressListener.setProgress(progressMade);
  618. progressListener.setText("woven: " + classFile.getFilename());
  619. }
  620. return ret;
  621. }
  622. private LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType, boolean dump) throws IOException {
  623. if (classType.isSynthetic()) {
  624. if (dump) dumpUnchanged(classFile);
  625. return null;
  626. }
  627. // JavaClass javaClass = classType.getJavaClass();
  628. List shadowMungers = fastMatch(shadowMungerList, classType.getResolvedTypeX());
  629. List typeMungers = classType.getResolvedTypeX().getInterTypeMungers();
  630. classType.getResolvedTypeX().checkInterTypeMungers();
  631. LazyClassGen clazz = null;
  632. if (shadowMungers.size() > 0 || typeMungers.size() > 0 || classType.isAspect()) {
  633. clazz = classType.getLazyClassGen();
  634. //System.err.println("got lazy gen: " + clazz + ", " + clazz.getWeaverState());
  635. try {
  636. boolean isChanged = BcelClassWeaver.weave(world, clazz, shadowMungers, typeMungers);
  637. if (isChanged) {
  638. if (dump) dump(classFile, clazz);
  639. return clazz;
  640. }
  641. } catch (RuntimeException re) {
  642. System.err.println("trouble in: ");
  643. //XXXclazz.print(System.err);
  644. throw re;
  645. } catch (Error re) {
  646. System.err.println("trouble in: ");
  647. clazz.print(System.err);
  648. throw re;
  649. }
  650. }
  651. // this is very odd return behavior trying to keep everyone happy
  652. if (dump) {
  653. dumpUnchanged(classFile);
  654. return clazz;
  655. } else {
  656. return null;
  657. }
  658. }
  659. // ---- writing
  660. private void dumpUnchanged(UnwovenClassFile classFile) throws IOException {
  661. if (zipOutputStream != null) {
  662. writeZipEntry(getEntryName(classFile.getJavaClass().getClassName()), classFile.getBytes());
  663. } else {
  664. classFile.writeUnchangedBytes();
  665. }
  666. }
  667. private String getEntryName(String className) {
  668. //XXX what does bcel's getClassName do for inner names
  669. return className.replace('.', '/') + ".class";
  670. }
  671. private void dump(UnwovenClassFile classFile, LazyClassGen clazz) throws IOException {
  672. if (zipOutputStream != null) {
  673. String mainClassName = classFile.getJavaClass().getClassName();
  674. writeZipEntry(getEntryName(mainClassName),
  675. clazz.getJavaClass(world).getBytes());
  676. if (!clazz.getChildClasses(world).isEmpty()) {
  677. for (Iterator i = clazz.getChildClasses(world).iterator(); i.hasNext();) {
  678. UnwovenClassFile.ChildClass c = (UnwovenClassFile.ChildClass) i.next();
  679. writeZipEntry(getEntryName(mainClassName + "$" + c.name), c.bytes);
  680. }
  681. }
  682. } else {
  683. classFile.writeWovenBytes(
  684. clazz.getJavaClass(world).getBytes(),
  685. clazz.getChildClasses(world)
  686. );
  687. }
  688. }
  689. private void writeZipEntry(String name, byte[] bytes) throws IOException {
  690. ZipEntry newEntry = new ZipEntry(name); //??? get compression scheme right
  691. zipOutputStream.putNextEntry(newEntry);
  692. zipOutputStream.write(bytes);
  693. zipOutputStream.closeEntry();
  694. }
  695. private List fastMatch(List list, ResolvedTypeX type) {
  696. if (list == null) return Collections.EMPTY_LIST;
  697. // here we do the coarsest grained fast match with no kind constraints
  698. // this will remove all obvious non-matches and see if we need to do any weaving
  699. FastMatchInfo info = new FastMatchInfo(type, null);
  700. List result = new ArrayList();
  701. Iterator iter = list.iterator();
  702. while (iter.hasNext()) {
  703. ShadowMunger munger = (ShadowMunger)iter.next();
  704. if (munger.getPointcut().fastMatch(info).maybeTrue()) {
  705. result.add(munger);
  706. }
  707. }
  708. return result;
  709. }
  710. public void setProgressListener(IProgressListener listener, double previousProgress, double progressPerClassFile) {
  711. progressListener = listener;
  712. this.progressMade = previousProgress;
  713. this.progressPerClassFile = progressPerClassFile;
  714. }
  715. public void setReweavableMode(boolean mode,boolean compress) {
  716. inReweavableMode = mode;
  717. WeaverStateInfo.setReweavableModeDefaults(mode,compress);
  718. BcelClassWeaver.setReweavableMode(mode,compress);
  719. }
  720. public boolean isReweavable() {
  721. return inReweavableMode;
  722. }
  723. }