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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  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.ajdt.internal.core.builder;
  13. import java.io.*;
  14. import java.util.*;
  15. import java.util.jar.*;
  16. import java.util.zip.ZipEntry;
  17. import org.aspectj.ajdt.internal.compiler.AjCompilerAdapter;
  18. import org.aspectj.ajdt.internal.compiler.IBinarySourceProvider;
  19. import org.aspectj.ajdt.internal.compiler.IIntermediateResultsRequestor;
  20. import org.aspectj.ajdt.internal.compiler.IOutputClassFileNameProvider;
  21. import org.aspectj.ajdt.internal.compiler.InterimCompilationResult;
  22. import org.aspectj.ajdt.internal.compiler.lookup.*;
  23. import org.aspectj.ajdt.internal.compiler.problem.AjProblemReporter;
  24. import org.aspectj.asm.*;
  25. //import org.aspectj.asm.internal.*;
  26. import org.aspectj.asm.internal.ProgramElement;
  27. import org.aspectj.bridge.*;
  28. import org.aspectj.util.FileUtil;
  29. import org.aspectj.weaver.Dump;
  30. import org.aspectj.weaver.World;
  31. import org.aspectj.weaver.bcel.*;
  32. import org.eclipse.core.runtime.OperationCanceledException;
  33. import org.eclipse.jdt.core.compiler.*;
  34. import org.eclipse.jdt.internal.compiler.*;
  35. import org.eclipse.jdt.internal.compiler.batch.*;
  36. import org.eclipse.jdt.internal.compiler.batch.FileSystem;
  37. import org.eclipse.jdt.internal.compiler.env.*;
  38. import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
  39. import org.eclipse.jdt.internal.compiler.parser.Parser;
  40. import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
  41. import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
  42. //import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
  43. public class AjBuildManager implements IOutputClassFileNameProvider,IBinarySourceProvider,ICompilerAdapterFactory {
  44. private static final String CANT_WRITE_RESULT = "unable to write compilation result";
  45. private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
  46. static final boolean COPY_INPATH_DIR_RESOURCES = false;
  47. static final boolean FAIL_IF_RUNTIME_NOT_FOUND = false;
  48. private static final FileFilter binarySourceFilter =
  49. new FileFilter() {
  50. public boolean accept(File f) {
  51. return f.getName().endsWith(".class");
  52. }};
  53. /**
  54. * This builder is static so that it can be subclassed and reset. However, note
  55. * that there is only one builder present, so if two extendsion reset it, only
  56. * the latter will get used.
  57. */
  58. private static AsmHierarchyBuilder asmHierarchyBuilder = new AsmHierarchyBuilder();
  59. private IProgressListener progressListener = null;
  60. private int compiledCount;
  61. private int sourceFileCount;
  62. private JarOutputStream zos;
  63. private boolean batchCompile = true;
  64. private INameEnvironment environment;
  65. private Map /* String -> List<UCF>*/ binarySourcesForTheNextCompile = new HashMap();
  66. private IHierarchy structureModel;
  67. public AjBuildConfig buildConfig;
  68. AjState state = new AjState(this);
  69. BcelWeaver bcelWeaver;
  70. public BcelWorld bcelWorld;
  71. public CountingMessageHandler handler;
  72. public AjBuildManager(IMessageHandler holder) {
  73. super();
  74. this.handler = CountingMessageHandler.makeCountingMessageHandler(holder);
  75. }
  76. /** @return true if we should generate a model as a side-effect */
  77. public boolean doGenerateModel() {
  78. return buildConfig.isGenerateModelMode();
  79. }
  80. public boolean batchBuild(
  81. AjBuildConfig buildConfig,
  82. IMessageHandler baseHandler)
  83. throws IOException, AbortException {
  84. return doBuild(buildConfig, baseHandler, true);
  85. }
  86. public boolean incrementalBuild(
  87. AjBuildConfig buildConfig,
  88. IMessageHandler baseHandler)
  89. throws IOException, AbortException {
  90. return doBuild(buildConfig, baseHandler, false);
  91. }
  92. /** @throws AbortException if check for runtime fails */
  93. protected boolean doBuild(
  94. AjBuildConfig buildConfig,
  95. IMessageHandler baseHandler,
  96. boolean batch) throws IOException, AbortException {
  97. boolean ret = true;
  98. batchCompile = batch;
  99. try {
  100. if (batch) {
  101. this.state = new AjState(this);
  102. }
  103. boolean canIncremental = state.prepareForNextBuild(buildConfig);
  104. if (!canIncremental && !batch) { // retry as batch?
  105. return doBuild(buildConfig, baseHandler, true);
  106. }
  107. this.handler =
  108. CountingMessageHandler.makeCountingMessageHandler(baseHandler);
  109. // XXX duplicate, no? remove?
  110. String check = checkRtJar(buildConfig);
  111. if (check != null) {
  112. if (FAIL_IF_RUNTIME_NOT_FOUND) {
  113. MessageUtil.error(handler, check);
  114. return false;
  115. } else {
  116. MessageUtil.warn(handler, check);
  117. }
  118. }
  119. // if (batch) {
  120. setBuildConfig(buildConfig);
  121. //}
  122. if (batch || !AsmManager.attemptIncrementalModelRepairs) {
  123. // if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  124. setupModel(buildConfig);
  125. // }
  126. }
  127. if (batch) {
  128. initBcelWorld(handler);
  129. }
  130. if (handler.hasErrors()) {
  131. return false;
  132. }
  133. if (buildConfig.getOutputJar() != null) {
  134. if (!openOutputStream(buildConfig.getOutputJar())) return false;
  135. }
  136. if (batch) {
  137. // System.err.println("XXXX batch: " + buildConfig.getFiles());
  138. if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  139. bcelWorld.setModel(AsmManager.getDefault().getHierarchy());
  140. // in incremental build, only get updated model?
  141. }
  142. binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(true);
  143. performCompilation(buildConfig.getFiles());
  144. if (handler.hasErrors()) {
  145. return false;
  146. }
  147. if (AsmManager.isReporting())
  148. AsmManager.getDefault().reportModelInfo("After a batch build");
  149. } else {
  150. // done already?
  151. // if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  152. // bcelWorld.setModel(StructureModelManager.INSTANCE.getStructureModel());
  153. // }
  154. // System.err.println("XXXX start inc ");
  155. binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(true);
  156. List files = state.getFilesToCompile(true);
  157. if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode())
  158. if (AsmManager.attemptIncrementalModelRepairs)
  159. AsmManager.getDefault().processDelta(files,state.addedFiles,state.deletedFiles);
  160. boolean hereWeGoAgain = !(files.isEmpty() && binarySourcesForTheNextCompile.isEmpty());
  161. for (int i = 0; (i < 5) && hereWeGoAgain; i++) {
  162. // System.err.println("XXXX inc: " + files);
  163. performCompilation(files);
  164. if (handler.hasErrors() || (progressListener!=null && progressListener.isCancelledRequested())) {
  165. return false;
  166. }
  167. binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(false);
  168. files = state.getFilesToCompile(false);
  169. hereWeGoAgain = !(files.isEmpty() && binarySourcesForTheNextCompile.isEmpty());
  170. // TODO Andy - Needs some thought here...
  171. // I think here we might want to pass empty addedFiles/deletedFiles as they were
  172. // dealt with on the first call to processDelta - we are going through this loop
  173. // again because in compiling something we found something else we needed to
  174. // rebuild. But what case causes this?
  175. if (hereWeGoAgain)
  176. if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode())
  177. if (AsmManager.attemptIncrementalModelRepairs)
  178. AsmManager.getDefault().processDelta(files,state.addedFiles,state.deletedFiles);
  179. }
  180. if (!files.isEmpty()) {
  181. return batchBuild(buildConfig, baseHandler);
  182. } else {
  183. if (AsmManager.isReporting())
  184. AsmManager.getDefault().reportModelInfo("After an incremental build");
  185. }
  186. }
  187. // XXX not in Mik's incremental
  188. if (buildConfig.isEmacsSymMode()) {
  189. new org.aspectj.ajdt.internal.core.builder.EmacsStructureModelManager().externalizeModel();
  190. }
  191. // have to tell state we succeeded or next is not incremental
  192. state.successfulCompile(buildConfig);
  193. copyResourcesToDestination();
  194. /*boolean weaved = *///weaveAndGenerateClassFiles();
  195. // if not weaved, then no-op build, no model changes
  196. // but always returns true
  197. // XXX weaved not in Mik's incremental
  198. if (buildConfig.isGenerateModelMode()) {
  199. AsmManager.getDefault().fireModelUpdated();
  200. }
  201. } finally {
  202. if (zos != null) {
  203. closeOutputStream(buildConfig.getOutputJar());
  204. }
  205. ret = !handler.hasErrors();
  206. // bug 59895, don't release reference to handler as may be needed by a nested call
  207. //handler = null;
  208. }
  209. return ret;
  210. }
  211. private boolean openOutputStream(File outJar) {
  212. try {
  213. OutputStream os = FileUtil.makeOutputStream(buildConfig.getOutputJar());
  214. zos = new JarOutputStream(os,bcelWeaver.getManifest(true));
  215. } catch (IOException ex) {
  216. IMessage message =
  217. new Message("Unable to open outjar "
  218. + outJar.getPath()
  219. + "(" + ex.getMessage()
  220. + ")",
  221. new SourceLocation(outJar,0),
  222. true);
  223. handler.handleMessage(message);
  224. return false;
  225. }
  226. return true;
  227. }
  228. private void closeOutputStream(File outJar) {
  229. try {
  230. if (zos != null) zos.close();
  231. zos = null;
  232. /* Ensure we don't write an incomplete JAR bug-71339 */
  233. if (handler.hasErrors()) {
  234. outJar.delete();
  235. }
  236. } catch (IOException ex) {
  237. IMessage message =
  238. new Message("Unable to write outjar "
  239. + outJar.getPath()
  240. + "(" + ex.getMessage()
  241. + ")",
  242. new SourceLocation(outJar,0),
  243. true);
  244. handler.handleMessage(message);
  245. }
  246. }
  247. private void copyResourcesToDestination() throws IOException {
  248. // resources that we need to copy are contained in the injars and inpath only
  249. for (Iterator i = buildConfig.getInJars().iterator(); i.hasNext(); ) {
  250. File inJar = (File)i.next();
  251. copyResourcesFromJarFile(inJar);
  252. }
  253. for (Iterator i = buildConfig.getInpath().iterator(); i.hasNext(); ) {
  254. File inPathElement = (File)i.next();
  255. if (inPathElement.isDirectory()) {
  256. copyResourcesFromDirectory(inPathElement);
  257. } else {
  258. copyResourcesFromJarFile(inPathElement);
  259. }
  260. }
  261. if (buildConfig.getSourcePathResources() != null) {
  262. for (Iterator i = buildConfig.getSourcePathResources().keySet().iterator(); i.hasNext(); ) {
  263. String resource = (String)i.next();
  264. File from = (File)buildConfig.getSourcePathResources().get(resource);
  265. copyResourcesFromFile(from,resource,from);
  266. }
  267. }
  268. writeManifest();
  269. }
  270. private void copyResourcesFromJarFile(File jarFile) throws IOException {
  271. JarInputStream inStream = null;
  272. try {
  273. inStream = new JarInputStream(new FileInputStream(jarFile));
  274. while (true) {
  275. ZipEntry entry = inStream.getNextEntry();
  276. if (entry == null) break;
  277. String filename = entry.getName();
  278. // System.out.println("? copyResourcesFromJarFile() filename='" + filename +"'");
  279. if (!entry.isDirectory() && acceptResource(filename)) {
  280. byte[] bytes = FileUtil.readAsByteArray(inStream);
  281. writeResource(filename,bytes,jarFile);
  282. }
  283. inStream.closeEntry();
  284. }
  285. } finally {
  286. if (inStream != null) inStream.close();
  287. }
  288. }
  289. private void copyResourcesFromDirectory(File dir) throws IOException {
  290. if (!COPY_INPATH_DIR_RESOURCES) return;
  291. // Get a list of all files (i.e. everything that isnt a directory)
  292. File[] files = FileUtil.listFiles(dir,new FileFilter() {
  293. public boolean accept(File f) {
  294. boolean accept = !(f.isDirectory() || f.getName().endsWith(".class")) ;
  295. return accept;
  296. }
  297. });
  298. // For each file, add it either as a real .class file or as a resource
  299. for (int i = 0; i < files.length; i++) {
  300. // ASSERT: files[i].getAbsolutePath().startsWith(inFile.getAbsolutePath()
  301. // or we are in trouble...
  302. String filename = files[i].getAbsolutePath().substring(
  303. dir.getAbsolutePath().length()+1);
  304. copyResourcesFromFile(files[i],filename,dir);
  305. }
  306. }
  307. private void copyResourcesFromFile(File f,String filename,File src) throws IOException {
  308. if (!acceptResource(filename)) return;
  309. FileInputStream fis = null;
  310. try {
  311. fis = new FileInputStream(f);
  312. byte[] bytes = FileUtil.readAsByteArray(fis);
  313. // String relativePath = files[i].getPath();
  314. writeResource(filename,bytes,src);
  315. } finally {
  316. if (fis != null) fis.close();
  317. }
  318. }
  319. private void writeResource(String filename, byte[] content, File srcLocation) throws IOException {
  320. if (state.resources.contains(filename)) {
  321. IMessage msg = new Message("duplicate resource: '" + filename + "'",
  322. IMessage.WARNING,
  323. null,
  324. new SourceLocation(srcLocation,0));
  325. handler.handleMessage(msg);
  326. return;
  327. }
  328. if (zos != null) {
  329. ZipEntry newEntry = new ZipEntry(filename); //??? get compression scheme right
  330. zos.putNextEntry(newEntry);
  331. zos.write(content);
  332. zos.closeEntry();
  333. } else {
  334. OutputStream fos =
  335. FileUtil.makeOutputStream(new File(buildConfig.getOutputDir(),filename));
  336. fos.write(content);
  337. fos.close();
  338. }
  339. state.resources.add(filename);
  340. }
  341. /*
  342. * If we are writing to an output directory copy the manifest but only
  343. * if we already have one
  344. */
  345. private void writeManifest () throws IOException {
  346. Manifest manifest = bcelWeaver.getManifest(false);
  347. if (manifest != null && zos == null) {
  348. OutputStream fos =
  349. FileUtil.makeOutputStream(new File(buildConfig.getOutputDir(),MANIFEST_NAME));
  350. manifest.write(fos);
  351. fos.close();
  352. }
  353. }
  354. private boolean acceptResource(String resourceName) {
  355. if (
  356. (resourceName.startsWith("CVS/")) ||
  357. (resourceName.indexOf("/CVS/") != -1) ||
  358. (resourceName.endsWith("/CVS")) ||
  359. (resourceName.endsWith(".class")) ||
  360. (resourceName.toUpperCase().equals(MANIFEST_NAME))
  361. )
  362. {
  363. return false;
  364. } else {
  365. return true;
  366. }
  367. }
  368. // public static void dumprels() {
  369. // IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
  370. // int ctr = 1;
  371. // Set entries = irm.getEntries();
  372. // for (Iterator iter = entries.iterator(); iter.hasNext();) {
  373. // String hid = (String) iter.next();
  374. // List rels = irm.get(hid);
  375. // for (Iterator iterator = rels.iterator(); iterator.hasNext();) {
  376. // IRelationship ir = (IRelationship) iterator.next();
  377. // List targets = ir.getTargets();
  378. // for (Iterator iterator2 = targets.iterator();
  379. // iterator2.hasNext();
  380. // ) {
  381. // String thid = (String) iterator2.next();
  382. // System.err.println("Hid:"+(ctr++)+":(targets="+targets.size()+") "+hid+" ("+ir.getName()+") "+thid);
  383. // }
  384. // }
  385. // }
  386. // }
  387. /**
  388. * Responsible for managing the ASM model between builds. Contains the policy for
  389. * maintaining the persistance of elements in the model.
  390. *
  391. * TODO: implement incremental policy.
  392. */
  393. private void setupModel(AjBuildConfig config) {
  394. IHierarchy model = AsmManager.getDefault().getHierarchy();
  395. String rootLabel = "<root>";
  396. AsmManager.getDefault().getRelationshipMap().clear();
  397. IProgramElement.Kind kind = IProgramElement.Kind.FILE_JAVA;
  398. if (buildConfig.getConfigFile() != null) {
  399. rootLabel = buildConfig.getConfigFile().getName();
  400. model.setConfigFile(
  401. buildConfig.getConfigFile().getAbsolutePath()
  402. );
  403. kind = IProgramElement.Kind.FILE_LST;
  404. }
  405. model.setRoot(new ProgramElement(rootLabel, kind, new ArrayList()));
  406. model.setFileMap(new HashMap());
  407. setStructureModel(model);
  408. }
  409. //
  410. // private void dumplist(List l) {
  411. // System.err.println("---- "+l.size());
  412. // for (int i =0 ;i<l.size();i++) System.err.println(i+"\t "+l.get(i));
  413. // }
  414. // private void accumulateFileNodes(IProgramElement ipe,List store) {
  415. // if (ipe.getKind()==IProgramElement.Kind.FILE_JAVA ||
  416. // ipe.getKind()==IProgramElement.Kind.FILE_ASPECTJ) {
  417. // if (!ipe.getName().equals("<root>")) {
  418. // store.add(ipe);
  419. // return;
  420. // }
  421. // }
  422. // for (Iterator i = ipe.getChildren().iterator();i.hasNext();) {
  423. // accumulateFileNodes((IProgramElement)i.next(),store);
  424. // }
  425. // }
  426. /** init only on initial batch compile? no file-specific options */
  427. private void initBcelWorld(IMessageHandler handler) throws IOException {
  428. bcelWorld = new BcelWorld(buildConfig.getClasspath(), handler, null);
  429. bcelWorld.setXnoInline(buildConfig.isXnoInline());
  430. bcelWorld.setXlazyTjp(buildConfig.isXlazyTjp());
  431. bcelWeaver = new BcelWeaver(bcelWorld);
  432. state.binarySourceFiles = new HashMap();
  433. for (Iterator i = buildConfig.getAspectpath().iterator(); i.hasNext();) {
  434. File f = (File) i.next();
  435. bcelWeaver.addLibraryJarFile(f);
  436. }
  437. // String lintMode = buildConfig.getLintMode();
  438. if (buildConfig.getLintMode().equals(AjBuildConfig.AJLINT_DEFAULT)) {
  439. bcelWorld.getLint().loadDefaultProperties();
  440. } else {
  441. bcelWorld.getLint().setAll(buildConfig.getLintMode());
  442. }
  443. if (buildConfig.getLintSpecFile() != null) {
  444. bcelWorld.getLint().setFromProperties(buildConfig.getLintSpecFile());
  445. }
  446. //??? incremental issues
  447. for (Iterator i = buildConfig.getInJars().iterator(); i.hasNext(); ) {
  448. File inJar = (File)i.next();
  449. List unwovenClasses = bcelWeaver.addJarFile(inJar, buildConfig.getOutputDir(),false);
  450. state.binarySourceFiles.put(inJar.getPath(), unwovenClasses);
  451. }
  452. for (Iterator i = buildConfig.getInpath().iterator(); i.hasNext(); ) {
  453. File inPathElement = (File)i.next();
  454. if (!inPathElement.isDirectory()) {
  455. // its a jar file on the inpath
  456. // the weaver method can actually handle dirs, but we don't call it, see next block
  457. List unwovenClasses = bcelWeaver.addJarFile(inPathElement,buildConfig.getOutputDir(),true);
  458. state.binarySourceFiles.put(inPathElement.getPath(),unwovenClasses);
  459. } else {
  460. // add each class file in an in-dir individually, this gives us the best error reporting
  461. // (they are like 'source' files then), and enables a cleaner incremental treatment of
  462. // class file changes in indirs.
  463. File[] binSrcs = FileUtil.listFiles(inPathElement, binarySourceFilter);
  464. for (int j = 0; j < binSrcs.length; j++) {
  465. UnwovenClassFile ucf =
  466. bcelWeaver.addClassFile(binSrcs[j], inPathElement, buildConfig.getOutputDir());
  467. List ucfl = new ArrayList();
  468. ucfl.add(ucf);
  469. state.binarySourceFiles.put(binSrcs[j].getPath(),ucfl);
  470. }
  471. }
  472. }
  473. bcelWeaver.setReweavableMode(buildConfig.isXreweavable(),buildConfig.getXreweavableCompressClasses());
  474. //check for org.aspectj.runtime.JoinPoint
  475. bcelWorld.resolve("org.aspectj.lang.JoinPoint");
  476. }
  477. public World getWorld() {
  478. return bcelWorld;
  479. }
  480. void addAspectClassFilesToWeaver(List addedClassFiles) throws IOException {
  481. for (Iterator i = addedClassFiles.iterator(); i.hasNext(); ) {
  482. UnwovenClassFile classFile = (UnwovenClassFile) i.next();
  483. bcelWeaver.addClassFile(classFile);
  484. }
  485. }
  486. // public boolean weaveAndGenerateClassFiles() throws IOException {
  487. // handler.handleMessage(MessageUtil.info("weaving"));
  488. // if (progressListener != null) progressListener.setText("weaving aspects");
  489. // bcelWeaver.setProgressListener(progressListener, 0.5, 0.5/state.addedClassFiles.size());
  490. // //!!! doesn't provide intermediate progress during weaving
  491. // // XXX add all aspects even during incremental builds?
  492. // addAspectClassFilesToWeaver(state.addedClassFiles);
  493. // if (buildConfig.isNoWeave()) {
  494. // if (buildConfig.getOutputJar() != null) {
  495. // bcelWeaver.dumpUnwoven(buildConfig.getOutputJar());
  496. // } else {
  497. // bcelWeaver.dumpUnwoven();
  498. // bcelWeaver.dumpResourcesToOutPath();
  499. // }
  500. // } else {
  501. // if (buildConfig.getOutputJar() != null) {
  502. // bcelWeaver.weave(buildConfig.getOutputJar());
  503. // } else {
  504. // bcelWeaver.weave();
  505. // bcelWeaver.dumpResourcesToOutPath();
  506. // }
  507. // }
  508. // if (progressListener != null) progressListener.setProgress(1.0);
  509. // return true;
  510. // //return messageAdapter.getErrorCount() == 0; //!javaBuilder.notifier.anyErrors();
  511. // }
  512. public FileSystem getLibraryAccess(String[] classpaths, String[] filenames) {
  513. String defaultEncoding = buildConfig.getOptions().defaultEncoding;
  514. if ("".equals(defaultEncoding)) //$NON-NLS-1$
  515. defaultEncoding = null; //$NON-NLS-1$
  516. // Bug 46671: We need an array as long as the number of elements in the classpath - *even though* not every
  517. // element of the classpath is likely to be a directory. If we ensure every element of the array is set to
  518. // only look for BINARY, then we make sure that for any classpath element that is a directory, we won't build
  519. // a classpathDirectory object that will attempt to look for source when it can't find binary.
  520. int[] classpathModes = new int[classpaths.length];
  521. for (int i =0 ;i<classpaths.length;i++) classpathModes[i]=ClasspathDirectory.BINARY;
  522. return new FileSystem(classpaths, filenames, defaultEncoding,classpathModes);
  523. }
  524. public IProblemFactory getProblemFactory() {
  525. return new DefaultProblemFactory(Locale.getDefault());
  526. }
  527. /*
  528. * Build the set of compilation source units
  529. */
  530. public CompilationUnit[] getCompilationUnits(String[] filenames, String[] encodings) {
  531. int fileCount = filenames.length;
  532. CompilationUnit[] units = new CompilationUnit[fileCount];
  533. // HashtableOfObject knownFileNames = new HashtableOfObject(fileCount);
  534. String defaultEncoding = buildConfig.getOptions().defaultEncoding;
  535. if ("".equals(defaultEncoding)) //$NON-NLS-1$
  536. defaultEncoding = null; //$NON-NLS-1$
  537. for (int i = 0; i < fileCount; i++) {
  538. String encoding = encodings[i];
  539. if (encoding == null)
  540. encoding = defaultEncoding;
  541. units[i] = new CompilationUnit(null, filenames[i], encoding);
  542. }
  543. return units;
  544. }
  545. public String extractDestinationPathFromSourceFile(CompilationResult result) {
  546. ICompilationUnit compilationUnit = result.compilationUnit;
  547. if (compilationUnit != null) {
  548. char[] fileName = compilationUnit.getFileName();
  549. int lastIndex = CharOperation.lastIndexOf(java.io.File.separatorChar, fileName);
  550. if (lastIndex == -1) {
  551. return System.getProperty("user.dir"); //$NON-NLS-1$
  552. }
  553. return new String(CharOperation.subarray(fileName, 0, lastIndex));
  554. }
  555. return System.getProperty("user.dir"); //$NON-NLS-1$
  556. }
  557. public void performCompilation(List files) {
  558. if (progressListener != null) {
  559. compiledCount = 0;
  560. sourceFileCount = files.size();
  561. progressListener.setText("compiling source files");
  562. }
  563. //System.err.println("got files: " + files);
  564. String[] filenames = new String[files.size()];
  565. String[] encodings = new String[files.size()];
  566. //System.err.println("filename: " + this.filenames);
  567. for (int i=0; i < files.size(); i++) {
  568. filenames[i] = ((File)files.get(i)).getPath();
  569. }
  570. List cps = buildConfig.getFullClasspath();
  571. Dump.saveFullClasspath(cps);
  572. String[] classpaths = new String[cps.size()];
  573. for (int i=0; i < cps.size(); i++) {
  574. classpaths[i] = (String)cps.get(i);
  575. }
  576. //System.out.println("compiling");
  577. environment = getLibraryAccess(classpaths, filenames);
  578. if (!state.classesFromName.isEmpty()) {
  579. environment = new StatefulNameEnvironment(environment, state.classesFromName);
  580. }
  581. org.eclipse.jdt.internal.compiler.Compiler.setCompilerAdapterFactory(this);
  582. org.eclipse.jdt.internal.compiler.Compiler compiler =
  583. new org.eclipse.jdt.internal.compiler.Compiler(environment,
  584. DefaultErrorHandlingPolicies.proceedWithAllProblems(),
  585. buildConfig.getOptions().getMap(),
  586. getBatchRequestor(),
  587. getProblemFactory());
  588. CompilerOptions options = compiler.options;
  589. options.produceReferenceInfo = true; //TODO turn off when not needed
  590. try {
  591. compiler.compile(getCompilationUnits(filenames, encodings));
  592. } catch (OperationCanceledException oce) {
  593. handler.handleMessage(new Message("build cancelled:"+oce.getMessage(),IMessage.WARNING,null,null));
  594. }
  595. // cleanup
  596. environment.cleanup();
  597. environment = null;
  598. }
  599. /*
  600. * Answer the component to which will be handed back compilation results from the compiler
  601. */
  602. public IIntermediateResultsRequestor getInterimResultRequestor() {
  603. return new IIntermediateResultsRequestor() {
  604. int lineDelta = 0;
  605. public void acceptResult(InterimCompilationResult result) {
  606. if (progressListener != null) {
  607. compiledCount++;
  608. progressListener.setProgress((compiledCount/2.0)/sourceFileCount);
  609. progressListener.setText("compiled: " + result.fileName());
  610. }
  611. state.noteResult(result);
  612. if (progressListener!=null && progressListener.isCancelledRequested()) {
  613. throw new AbortCompilation(true,
  614. new OperationCanceledException("Compilation cancelled as requested"));
  615. }
  616. }
  617. };
  618. }
  619. public ICompilerRequestor getBatchRequestor() {
  620. return new ICompilerRequestor() {
  621. public void acceptResult(CompilationResult unitResult) {
  622. // end of compile, must now write the results to the output destination
  623. // this is either a jar file or a file in a directory
  624. if (!(unitResult.hasErrors() && !proceedOnError())) {
  625. Enumeration classFiles = unitResult.compiledTypes.elements();
  626. while (classFiles.hasMoreElements()) {
  627. ClassFile classFile = (ClassFile) classFiles.nextElement();
  628. String filename = new String(classFile.fileName());
  629. filename = filename.replace('/', File.separatorChar) + ".class";
  630. try {
  631. if (buildConfig.getOutputJar() == null) {
  632. writeDirectoryEntry(unitResult, classFile,filename);
  633. } else {
  634. writeZipEntry(classFile,filename);
  635. }
  636. } catch (IOException ex) {
  637. IMessage message = EclipseAdapterUtils.makeErrorMessage(
  638. new String(unitResult.fileName),
  639. CANT_WRITE_RESULT,
  640. ex);
  641. handler.handleMessage(message);
  642. }
  643. }
  644. }
  645. if (unitResult.hasProblems() || unitResult.hasTasks()) {
  646. IProblem[] problems = unitResult.getAllProblems();
  647. for (int i=0; i < problems.length; i++) {
  648. IMessage message =
  649. EclipseAdapterUtils.makeMessage(unitResult.compilationUnit, problems[i]);
  650. handler.handleMessage(message);
  651. }
  652. }
  653. }
  654. private void writeDirectoryEntry(
  655. CompilationResult unitResult,
  656. ClassFile classFile,
  657. String filename)
  658. throws IOException {
  659. File destinationPath = buildConfig.getOutputDir();
  660. String outFile;
  661. if (destinationPath == null) {
  662. outFile = new File(filename).getName();
  663. outFile = new File(extractDestinationPathFromSourceFile(unitResult), outFile).getPath();
  664. } else {
  665. outFile = new File(destinationPath, filename).getPath();
  666. }
  667. BufferedOutputStream os =
  668. FileUtil.makeOutputStream(new File(outFile));
  669. os.write(classFile.getBytes());
  670. os.close();
  671. }
  672. private void writeZipEntry(ClassFile classFile, String name)
  673. throws IOException {
  674. name = name.replace(File.separatorChar,'/');
  675. ZipEntry newEntry = new ZipEntry(name); //??? get compression scheme right
  676. zos.putNextEntry(newEntry);
  677. zos.write(classFile.getBytes());
  678. zos.closeEntry();
  679. }
  680. };
  681. }
  682. protected boolean proceedOnError() {
  683. return true; //???
  684. }
  685. // public void noteClassFiles(AjCompiler.InterimResult result) {
  686. // if (result == null) return;
  687. // CompilationResult unitResult = result.result;
  688. // String sourceFileName = result.fileName();
  689. // if (!(unitResult.hasErrors() && !proceedOnError())) {
  690. // List unwovenClassFiles = new ArrayList();
  691. // Enumeration classFiles = unitResult.compiledTypes.elements();
  692. // while (classFiles.hasMoreElements()) {
  693. // ClassFile classFile = (ClassFile) classFiles.nextElement();
  694. // String filename = new String(classFile.fileName());
  695. // filename = filename.replace('/', File.separatorChar) + ".class";
  696. //
  697. // File destinationPath = buildConfig.getOutputDir();
  698. // if (destinationPath == null) {
  699. // filename = new File(filename).getName();
  700. // filename = new File(extractDestinationPathFromSourceFile(unitResult), filename).getPath();
  701. // } else {
  702. // filename = new File(destinationPath, filename).getPath();
  703. // }
  704. //
  705. // //System.out.println("classfile: " + filename);
  706. // unwovenClassFiles.add(new UnwovenClassFile(filename, classFile.getBytes()));
  707. // }
  708. // state.noteClassesFromFile(unitResult, sourceFileName, unwovenClassFiles);
  709. //// System.out.println("file: " + sourceFileName);
  710. //// for (int i=0; i < unitResult.simpleNameReferences.length; i++) {
  711. //// System.out.println("simple: " + new String(unitResult.simpleNameReferences[i]));
  712. //// }
  713. //// for (int i=0; i < unitResult.qualifiedReferences.length; i++) {
  714. //// System.out.println("qualified: " +
  715. //// new String(CharOperation.concatWith(unitResult.qualifiedReferences[i], '/')));
  716. //// }
  717. // } else {
  718. // state.noteClassesFromFile(null, sourceFileName, Collections.EMPTY_LIST);
  719. // }
  720. // }
  721. //
  722. private void setBuildConfig(AjBuildConfig buildConfig) {
  723. this.buildConfig = buildConfig;
  724. handler.reset();
  725. }
  726. String makeClasspathString() {
  727. if (buildConfig == null || buildConfig.getClasspath() == null) return "";
  728. StringBuffer buf = new StringBuffer();
  729. boolean first = true;
  730. for (Iterator it = buildConfig.getClasspath().iterator(); it.hasNext(); ) {
  731. if (first) { first = false; }
  732. else { buf.append(File.pathSeparator); }
  733. buf.append(it.next().toString());
  734. }
  735. return buf.toString();
  736. }
  737. /**
  738. * This will return null if aspectjrt.jar is present and has the correct version.
  739. * Otherwise it will return a string message indicating the problem.
  740. */
  741. public String checkRtJar(AjBuildConfig buildConfig) {
  742. // omitting dev info
  743. if (Version.text.equals(Version.DEVELOPMENT)) {
  744. // in the development version we can't do this test usefully
  745. // MessageUtil.info(holder, "running development version of aspectj compiler");
  746. return null;
  747. }
  748. if (buildConfig == null || buildConfig.getClasspath() == null) return "no classpath specified";
  749. for (Iterator it = buildConfig.getClasspath().iterator(); it.hasNext(); ) {
  750. File p = new File( (String)it.next() );
  751. if (p.isFile() && p.getName().equals("aspectjrt.jar")) {
  752. try {
  753. String version = null;
  754. Manifest manifest = new JarFile(p).getManifest();
  755. if (manifest == null) {
  756. return "no manifest found in " + p.getAbsolutePath() +
  757. ", expected " + Version.text;
  758. }
  759. Attributes attr = manifest.getAttributes("org/aspectj/lang/");
  760. if (null != attr) {
  761. version = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
  762. if (null != version) {
  763. version = version.trim();
  764. }
  765. }
  766. // assume that users of development aspectjrt.jar know what they're doing
  767. if (Version.DEVELOPMENT.equals(version)) {
  768. // MessageUtil.info(holder,
  769. // "running with development version of aspectjrt.jar in " +
  770. // p.getAbsolutePath());
  771. return null;
  772. } else if (!Version.text.equals(version)) {
  773. return "bad version number found in " + p.getAbsolutePath() +
  774. " expected " + Version.text + " found " + version;
  775. }
  776. } catch (IOException ioe) {
  777. return "bad jar file found in " + p.getAbsolutePath() + " error: " + ioe;
  778. }
  779. return null;
  780. } else {
  781. // might want to catch other classpath errors
  782. }
  783. }
  784. return "couldn't find aspectjrt.jar on classpath, checked: " + makeClasspathString();
  785. }
  786. public String toString() {
  787. StringBuffer buf = new StringBuffer();
  788. buf.append("AjBuildManager(");
  789. buf.append(")");
  790. return buf.toString();
  791. }
  792. public void setStructureModel(IHierarchy structureModel) {
  793. this.structureModel = structureModel;
  794. }
  795. /**
  796. * Returns null if there is no structure model
  797. */
  798. public IHierarchy getStructureModel() {
  799. return structureModel;
  800. }
  801. public IProgressListener getProgressListener() {
  802. return progressListener;
  803. }
  804. public void setProgressListener(IProgressListener progressListener) {
  805. this.progressListener = progressListener;
  806. }
  807. /* (non-Javadoc)
  808. * @see org.aspectj.ajdt.internal.compiler.AjCompiler.IOutputClassFileNameProvider#getOutputClassFileName(char[])
  809. */
  810. public String getOutputClassFileName(char[] eclipseClassFileName, CompilationResult result) {
  811. String filename = new String(eclipseClassFileName);
  812. filename = filename.replace('/', File.separatorChar) + ".class";
  813. File destinationPath = buildConfig.getOutputDir();
  814. String outFile;
  815. if (destinationPath == null) {
  816. outFile = new File(filename).getName();
  817. outFile = new File(extractDestinationPathFromSourceFile(result), outFile).getPath();
  818. } else {
  819. outFile = new File(destinationPath, filename).getPath();
  820. }
  821. return outFile;
  822. }
  823. /* (non-Javadoc)
  824. * @see org.eclipse.jdt.internal.compiler.ICompilerAdapterFactory#getAdapter(org.eclipse.jdt.internal.compiler.Compiler)
  825. */
  826. public ICompilerAdapter getAdapter(org.eclipse.jdt.internal.compiler.Compiler forCompiler) {
  827. // complete compiler config and return a suitable adapter...
  828. AjProblemReporter pr =
  829. new AjProblemReporter(DefaultErrorHandlingPolicies.proceedWithAllProblems(),
  830. forCompiler.options, getProblemFactory());
  831. forCompiler.problemReporter = pr;
  832. AjLookupEnvironment le =
  833. new AjLookupEnvironment(forCompiler, forCompiler.options, pr, environment);
  834. EclipseFactory factory = new EclipseFactory(le,this);
  835. le.factory = factory;
  836. pr.factory = factory;
  837. forCompiler.lookupEnvironment = le;
  838. forCompiler.parser =
  839. new Parser(
  840. pr,
  841. forCompiler.options.parseLiteralExpressionsAsConstants);
  842. return new AjCompilerAdapter(forCompiler,batchCompile,bcelWorld,bcelWeaver,
  843. factory,
  844. getInterimResultRequestor(),
  845. progressListener,
  846. this, // IOutputFilenameProvider
  847. this, // IBinarySourceProvider
  848. state.binarySourceFiles,
  849. state.resultsFromFile.values(),
  850. buildConfig.isNoWeave());
  851. }
  852. /* (non-Javadoc)
  853. * @see org.aspectj.ajdt.internal.compiler.IBinarySourceProvider#getBinarySourcesForThisWeave()
  854. */
  855. public Map getBinarySourcesForThisWeave() {
  856. return binarySourcesForTheNextCompile;
  857. }
  858. public static AsmHierarchyBuilder getAsmHierarchyBuilder() {
  859. return asmHierarchyBuilder;
  860. }
  861. /**
  862. * Override the the default hierarchy builder.
  863. */
  864. public static void setAsmHierarchyBuilder(AsmHierarchyBuilder newBuilder) {
  865. asmHierarchyBuilder = newBuilder;
  866. }
  867. public AjState getState() {
  868. return state;
  869. }
  870. } // class AjBuildManager