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.

AjBuildManager.java 55KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
  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 Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.ajdt.internal.core.builder;
  13. import java.io.BufferedOutputStream;
  14. import java.io.ByteArrayOutputStream;
  15. import java.io.File;
  16. import java.io.FileFilter;
  17. import java.io.FileInputStream;
  18. import java.io.FileNotFoundException;
  19. import java.io.IOException;
  20. import java.io.OutputStream;
  21. import java.io.PrintStream;
  22. import java.util.ArrayList;
  23. import java.util.Collection;
  24. import java.util.Collections;
  25. import java.util.HashMap;
  26. import java.util.Iterator;
  27. import java.util.List;
  28. import java.util.Locale;
  29. import java.util.Map;
  30. import java.util.Set;
  31. import java.util.jar.Attributes;
  32. import java.util.jar.JarFile;
  33. import java.util.jar.JarInputStream;
  34. import java.util.jar.JarOutputStream;
  35. import java.util.jar.Manifest;
  36. import java.util.zip.ZipEntry;
  37. import org.aspectj.ajdt.internal.compiler.AjCompilerAdapter;
  38. import org.aspectj.ajdt.internal.compiler.AjPipeliningCompilerAdapter;
  39. import org.aspectj.ajdt.internal.compiler.CompilationResultDestinationManager;
  40. import org.aspectj.ajdt.internal.compiler.IBinarySourceProvider;
  41. import org.aspectj.ajdt.internal.compiler.ICompilerAdapter;
  42. import org.aspectj.ajdt.internal.compiler.ICompilerAdapterFactory;
  43. import org.aspectj.ajdt.internal.compiler.IIntermediateResultsRequestor;
  44. import org.aspectj.ajdt.internal.compiler.IOutputClassFileNameProvider;
  45. import org.aspectj.ajdt.internal.compiler.InterimCompilationResult;
  46. import org.aspectj.ajdt.internal.compiler.lookup.AjLookupEnvironment;
  47. import org.aspectj.ajdt.internal.compiler.lookup.AnonymousClassPublisher;
  48. import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
  49. import org.aspectj.ajdt.internal.compiler.problem.AjProblemReporter;
  50. import org.aspectj.asm.AsmManager;
  51. import org.aspectj.asm.IHierarchy;
  52. import org.aspectj.asm.IProgramElement;
  53. import org.aspectj.asm.internal.ProgramElement;
  54. import org.aspectj.bridge.AbortException;
  55. import org.aspectj.bridge.CountingMessageHandler;
  56. import org.aspectj.bridge.ILifecycleAware;
  57. import org.aspectj.bridge.IMessage;
  58. import org.aspectj.bridge.IMessageHandler;
  59. import org.aspectj.bridge.IProgressListener;
  60. import org.aspectj.bridge.Message;
  61. import org.aspectj.bridge.MessageUtil;
  62. import org.aspectj.bridge.SourceLocation;
  63. import org.aspectj.bridge.Version;
  64. import org.aspectj.bridge.context.CompilationAndWeavingContext;
  65. import org.aspectj.bridge.context.ContextFormatter;
  66. import org.aspectj.bridge.context.ContextToken;
  67. import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
  68. import org.aspectj.org.eclipse.jdt.core.compiler.IProblem;
  69. import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
  70. import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
  71. import org.aspectj.org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
  72. import org.aspectj.org.eclipse.jdt.internal.compiler.ICompilerRequestor;
  73. import org.aspectj.org.eclipse.jdt.internal.compiler.IProblemFactory;
  74. import org.aspectj.org.eclipse.jdt.internal.compiler.batch.ClasspathLocation;
  75. import org.aspectj.org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
  76. import org.aspectj.org.eclipse.jdt.internal.compiler.batch.FileSystem;
  77. import org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
  78. import org.aspectj.org.eclipse.jdt.internal.compiler.env.INameEnvironment;
  79. import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
  80. import org.aspectj.org.eclipse.jdt.internal.compiler.impl.IrritantSet;
  81. import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
  82. import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
  83. import org.aspectj.org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
  84. import org.aspectj.tools.ajc.Main;
  85. import org.aspectj.util.FileUtil;
  86. import org.aspectj.weaver.CustomMungerFactory;
  87. import org.aspectj.weaver.Dump;
  88. import org.aspectj.weaver.ResolvedType;
  89. import org.aspectj.weaver.World;
  90. import org.aspectj.weaver.bcel.BcelWeaver;
  91. import org.aspectj.weaver.bcel.BcelWorld;
  92. import org.aspectj.weaver.bcel.UnwovenClassFile;
  93. import org.eclipse.core.runtime.OperationCanceledException;
  94. public class AjBuildManager implements IOutputClassFileNameProvider, IBinarySourceProvider, ICompilerAdapterFactory {
  95. private static final String CROSSREFS_FILE_NAME = "build.lst";
  96. private static final String CANT_WRITE_RESULT = "unable to write compilation result";
  97. private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
  98. public static boolean COPY_INPATH_DIR_RESOURCES = false;
  99. // AJDT doesn't want this check, so Main enables it.
  100. private static boolean DO_RUNTIME_VERSION_CHECK = false;
  101. // If runtime version check fails, warn or fail? (unset?)
  102. static final boolean FAIL_IF_RUNTIME_NOT_FOUND = false;
  103. private static final FileFilter binarySourceFilter = new FileFilter() {
  104. public boolean accept(File f) {
  105. return f.getName().endsWith(".class");
  106. }
  107. };
  108. /**
  109. * This builder is static so that it can be subclassed and reset. However, note that there is only one builder present, so if
  110. * two extendsion reset it, only the latter will get used.
  111. */
  112. public static AsmHierarchyBuilder asmHierarchyBuilder = new AsmHierarchyBuilder();
  113. static {
  114. // CompilationAndWeavingContext.setMultiThreaded(false);
  115. CompilationAndWeavingContext.registerFormatter(CompilationAndWeavingContext.BATCH_BUILD, new AjBuildContexFormatter());
  116. CompilationAndWeavingContext
  117. .registerFormatter(CompilationAndWeavingContext.INCREMENTAL_BUILD, new AjBuildContexFormatter());
  118. }
  119. private IProgressListener progressListener = null;
  120. private boolean environmentSupportsIncrementalCompilation = false;
  121. private int compiledCount;
  122. private int sourceFileCount;
  123. private JarOutputStream zos;
  124. private boolean batchCompile = true;
  125. private INameEnvironment environment;
  126. private Map /* String -> List<UCF> */binarySourcesForTheNextCompile = new HashMap();
  127. // FIXME asc should this really be in here?
  128. // private AsmManager structureModel;
  129. public AjBuildConfig buildConfig;
  130. private boolean ignoreOutxml;
  131. private boolean wasFullBuild = true; // true if last build was a full build rather than an incremental build
  132. AjState state = new AjState(this);
  133. /**
  134. * Enable check for runtime version, used only by Ant/command-line Main.
  135. *
  136. * @param main Main unused except to limit to non-null clients.
  137. */
  138. public static void enableRuntimeVersionCheck(Main caller) {
  139. DO_RUNTIME_VERSION_CHECK = null != caller;
  140. }
  141. public BcelWeaver getWeaver() {
  142. return state.getWeaver();
  143. }
  144. public BcelWorld getBcelWorld() {
  145. return state.getBcelWorld();
  146. }
  147. public CountingMessageHandler handler;
  148. private CustomMungerFactory customMungerFactory;
  149. public AjBuildManager(IMessageHandler holder) {
  150. super();
  151. this.handler = CountingMessageHandler.makeCountingMessageHandler(holder);
  152. }
  153. public void environmentSupportsIncrementalCompilation(boolean itDoes) {
  154. this.environmentSupportsIncrementalCompilation = itDoes;
  155. if (itDoes) {
  156. org.aspectj.weaver.loadtime.definition.DocumentParser.deactivateCaching();
  157. }
  158. }
  159. /** @return true if we should generate a model as a side-effect */
  160. public boolean doGenerateModel() {
  161. return buildConfig.isGenerateModelMode();
  162. }
  163. public boolean batchBuild(AjBuildConfig buildConfig, IMessageHandler baseHandler) throws IOException, AbortException {
  164. return performBuild(buildConfig, baseHandler, true);
  165. }
  166. public boolean incrementalBuild(AjBuildConfig buildConfig, IMessageHandler baseHandler) throws IOException, AbortException {
  167. return performBuild(buildConfig, baseHandler, false);
  168. }
  169. /**
  170. * Perform a build.
  171. *
  172. * @return true if the build was successful (ie. no errors)
  173. */
  174. private boolean performBuild(AjBuildConfig buildConfig, IMessageHandler baseHandler, boolean isFullBuild) throws IOException,
  175. AbortException {
  176. boolean ret = true;
  177. batchCompile = isFullBuild;
  178. wasFullBuild = isFullBuild;
  179. if (baseHandler instanceof ILifecycleAware) {
  180. ((ILifecycleAware) baseHandler).buildStarting(!isFullBuild);
  181. }
  182. CompilationAndWeavingContext.reset();
  183. int phase = isFullBuild ? CompilationAndWeavingContext.BATCH_BUILD : CompilationAndWeavingContext.INCREMENTAL_BUILD;
  184. ContextToken ct = CompilationAndWeavingContext.enteringPhase(phase, buildConfig);
  185. try {
  186. if (isFullBuild) {
  187. this.state = new AjState(this);
  188. }
  189. this.state.setCouldBeSubsequentIncrementalBuild(this.environmentSupportsIncrementalCompilation);
  190. boolean canIncremental = state.prepareForNextBuild(buildConfig);
  191. if (!canIncremental && !isFullBuild) { // retry as batch?
  192. CompilationAndWeavingContext.leavingPhase(ct);
  193. if (state.listenerDefined()) {
  194. state.getListener().recordDecision("Falling back to batch compilation");
  195. }
  196. return performBuild(buildConfig, baseHandler, true);
  197. }
  198. this.handler = CountingMessageHandler.makeCountingMessageHandler(baseHandler);
  199. if (buildConfig == null || buildConfig.isCheckRuntimeVersion()) {
  200. if (DO_RUNTIME_VERSION_CHECK) {
  201. String check = checkRtJar(buildConfig);
  202. if (check != null) {
  203. if (FAIL_IF_RUNTIME_NOT_FOUND) {
  204. MessageUtil.error(handler, check);
  205. CompilationAndWeavingContext.leavingPhase(ct);
  206. return false;
  207. } else {
  208. MessageUtil.warn(handler, check);
  209. }
  210. }
  211. }
  212. }
  213. // if (batch) {
  214. setBuildConfig(buildConfig);
  215. // }
  216. if (isFullBuild || !AsmManager.attemptIncrementalModelRepairs) {
  217. // if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  218. setupModel(buildConfig);
  219. // }
  220. }
  221. if (isFullBuild) {
  222. initBcelWorld(handler);
  223. }
  224. if (handler.hasErrors()) {
  225. CompilationAndWeavingContext.leavingPhase(ct);
  226. return false;
  227. }
  228. if (buildConfig.getOutputJar() != null) {
  229. if (!openOutputStream(buildConfig.getOutputJar())) {
  230. CompilationAndWeavingContext.leavingPhase(ct);
  231. return false;
  232. }
  233. }
  234. if (isFullBuild) {
  235. // System.err.println("XXXX batch: " + buildConfig.getFiles());
  236. if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  237. AsmManager.setLastActiveStructureModel(state.getStructureModel());
  238. getWorld().setModel(state.getStructureModel());
  239. // in incremental build, only get updated model?
  240. }
  241. binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(true);
  242. performCompilation(buildConfig.getFiles());
  243. state.clearBinarySourceFiles(); // we don't want these hanging around...
  244. if (!proceedOnError() && handler.hasErrors()) {
  245. CompilationAndWeavingContext.leavingPhase(ct);
  246. if (AsmManager.isReporting()) {
  247. state.getStructureModel().reportModelInfo("After a batch build");
  248. }
  249. return false;
  250. }
  251. if (AsmManager.isReporting()) {
  252. state.getStructureModel().reportModelInfo("After a batch build");
  253. }
  254. } else {
  255. // done already?
  256. // if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  257. // bcelWorld.setModel(StructureModelManager.INSTANCE.getStructureModel());
  258. // }
  259. // System.err.println("XXXX start inc ");
  260. AsmManager.setLastActiveStructureModel(state.getStructureModel());
  261. binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(true);
  262. Set<File> files = state.getFilesToCompile(true);
  263. if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  264. if (AsmManager.attemptIncrementalModelRepairs) {
  265. state.getStructureModel().resetDeltaProcessing();
  266. state.getStructureModel().processDelta(files, state.getAddedFiles(), state.getDeletedFiles());
  267. }
  268. }
  269. boolean hereWeGoAgain = !(files.isEmpty() && binarySourcesForTheNextCompile.isEmpty());
  270. for (int i = 0; (i < 5) && hereWeGoAgain; i++) {
  271. if (state.listenerDefined()) {
  272. state.getListener()
  273. .recordInformation("Starting incremental compilation loop " + (i + 1) + " of possibly 5");
  274. // System.err.println("XXXX inc: " + files);
  275. }
  276. performCompilation(files);
  277. if ((!proceedOnError() && handler.hasErrors())
  278. || (progressListener != null && progressListener.isCancelledRequested())) {
  279. CompilationAndWeavingContext.leavingPhase(ct);
  280. return false;
  281. }
  282. if (state.requiresFullBatchBuild()) {
  283. if (state.listenerDefined()) {
  284. state.getListener().recordInformation(" Dropping back to full build");
  285. }
  286. return batchBuild(buildConfig, baseHandler);
  287. }
  288. binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(false);
  289. files = state.getFilesToCompile(false);
  290. hereWeGoAgain = !(files.isEmpty() && binarySourcesForTheNextCompile.isEmpty());
  291. // TODO Andy - Needs some thought here...
  292. // I think here we might want to pass empty addedFiles/deletedFiles as they were
  293. // dealt with on the first call to processDelta - we are going through this loop
  294. // again because in compiling something we found something else we needed to
  295. // rebuild. But what case causes this?
  296. if (hereWeGoAgain) {
  297. if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  298. if (AsmManager.attemptIncrementalModelRepairs) {
  299. state.getStructureModel().processDelta(files, state.getAddedFiles(), state.getDeletedFiles());
  300. }
  301. }
  302. }
  303. }
  304. if (!files.isEmpty()) {
  305. CompilationAndWeavingContext.leavingPhase(ct);
  306. return batchBuild(buildConfig, baseHandler);
  307. } else {
  308. if (AsmManager.isReporting()) {
  309. state.getStructureModel().reportModelInfo("After an incremental build");
  310. }
  311. }
  312. }
  313. // XXX not in Mik's incremental
  314. if (buildConfig.isEmacsSymMode()) {
  315. new org.aspectj.ajdt.internal.core.builder.EmacsStructureModelManager().externalizeModel(state.getStructureModel());
  316. }
  317. // for bug 113554: support ajsym file generation for command line builds
  318. if (buildConfig.isGenerateCrossRefsMode()) {
  319. File configFileProxy = new File(buildConfig.getOutputDir(), CROSSREFS_FILE_NAME);
  320. state.getStructureModel().writeStructureModel(configFileProxy.getAbsolutePath());
  321. }
  322. // have to tell state we succeeded or next is not incremental
  323. state.successfulCompile(buildConfig, isFullBuild);
  324. // For a full compile, copy resources to the destination
  325. // - they should not get deleted on incremental and AJDT
  326. // will handle changes to them that require a recopying
  327. if (isFullBuild) {
  328. copyResourcesToDestination();
  329. }
  330. if (buildConfig.getOutxmlName() != null) {
  331. writeOutxmlFile();
  332. }
  333. /* boolean weaved = */// weaveAndGenerateClassFiles();
  334. // if not weaved, then no-op build, no model changes
  335. // but always returns true
  336. // XXX weaved not in Mik's incremental
  337. if (buildConfig.isGenerateModelMode()) {
  338. state.getStructureModel().fireModelUpdated();
  339. }
  340. CompilationAndWeavingContext.leavingPhase(ct);
  341. } finally {
  342. if (baseHandler instanceof ILifecycleAware) {
  343. ((ILifecycleAware) baseHandler).buildFinished(!isFullBuild);
  344. }
  345. if (zos != null) {
  346. closeOutputStream(buildConfig.getOutputJar());
  347. }
  348. ret = !handler.hasErrors();
  349. if (getBcelWorld() != null) {
  350. BcelWorld bcelWorld = getBcelWorld();
  351. bcelWorld.reportTimers();
  352. bcelWorld.tidyUp();
  353. }
  354. if (getWeaver() != null) {
  355. getWeaver().tidyUp();
  356. // bug 59895, don't release reference to handler as may be needed by a nested call
  357. // handler = null;
  358. }
  359. }
  360. return ret;
  361. }
  362. /**
  363. * Open an output jar file in which to write the compiler output.
  364. *
  365. * @param outJar the jar file to open
  366. * @return true if successful
  367. */
  368. private boolean openOutputStream(File outJar) {
  369. try {
  370. OutputStream os = FileUtil.makeOutputStream(buildConfig.getOutputJar());
  371. zos = new JarOutputStream(os, getWeaver().getManifest(true));
  372. } catch (IOException ex) {
  373. IMessage message = new Message("Unable to open outjar " + outJar.getPath() + "(" + ex.getMessage() + ")",
  374. new SourceLocation(outJar, 0), true);
  375. handler.handleMessage(message);
  376. return false;
  377. }
  378. return true;
  379. }
  380. private void closeOutputStream(File outJar) {
  381. try {
  382. if (zos != null) {
  383. zos.close();
  384. if (buildConfig.getCompilationResultDestinationManager() != null) {
  385. buildConfig.getCompilationResultDestinationManager().reportFileWrite(outJar.getPath(),
  386. CompilationResultDestinationManager.FILETYPE_OUTJAR);
  387. }
  388. }
  389. zos = null;
  390. /* Ensure we don't write an incomplete JAR bug-71339 */
  391. if (handler.hasErrors()) {
  392. outJar.delete();
  393. if (buildConfig.getCompilationResultDestinationManager() != null) {
  394. buildConfig.getCompilationResultDestinationManager().reportFileRemove(outJar.getPath(),
  395. CompilationResultDestinationManager.FILETYPE_OUTJAR);
  396. }
  397. }
  398. } catch (IOException ex) {
  399. IMessage message = new Message("Unable to write outjar " + outJar.getPath() + "(" + ex.getMessage() + ")",
  400. new SourceLocation(outJar, 0), true);
  401. handler.handleMessage(message);
  402. }
  403. }
  404. private void copyResourcesToDestination() throws IOException {
  405. // resources that we need to copy are contained in the injars and inpath only
  406. for (Iterator i = buildConfig.getInJars().iterator(); i.hasNext();) {
  407. File inJar = (File) i.next();
  408. copyResourcesFromJarFile(inJar);
  409. }
  410. for (Iterator i = buildConfig.getInpath().iterator(); i.hasNext();) {
  411. File inPathElement = (File) i.next();
  412. if (inPathElement.isDirectory()) {
  413. copyResourcesFromDirectory(inPathElement);
  414. } else {
  415. copyResourcesFromJarFile(inPathElement);
  416. }
  417. }
  418. if (buildConfig.getSourcePathResources() != null) {
  419. for (Iterator i = buildConfig.getSourcePathResources().keySet().iterator(); i.hasNext();) {
  420. String resource = (String) i.next();
  421. File from = buildConfig.getSourcePathResources().get(resource);
  422. copyResourcesFromFile(from, resource, from);
  423. }
  424. }
  425. writeManifest();
  426. }
  427. private void copyResourcesFromJarFile(File jarFile) throws IOException {
  428. JarInputStream inStream = null;
  429. try {
  430. inStream = new JarInputStream(new FileInputStream(jarFile));
  431. while (true) {
  432. ZipEntry entry = inStream.getNextEntry();
  433. if (entry == null) {
  434. break;
  435. }
  436. String filename = entry.getName();
  437. // System.out.println("? copyResourcesFromJarFile() filename='" + filename +"'");
  438. if (entry.isDirectory()) {
  439. writeDirectory(filename, jarFile);
  440. } else if (acceptResource(filename, false)) {
  441. byte[] bytes = FileUtil.readAsByteArray(inStream);
  442. writeResource(filename, bytes, jarFile);
  443. }
  444. inStream.closeEntry();
  445. }
  446. } finally {
  447. if (inStream != null) {
  448. inStream.close();
  449. }
  450. }
  451. }
  452. private void copyResourcesFromDirectory(File dir) throws IOException {
  453. if (!COPY_INPATH_DIR_RESOURCES) {
  454. return;
  455. }
  456. // Get a list of all files (i.e. everything that isnt a directory)
  457. File[] files = FileUtil.listFiles(dir, new FileFilter() {
  458. public boolean accept(File f) {
  459. boolean accept = !(f.isDirectory() || f.getName().endsWith(".class"));
  460. return accept;
  461. }
  462. });
  463. // For each file, add it either as a real .class file or as a resource
  464. for (int i = 0; i < files.length; i++) {
  465. // ASSERT: files[i].getAbsolutePath().startsWith(inFile.getAbsolutePath()
  466. // or we are in trouble...
  467. String filename = files[i].getAbsolutePath().substring(dir.getAbsolutePath().length() + 1);
  468. copyResourcesFromFile(files[i], filename, dir);
  469. }
  470. }
  471. private void copyResourcesFromFile(File f, String filename, File src) throws IOException {
  472. if (!acceptResource(filename, true)) {
  473. return;
  474. }
  475. FileInputStream fis = null;
  476. try {
  477. fis = new FileInputStream(f);
  478. byte[] bytes = FileUtil.readAsByteArray(fis);
  479. // String relativePath = files[i].getPath();
  480. writeResource(filename, bytes, src);
  481. } catch (FileNotFoundException fnfe) {
  482. // pr359332: looks like the file moved (refactoring?) just as this copy was starting
  483. // that is OK
  484. } finally {
  485. if (fis != null) {
  486. fis.close();
  487. }
  488. }
  489. }
  490. /**
  491. * Add a directory entry to the output zip file. Don't do anything if not writing out to a zip file. A directory entry is one
  492. * whose filename ends with '/'
  493. *
  494. * @param directory the directory path
  495. * @param srcloc the src of the directory entry, for use when creating a warning message
  496. * @throws IOException if something goes wrong creating the new zip entry
  497. */
  498. private void writeDirectory(String directory, File srcloc) throws IOException {
  499. if (state.hasResource(directory)) {
  500. IMessage msg = new Message("duplicate resource: '" + directory + "'", IMessage.WARNING, null, new SourceLocation(
  501. srcloc, 0));
  502. handler.handleMessage(msg);
  503. return;
  504. }
  505. if (zos != null) {
  506. ZipEntry newEntry = new ZipEntry(directory);
  507. zos.putNextEntry(newEntry);
  508. zos.closeEntry();
  509. state.recordResource(directory, srcloc);
  510. }
  511. // Nothing to do if not writing to a zip file
  512. }
  513. private void writeResource(String filename, byte[] content, File srcLocation) throws IOException {
  514. if (state.hasResource(filename)) {
  515. IMessage msg = new Message("duplicate resource: '" + filename + "'", IMessage.WARNING, null, new SourceLocation(
  516. srcLocation, 0));
  517. handler.handleMessage(msg);
  518. return;
  519. }
  520. if (filename.equals(buildConfig.getOutxmlName())) {
  521. ignoreOutxml = true;
  522. IMessage msg = new Message("-outxml/-outxmlfile option ignored because resource already exists: '" + filename + "'",
  523. IMessage.WARNING, null, new SourceLocation(srcLocation, 0));
  524. handler.handleMessage(msg);
  525. }
  526. if (zos != null) {
  527. ZipEntry newEntry = new ZipEntry(filename); // ??? get compression scheme right
  528. zos.putNextEntry(newEntry);
  529. zos.write(content);
  530. zos.closeEntry();
  531. } else {
  532. File destDir = buildConfig.getOutputDir();
  533. if (buildConfig.getCompilationResultDestinationManager() != null) {
  534. destDir = buildConfig.getCompilationResultDestinationManager().getOutputLocationForResource(srcLocation);
  535. }
  536. try {
  537. File outputLocation = new File(destDir, filename);
  538. OutputStream fos = FileUtil.makeOutputStream(outputLocation);
  539. fos.write(content);
  540. fos.close();
  541. if (buildConfig.getCompilationResultDestinationManager() != null) {
  542. buildConfig.getCompilationResultDestinationManager().reportFileWrite(outputLocation.getPath(),
  543. CompilationResultDestinationManager.FILETYPE_RESOURCE);
  544. }
  545. } catch (FileNotFoundException fnfe) {
  546. IMessage msg = new Message("unable to copy resource to output folder: '" + filename + "' - reason: "
  547. + fnfe.getMessage(), IMessage.ERROR, null, new SourceLocation(srcLocation, 0));
  548. handler.handleMessage(msg);
  549. }
  550. }
  551. state.recordResource(filename, srcLocation);
  552. }
  553. /*
  554. * If we are writing to an output directory copy the manifest but only if we already have one
  555. */
  556. private void writeManifest() throws IOException {
  557. Manifest manifest = getWeaver().getManifest(false);
  558. if (manifest != null && zos == null) {
  559. File outputDir = buildConfig.getOutputDir();
  560. if (buildConfig.getCompilationResultDestinationManager() != null) {
  561. // Manifests are only written if we have a jar on the inpath. Therefore,
  562. // we write the manifest to the defaultOutputLocation because this is
  563. // where we sent the classes that were on the inpath
  564. outputDir = buildConfig.getCompilationResultDestinationManager().getDefaultOutputLocation();
  565. }
  566. if (outputDir == null) {
  567. return;
  568. }
  569. File outputLocation = new File(outputDir, MANIFEST_NAME);
  570. OutputStream fos = FileUtil.makeOutputStream(outputLocation);
  571. manifest.write(fos);
  572. fos.close();
  573. if (buildConfig.getCompilationResultDestinationManager() != null) {
  574. buildConfig.getCompilationResultDestinationManager().reportFileWrite(outputLocation.getPath(),
  575. CompilationResultDestinationManager.FILETYPE_RESOURCE);
  576. }
  577. }
  578. }
  579. private boolean acceptResource(String resourceName, boolean fromFile) {
  580. if ((resourceName.startsWith("CVS/")) || (resourceName.indexOf("/CVS/") != -1) || (resourceName.endsWith("/CVS"))
  581. || (resourceName.endsWith(".class")) || (resourceName.startsWith(".svn/"))
  582. || (resourceName.indexOf("/.svn/") != -1) || (resourceName.endsWith("/.svn")) ||
  583. // Do not copy manifests if either they are coming from a jar or we are writing to a jar
  584. (resourceName.toUpperCase().equals(MANIFEST_NAME) && (!fromFile || zos != null))) {
  585. return false;
  586. } else {
  587. return true;
  588. }
  589. }
  590. private void writeOutxmlFile() throws IOException {
  591. if (ignoreOutxml) {
  592. return;
  593. }
  594. String filename = buildConfig.getOutxmlName();
  595. // System.err.println("? AjBuildManager.writeOutxmlFile() outxml=" + filename);
  596. Map<File, List<String>> outputDirsAndAspects = findOutputDirsForAspects();
  597. Set<Map.Entry<File, List<String>>> outputDirs = outputDirsAndAspects.entrySet();
  598. for (Iterator<Map.Entry<File, List<String>>> iterator = outputDirs.iterator(); iterator.hasNext();) {
  599. Map.Entry<File, List<String>> entry = iterator.next();
  600. File outputDir = entry.getKey();
  601. List<String> aspects = entry.getValue();
  602. ByteArrayOutputStream baos = getOutxmlContents(aspects);
  603. if (zos != null) {
  604. ZipEntry newEntry = new ZipEntry(filename);
  605. zos.putNextEntry(newEntry);
  606. zos.write(baos.toByteArray());
  607. zos.closeEntry();
  608. } else {
  609. File outputFile = new File(outputDir, filename);
  610. OutputStream fos = FileUtil.makeOutputStream(outputFile);
  611. fos.write(baos.toByteArray());
  612. fos.close();
  613. if (buildConfig.getCompilationResultDestinationManager() != null) {
  614. buildConfig.getCompilationResultDestinationManager().reportFileWrite(outputFile.getPath(),
  615. CompilationResultDestinationManager.FILETYPE_RESOURCE);
  616. }
  617. }
  618. }
  619. }
  620. private ByteArrayOutputStream getOutxmlContents(List aspectNames) {
  621. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  622. PrintStream ps = new PrintStream(baos);
  623. ps.println("<aspectj>");
  624. ps.println("<aspects>");
  625. if (aspectNames != null) {
  626. for (Iterator i = aspectNames.iterator(); i.hasNext();) {
  627. String name = (String) i.next();
  628. ps.println("<aspect name=\"" + name + "\"/>");
  629. }
  630. }
  631. ps.println("</aspects>");
  632. ps.println("</aspectj>");
  633. ps.println();
  634. ps.close();
  635. return baos;
  636. }
  637. /**
  638. * Returns a map where the keys are File objects corresponding to all the output directories and the values are a list of
  639. * aspects which are sent to that ouptut directory
  640. */
  641. private Map<File, List<String>> findOutputDirsForAspects() {
  642. Map<File, List<String>> outputDirsToAspects = new HashMap<File, List<String>>();
  643. Map<String, char[]> aspectNamesToFileNames = state.getAspectNamesToFileNameMap();
  644. if (buildConfig.getCompilationResultDestinationManager() == null
  645. || buildConfig.getCompilationResultDestinationManager().getAllOutputLocations().size() == 1) {
  646. // we only have one output directory...which simplifies things
  647. File outputDir = buildConfig.getOutputDir();
  648. if (buildConfig.getCompilationResultDestinationManager() != null) {
  649. outputDir = buildConfig.getCompilationResultDestinationManager().getDefaultOutputLocation();
  650. }
  651. List<String> aspectNames = new ArrayList<String>();
  652. if (aspectNamesToFileNames != null) {
  653. Set<String> keys = aspectNamesToFileNames.keySet();
  654. for (String name : keys) {
  655. aspectNames.add(name);
  656. }
  657. }
  658. outputDirsToAspects.put(outputDir, aspectNames);
  659. } else {
  660. List outputDirs = buildConfig.getCompilationResultDestinationManager().getAllOutputLocations();
  661. for (Iterator iterator = outputDirs.iterator(); iterator.hasNext();) {
  662. File outputDir = (File) iterator.next();
  663. outputDirsToAspects.put(outputDir, new ArrayList<String>());
  664. }
  665. if (aspectNamesToFileNames != null) {
  666. Set<Map.Entry<String, char[]>> entrySet = aspectNamesToFileNames.entrySet();
  667. for (Iterator<Map.Entry<String, char[]>> iterator = entrySet.iterator(); iterator.hasNext();) {
  668. Map.Entry<String, char[]> entry = iterator.next();
  669. String aspectName = entry.getKey();
  670. char[] fileName = entry.getValue();
  671. File outputDir = buildConfig.getCompilationResultDestinationManager().getOutputLocationForClass(
  672. new File(new String(fileName)));
  673. if (!outputDirsToAspects.containsKey(outputDir)) {
  674. outputDirsToAspects.put(outputDir, new ArrayList<String>());
  675. }
  676. ((List) outputDirsToAspects.get(outputDir)).add(aspectName);
  677. }
  678. }
  679. }
  680. return outputDirsToAspects;
  681. }
  682. // public static void dumprels() {
  683. // IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
  684. // int ctr = 1;
  685. // Set entries = irm.getEntries();
  686. // for (Iterator iter = entries.iterator(); iter.hasNext();) {
  687. // String hid = (String) iter.next();
  688. // List rels = irm.get(hid);
  689. // for (Iterator iterator = rels.iterator(); iterator.hasNext();) {
  690. // IRelationship ir = (IRelationship) iterator.next();
  691. // List targets = ir.getTargets();
  692. // for (Iterator iterator2 = targets.iterator();
  693. // iterator2.hasNext();
  694. // ) {
  695. // String thid = (String) iterator2.next();
  696. // System.err.println("Hid:"+(ctr++)+":(targets="+targets.size()+") "+hid+" ("+ir.getName()+") "+thid);
  697. // }
  698. // }
  699. // }
  700. // }
  701. /**
  702. * Responsible for managing the ASM model between builds. Contains the policy for maintaining the persistance of elements in the
  703. * model.
  704. *
  705. * This code is driven before each 'fresh' (batch) build to create a new model.
  706. */
  707. private void setupModel(AjBuildConfig config) {
  708. if (!(config.isEmacsSymMode() || config.isGenerateModelMode())) {
  709. return;
  710. }
  711. // AsmManager.setCreatingModel(config.isEmacsSymMode() || config.isGenerateModelMode());
  712. // if (!AsmManager.isCreatingModel())
  713. // return;
  714. CompilationResultDestinationManager crdm = config.getCompilationResultDestinationManager();
  715. AsmManager structureModel = AsmManager.createNewStructureModel(crdm == null ? Collections.EMPTY_MAP : crdm.getInpathMap());
  716. // AsmManager.getDefault().getRelationshipMap().clear();
  717. IHierarchy model = structureModel.getHierarchy();
  718. String rootLabel = "<root>";
  719. IProgramElement.Kind kind = IProgramElement.Kind.FILE_JAVA;
  720. if (buildConfig.getConfigFile() != null) {
  721. rootLabel = buildConfig.getConfigFile().getName();
  722. model.setConfigFile(buildConfig.getConfigFile().getAbsolutePath());
  723. kind = IProgramElement.Kind.FILE_LST;
  724. }
  725. model.setRoot(new ProgramElement(structureModel, rootLabel, kind, new ArrayList()));
  726. model.setFileMap(new HashMap<String, IProgramElement>());
  727. // setStructureModel(model);
  728. state.setStructureModel(structureModel);
  729. // state.setRelationshipMap(AsmManager.getDefault().getRelationshipMap());
  730. }
  731. //
  732. // private void dumplist(List l) {
  733. // System.err.println("---- "+l.size());
  734. // for (int i =0 ;i<l.size();i++) System.err.println(i+"\t "+l.get(i));
  735. // }
  736. // private void accumulateFileNodes(IProgramElement ipe,List store) {
  737. // if (ipe.getKind()==IProgramElement.Kind.FILE_JAVA ||
  738. // ipe.getKind()==IProgramElement.Kind.FILE_ASPECTJ) {
  739. // if (!ipe.getName().equals("<root>")) {
  740. // store.add(ipe);
  741. // return;
  742. // }
  743. // }
  744. // for (Iterator i = ipe.getChildren().iterator();i.hasNext();) {
  745. // accumulateFileNodes((IProgramElement)i.next(),store);
  746. // }
  747. // }
  748. // LTODO delegate to BcelWeaver?
  749. // XXX hideous, should not be Object
  750. public void setCustomMungerFactory(Object o) {
  751. customMungerFactory = (CustomMungerFactory) o;
  752. }
  753. public Object getCustomMungerFactory() {
  754. return customMungerFactory;
  755. }
  756. /** init only on initial batch compile? no file-specific options */
  757. private void initBcelWorld(IMessageHandler handler) throws IOException {
  758. List cp = buildConfig.getFullClasspath(); // pr145693
  759. // buildConfig.getBootclasspath();
  760. // cp.addAll(buildConfig.getClasspath());
  761. BcelWorld bcelWorld = new BcelWorld(cp, handler, null);
  762. bcelWorld.setBehaveInJava5Way(buildConfig.getBehaveInJava5Way());
  763. bcelWorld.setTiming(buildConfig.isTiming(), false);
  764. bcelWorld.setAddSerialVerUID(buildConfig.isAddSerialVerUID());
  765. bcelWorld.setXmlConfigured(buildConfig.isXmlConfigured());
  766. bcelWorld.setXmlFiles(buildConfig.getXmlFiles());
  767. bcelWorld.performExtraConfiguration(buildConfig.getXconfigurationInfo());
  768. bcelWorld.setTargetAspectjRuntimeLevel(buildConfig.getTargetAspectjRuntimeLevel());
  769. bcelWorld.setOptionalJoinpoints(buildConfig.getXJoinpoints());
  770. bcelWorld.setXnoInline(buildConfig.isXnoInline());
  771. bcelWorld.setXlazyTjp(buildConfig.isXlazyTjp());
  772. bcelWorld.setXHasMemberSupportEnabled(buildConfig.isXHasMemberEnabled());
  773. bcelWorld.setPinpointMode(buildConfig.isXdevPinpoint());
  774. bcelWorld.setErrorAndWarningThreshold(buildConfig.getOptions().errorThreshold.isSet(24), buildConfig.getOptions().warningThreshold.isSet(24));
  775. BcelWeaver bcelWeaver = new BcelWeaver(bcelWorld);
  776. bcelWeaver.setCustomMungerFactory(customMungerFactory);
  777. state.setWorld(bcelWorld);
  778. state.setWeaver(bcelWeaver);
  779. state.clearBinarySourceFiles();
  780. if (buildConfig.getLintMode().equals(AjBuildConfig.AJLINT_DEFAULT)) {
  781. bcelWorld.getLint().loadDefaultProperties();
  782. } else {
  783. bcelWorld.getLint().setAll(buildConfig.getLintMode());
  784. }
  785. if (buildConfig.getLintSpecFile() != null) {
  786. bcelWorld.getLint().setFromProperties(buildConfig.getLintSpecFile());
  787. }
  788. for (Iterator i = buildConfig.getAspectpath().iterator(); i.hasNext();) {
  789. File f = (File) i.next();
  790. if (!f.exists()) {
  791. IMessage message = new Message("invalid aspectpath entry: " + f.getName(), null, true);
  792. handler.handleMessage(message);
  793. } else {
  794. bcelWeaver.addLibraryJarFile(f);
  795. }
  796. }
  797. // String lintMode = buildConfig.getLintMode();
  798. File outputDir = buildConfig.getOutputDir();
  799. if (outputDir == null && buildConfig.getCompilationResultDestinationManager() != null) {
  800. // send all output from injars and inpath to the default output location
  801. // (will also later send the manifest there too)
  802. outputDir = buildConfig.getCompilationResultDestinationManager().getDefaultOutputLocation();
  803. }
  804. // ??? incremental issues
  805. for (File inJar : buildConfig.getInJars()) {
  806. List<UnwovenClassFile> unwovenClasses = bcelWeaver.addJarFile(inJar, outputDir, false);
  807. state.recordBinarySource(inJar.getPath(), unwovenClasses);
  808. }
  809. for (File inPathElement : buildConfig.getInpath()) {
  810. if (!inPathElement.isDirectory()) {
  811. // its a jar file on the inpath
  812. // the weaver method can actually handle dirs, but we don't call it, see next block
  813. List<UnwovenClassFile> unwovenClasses = bcelWeaver.addJarFile(inPathElement, outputDir, true);
  814. state.recordBinarySource(inPathElement.getPath(), unwovenClasses);
  815. } else {
  816. // add each class file in an in-dir individually, this gives us the best error reporting
  817. // (they are like 'source' files then), and enables a cleaner incremental treatment of
  818. // class file changes in indirs.
  819. File[] binSrcs = FileUtil.listFiles(inPathElement, binarySourceFilter);
  820. for (int j = 0; j < binSrcs.length; j++) {
  821. UnwovenClassFile ucf = bcelWeaver.addClassFile(binSrcs[j], inPathElement, outputDir);
  822. List<UnwovenClassFile> ucfl = new ArrayList<UnwovenClassFile>();
  823. ucfl.add(ucf);
  824. state.recordBinarySource(binSrcs[j].getPath(), ucfl);
  825. }
  826. }
  827. }
  828. bcelWeaver.setReweavableMode(buildConfig.isXNotReweavable());
  829. // check for org.aspectj.runtime.JoinPoint
  830. ResolvedType joinPoint = bcelWorld.resolve("org.aspectj.lang.JoinPoint");
  831. if (joinPoint.isMissing()) {
  832. IMessage message = new Message(
  833. "classpath error: unable to find org.aspectj.lang.JoinPoint (check that aspectjrt.jar is in your classpath)",
  834. null, true);
  835. handler.handleMessage(message);
  836. }
  837. }
  838. public World getWorld() {
  839. return getBcelWorld();
  840. }
  841. // void addAspectClassFilesToWeaver(List addedClassFiles) throws IOException {
  842. // for (Iterator i = addedClassFiles.iterator(); i.hasNext();) {
  843. // UnwovenClassFile classFile = (UnwovenClassFile) i.next();
  844. // getWeaver().addClassFile(classFile);
  845. // }
  846. // }
  847. public FileSystem getLibraryAccess(String[] classpaths, String[] filenames) {
  848. String defaultEncoding = buildConfig.getOptions().defaultEncoding;
  849. if ("".equals(defaultEncoding)) {//$NON-NLS-1$
  850. defaultEncoding = null;
  851. }
  852. // Bug 46671: We need an array as long as the number of elements in the classpath - *even though* not every
  853. // element of the classpath is likely to be a directory. If we ensure every element of the array is set to
  854. // only look for BINARY, then we make sure that for any classpath element that is a directory, we won't build
  855. // a classpathDirectory object that will attempt to look for source when it can't find binary.
  856. // int[] classpathModes = new int[classpaths.length];
  857. // for (int i =0 ;i<classpaths.length;i++) classpathModes[i]=ClasspathDirectory.BINARY;
  858. return new FileSystem(classpaths, filenames, defaultEncoding, ClasspathLocation.BINARY);
  859. }
  860. public IProblemFactory getProblemFactory() {
  861. return new DefaultProblemFactory(Locale.getDefault());
  862. }
  863. /*
  864. * Build the set of compilation source units
  865. */
  866. public CompilationUnit[] getCompilationUnits(String[] filenames) {
  867. int fileCount = filenames.length;
  868. CompilationUnit[] units = new CompilationUnit[fileCount];
  869. // HashtableOfObject knownFileNames = new HashtableOfObject(fileCount);
  870. String defaultEncoding = buildConfig.getOptions().defaultEncoding;
  871. if ("".equals(defaultEncoding)) {//$NON-NLS-1$
  872. defaultEncoding = null;
  873. }
  874. for (int i = 0; i < fileCount; i++) {
  875. units[i] = new CompilationUnit(null, filenames[i], defaultEncoding);
  876. }
  877. return units;
  878. }
  879. public String extractDestinationPathFromSourceFile(CompilationResult result) {
  880. ICompilationUnit compilationUnit = result.compilationUnit;
  881. if (compilationUnit != null) {
  882. char[] fileName = compilationUnit.getFileName();
  883. int lastIndex = CharOperation.lastIndexOf(java.io.File.separatorChar, fileName);
  884. if (lastIndex == -1) {
  885. return System.getProperty("user.dir"); //$NON-NLS-1$
  886. }
  887. return new String(CharOperation.subarray(fileName, 0, lastIndex));
  888. }
  889. return System.getProperty("user.dir"); //$NON-NLS-1$
  890. }
  891. public void performCompilation(Collection<File> files) {
  892. if (progressListener != null) {
  893. compiledCount = 0;
  894. sourceFileCount = files.size();
  895. progressListener.setText("compiling source files");
  896. }
  897. // Translate from strings to File objects
  898. String[] filenames = new String[files.size()];
  899. int idx = 0;
  900. for (Iterator<File> fIterator = files.iterator(); fIterator.hasNext();) {
  901. File f = fIterator.next();
  902. filenames[idx++] = f.getPath();
  903. }
  904. environment = state.getNameEnvironment();
  905. boolean environmentNeedsRebuilding = false;
  906. // Might be a bit too cautious, but let us see how it goes
  907. if (buildConfig.getChanged() != AjBuildConfig.NO_CHANGES) {
  908. environmentNeedsRebuilding = true;
  909. }
  910. if (environment == null || environmentNeedsRebuilding) {
  911. List<String> cps = buildConfig.getFullClasspath();
  912. Dump.saveFullClasspath(cps);
  913. String[] classpaths = new String[cps.size()];
  914. for (int i = 0; i < cps.size(); i++) {
  915. classpaths[i] = cps.get(i);
  916. }
  917. environment = new StatefulNameEnvironment(getLibraryAccess(classpaths, filenames), state.getClassNameToFileMap(), state);
  918. state.setNameEnvironment(environment);
  919. } else {
  920. ((StatefulNameEnvironment) environment).update(state.getClassNameToFileMap(), state.deltaAddedClasses);
  921. state.deltaAddedClasses.clear();
  922. }
  923. org.aspectj.ajdt.internal.compiler.CompilerAdapter.setCompilerAdapterFactory(this);
  924. org.aspectj.org.eclipse.jdt.internal.compiler.Compiler compiler = new org.aspectj.org.eclipse.jdt.internal.compiler.Compiler(
  925. environment, DefaultErrorHandlingPolicies.proceedWithAllProblems(), buildConfig.getOptions().getMap(),
  926. getBatchRequestor(), getProblemFactory());
  927. compiler.options.produceReferenceInfo = true; // TODO turn off when not needed
  928. try {
  929. compiler.compile(getCompilationUnits(filenames));
  930. } catch (OperationCanceledException oce) {
  931. handler.handleMessage(new Message("build cancelled:" + oce.getMessage(), IMessage.WARNING, null, null));
  932. }
  933. // cleanup
  934. org.aspectj.ajdt.internal.compiler.CompilerAdapter.setCompilerAdapterFactory(null);
  935. AnonymousClassPublisher.aspectOf().setAnonymousClassCreationListener(null);
  936. environment.cleanup();
  937. // environment = null;
  938. }
  939. public void cleanupEnvironment() {
  940. if (environment != null) {
  941. environment.cleanup();
  942. environment = null;
  943. // le = null;
  944. }
  945. }
  946. /*
  947. * Answer the component to which will be handed back compilation results from the compiler
  948. */
  949. public IIntermediateResultsRequestor getInterimResultRequestor() {
  950. return new IIntermediateResultsRequestor() {
  951. public void acceptResult(InterimCompilationResult result) {
  952. if (progressListener != null) {
  953. compiledCount++;
  954. progressListener.setProgress((compiledCount / 2.0) / sourceFileCount);
  955. progressListener.setText("compiled: " + result.fileName());
  956. }
  957. state.noteResult(result);
  958. if (progressListener != null && progressListener.isCancelledRequested()) {
  959. throw new AbortCompilation(true, new OperationCanceledException("Compilation cancelled as requested"));
  960. }
  961. }
  962. };
  963. }
  964. public ICompilerRequestor getBatchRequestor() {
  965. return new ICompilerRequestor() {
  966. public void acceptResult(CompilationResult unitResult) {
  967. // end of compile, must now write the results to the output destination
  968. // this is either a jar file or a file in a directory
  969. boolean hasErrors = unitResult.hasErrors();
  970. if (!hasErrors || proceedOnError()) {
  971. Collection<ClassFile> classFiles = unitResult.compiledTypes.values();
  972. boolean shouldAddAspectName = (buildConfig.getOutxmlName() != null);
  973. for (Iterator<ClassFile> iter = classFiles.iterator(); iter.hasNext();) {
  974. ClassFile classFile = iter.next();
  975. String filename = new String(classFile.fileName());
  976. String classname = filename.replace('/', '.');
  977. filename = filename.replace('/', File.separatorChar) + ".class";
  978. try {
  979. if (buildConfig.getOutputJar() == null) {
  980. String outfile = writeDirectoryEntry(unitResult, classFile, filename);
  981. getWorld().classWriteEvent(classFile.getCompoundName());
  982. if (environmentSupportsIncrementalCompilation) {
  983. if (!classname.endsWith("$ajcMightHaveAspect")) {
  984. ResolvedType type = getBcelWorld().resolve(classname);
  985. if (type.isAspect()) {
  986. state.recordAspectClassFile(outfile);
  987. }
  988. }
  989. }
  990. } else {
  991. writeZipEntry(classFile, filename);
  992. }
  993. if (shouldAddAspectName && !classname.endsWith("$ajcMightHaveAspect")) {
  994. addAspectName(classname, unitResult.getFileName());
  995. }
  996. } catch (IOException ex) {
  997. IMessage message = EclipseAdapterUtils.makeErrorMessage(new String(unitResult.fileName),
  998. CANT_WRITE_RESULT, ex);
  999. handler.handleMessage(message);
  1000. }
  1001. }
  1002. state.noteNewResult(unitResult);
  1003. unitResult.compiledTypes.clear(); // free up references to AjClassFile instances
  1004. }
  1005. if (unitResult.hasProblems() || unitResult.hasTasks()) {
  1006. IProblem[] problems = unitResult.getAllProblems();
  1007. for (int i = 0; i < problems.length; i++) {
  1008. IMessage message = EclipseAdapterUtils.makeMessage(unitResult.compilationUnit, problems[i], getBcelWorld(),
  1009. progressListener);
  1010. handler.handleMessage(message);
  1011. }
  1012. }
  1013. }
  1014. private String writeDirectoryEntry(CompilationResult unitResult, ClassFile classFile, String filename)
  1015. throws IOException {
  1016. File destinationPath = buildConfig.getOutputDir();
  1017. if (buildConfig.getCompilationResultDestinationManager() != null) {
  1018. destinationPath = buildConfig.getCompilationResultDestinationManager().getOutputLocationForClass(
  1019. new File(new String(unitResult.fileName)));
  1020. }
  1021. String outFile;
  1022. if (destinationPath == null) {
  1023. outFile = new File(filename).getName();
  1024. outFile = new File(extractDestinationPathFromSourceFile(unitResult), outFile).getPath();
  1025. } else {
  1026. outFile = new File(destinationPath, filename).getPath();
  1027. }
  1028. try {
  1029. BufferedOutputStream os = FileUtil.makeOutputStream(new File(outFile));
  1030. os.write(classFile.getBytes());
  1031. os.close();
  1032. } catch (FileNotFoundException fnfe) {
  1033. IMessage msg = new Message("unable to write out class file: '" + filename + "' - reason: " + fnfe.getMessage(),
  1034. IMessage.ERROR, null, new SourceLocation(new File(outFile), 0));
  1035. handler.handleMessage(msg);
  1036. }
  1037. if (buildConfig.getCompilationResultDestinationManager() != null) {
  1038. buildConfig.getCompilationResultDestinationManager().reportFileWrite(outFile,
  1039. CompilationResultDestinationManager.FILETYPE_CLASS);
  1040. }
  1041. return outFile;
  1042. }
  1043. private void writeZipEntry(ClassFile classFile, String name) throws IOException {
  1044. name = name.replace(File.separatorChar, '/');
  1045. ZipEntry newEntry = new ZipEntry(name); // ??? get compression scheme right
  1046. zos.putNextEntry(newEntry);
  1047. zos.write(classFile.getBytes());
  1048. zos.closeEntry();
  1049. }
  1050. private void addAspectName(String name, char[] fileContainingAspect) {
  1051. BcelWorld world = getBcelWorld();
  1052. ResolvedType type = world.resolve(name);
  1053. // System.err.println("? writeAspectName() type=" + type);
  1054. if (type.isAspect()) {
  1055. if (state.getAspectNamesToFileNameMap() == null) {
  1056. state.initializeAspectNamesToFileNameMap();
  1057. }
  1058. if (!state.getAspectNamesToFileNameMap().containsKey(name)) {
  1059. state.getAspectNamesToFileNameMap().put(name, fileContainingAspect);
  1060. }
  1061. }
  1062. }
  1063. };
  1064. }
  1065. protected boolean proceedOnError() {
  1066. return buildConfig.getProceedOnError();
  1067. }
  1068. // public void noteClassFiles(AjCompiler.InterimResult result) {
  1069. // if (result == null) return;
  1070. // CompilationResult unitResult = result.result;
  1071. // String sourceFileName = result.fileName();
  1072. // if (!(unitResult.hasErrors() && !proceedOnError())) {
  1073. // List unwovenClassFiles = new ArrayList();
  1074. // Enumeration classFiles = unitResult.compiledTypes.elements();
  1075. // while (classFiles.hasMoreElements()) {
  1076. // ClassFile classFile = (ClassFile) classFiles.nextElement();
  1077. // String filename = new String(classFile.fileName());
  1078. // filename = filename.replace('/', File.separatorChar) + ".class";
  1079. //
  1080. // File destinationPath = buildConfig.getOutputDir();
  1081. // if (destinationPath == null) {
  1082. // filename = new File(filename).getName();
  1083. // filename = new File(extractDestinationPathFromSourceFile(unitResult), filename).getPath();
  1084. // } else {
  1085. // filename = new File(destinationPath, filename).getPath();
  1086. // }
  1087. //
  1088. // //System.out.println("classfile: " + filename);
  1089. // unwovenClassFiles.add(new UnwovenClassFile(filename, classFile.getBytes()));
  1090. // }
  1091. // state.noteClassesFromFile(unitResult, sourceFileName, unwovenClassFiles);
  1092. // // System.out.println("file: " + sourceFileName);
  1093. // // for (int i=0; i < unitResult.simpleNameReferences.length; i++) {
  1094. // // System.out.println("simple: " + new String(unitResult.simpleNameReferences[i]));
  1095. // // }
  1096. // // for (int i=0; i < unitResult.qualifiedReferences.length; i++) {
  1097. // // System.out.println("qualified: " +
  1098. // // new String(CharOperation.concatWith(unitResult.qualifiedReferences[i], '/')));
  1099. // // }
  1100. // } else {
  1101. // state.noteClassesFromFile(null, sourceFileName, Collections.EMPTY_LIST);
  1102. // }
  1103. // }
  1104. //
  1105. private void setBuildConfig(AjBuildConfig buildConfig) {
  1106. this.buildConfig = buildConfig;
  1107. if (!this.environmentSupportsIncrementalCompilation) {
  1108. this.environmentSupportsIncrementalCompilation = (buildConfig.isIncrementalMode() || buildConfig
  1109. .isIncrementalFileMode());
  1110. }
  1111. handler.reset();
  1112. }
  1113. String makeClasspathString(AjBuildConfig buildConfig) {
  1114. if (buildConfig == null || buildConfig.getFullClasspath() == null) {
  1115. return "";
  1116. }
  1117. StringBuffer buf = new StringBuffer();
  1118. boolean first = true;
  1119. for (Iterator it = buildConfig.getFullClasspath().iterator(); it.hasNext();) {
  1120. if (first) {
  1121. first = false;
  1122. } else {
  1123. buf.append(File.pathSeparator);
  1124. }
  1125. buf.append(it.next().toString());
  1126. }
  1127. return buf.toString();
  1128. }
  1129. /**
  1130. * This will return null if aspectjrt.jar is present and has the correct version. Otherwise it will return a string message
  1131. * indicating the problem.
  1132. */
  1133. private String checkRtJar(AjBuildConfig buildConfig) {
  1134. // omitting dev info
  1135. if (Version.text.equals(Version.DEVELOPMENT)) {
  1136. // in the development version we can't do this test usefully
  1137. // MessageUtil.info(holder, "running development version of aspectj compiler");
  1138. return null;
  1139. }
  1140. if (buildConfig == null || buildConfig.getFullClasspath() == null) {
  1141. return "no classpath specified";
  1142. }
  1143. String ret = null;
  1144. for (Iterator it = buildConfig.getFullClasspath().iterator(); it.hasNext();) {
  1145. File p = new File((String) it.next());
  1146. // pr112830, allow variations on aspectjrt.jar of the form aspectjrtXXXXXX.jar
  1147. if (p.isFile() && p.getName().startsWith("aspectjrt") && p.getName().endsWith(".jar")) {
  1148. try {
  1149. String version = null;
  1150. Manifest manifest = new JarFile(p).getManifest();
  1151. if (manifest == null) {
  1152. ret = "no manifest found in " + p.getAbsolutePath() + ", expected " + Version.text;
  1153. continue;
  1154. }
  1155. Attributes attr = manifest.getAttributes("org/aspectj/lang/");
  1156. if (null != attr) {
  1157. version = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
  1158. if (null != version) {
  1159. version = version.trim();
  1160. }
  1161. }
  1162. // assume that users of development aspectjrt.jar know what they're doing
  1163. if (Version.DEVELOPMENT.equals(version)) {
  1164. // MessageUtil.info(holder,
  1165. // "running with development version of aspectjrt.jar in " +
  1166. // p.getAbsolutePath());
  1167. return null;
  1168. } else if (!Version.text.equals(version)) {
  1169. ret = "bad version number found in " + p.getAbsolutePath() + " expected " + Version.text + " found "
  1170. + version;
  1171. continue;
  1172. }
  1173. } catch (IOException ioe) {
  1174. ret = "bad jar file found in " + p.getAbsolutePath() + " error: " + ioe;
  1175. }
  1176. return null; // this is the "OK" return value!
  1177. } else if (p.isFile() && p.getName().indexOf("org.aspectj.runtime") != -1) {
  1178. // likely to be a variant from the springsource bundle repo b272591
  1179. return null;
  1180. } else {
  1181. // might want to catch other classpath errors
  1182. }
  1183. }
  1184. if (ret != null) {
  1185. return ret; // last error found in potentially matching jars...
  1186. }
  1187. return "couldn't find aspectjrt.jar on classpath, checked: " + makeClasspathString(buildConfig);
  1188. }
  1189. public String toString() {
  1190. StringBuffer buf = new StringBuffer();
  1191. buf.append("AjBuildManager(");
  1192. buf.append(")");
  1193. return buf.toString();
  1194. }
  1195. //
  1196. // public void setStructureModel(IHierarchy structureModel) {
  1197. // this.structureModel = structureModel;
  1198. // }
  1199. /**
  1200. * Returns null if there is no structure model
  1201. */
  1202. public AsmManager getStructureModel() {
  1203. return (state == null ? null : state.getStructureModel());
  1204. }
  1205. public IProgressListener getProgressListener() {
  1206. return progressListener;
  1207. }
  1208. public void setProgressListener(IProgressListener progressListener) {
  1209. this.progressListener = progressListener;
  1210. }
  1211. /*
  1212. * (non-Javadoc)
  1213. *
  1214. * @see org.aspectj.ajdt.internal.compiler.AjCompiler.IOutputClassFileNameProvider#getOutputClassFileName(char[])
  1215. */
  1216. public String getOutputClassFileName(char[] eclipseClassFileName, CompilationResult result) {
  1217. String filename = new String(eclipseClassFileName);
  1218. filename = filename.replace('/', File.separatorChar) + ".class";
  1219. File destinationPath = buildConfig.getOutputDir();
  1220. if (buildConfig.getCompilationResultDestinationManager() != null) {
  1221. File f = new File(new String(result.getFileName()));
  1222. destinationPath = buildConfig.getCompilationResultDestinationManager().getOutputLocationForClass(f);
  1223. }
  1224. String outFile;
  1225. if (destinationPath == null) {
  1226. outFile = new File(filename).getName();
  1227. outFile = new File(extractDestinationPathFromSourceFile(result), outFile).getPath();
  1228. } else {
  1229. outFile = new File(destinationPath, filename).getPath();
  1230. }
  1231. return outFile;
  1232. }
  1233. /*
  1234. * (non-Javadoc)
  1235. *
  1236. * @see org.eclipse.jdt.internal.compiler.ICompilerAdapterFactory#getAdapter(org.eclipse.jdt.internal.compiler.Compiler)
  1237. */
  1238. public ICompilerAdapter getAdapter(org.aspectj.org.eclipse.jdt.internal.compiler.Compiler forCompiler) {
  1239. // complete compiler config and return a suitable adapter...
  1240. populateCompilerOptionsFromLintSettings(forCompiler);
  1241. AjProblemReporter pr = new AjProblemReporter(DefaultErrorHandlingPolicies.proceedWithAllProblems(), forCompiler.options,
  1242. getProblemFactory());
  1243. forCompiler.problemReporter = pr;
  1244. AjLookupEnvironment le = new AjLookupEnvironment(forCompiler, forCompiler.options, pr, environment);
  1245. EclipseFactory factory = new EclipseFactory(le, this);
  1246. le.factory = factory;
  1247. pr.factory = factory;
  1248. forCompiler.lookupEnvironment = le;
  1249. forCompiler.parser = new Parser(pr, forCompiler.options.parseLiteralExpressionsAsConstants);
  1250. if (getBcelWorld().shouldPipelineCompilation()) {
  1251. IMessage message = MessageUtil.info("Pipelining compilation");
  1252. handler.handleMessage(message);
  1253. return new AjPipeliningCompilerAdapter(forCompiler, batchCompile, getBcelWorld(), getWeaver(), factory,
  1254. getInterimResultRequestor(), progressListener,
  1255. this, // IOutputFilenameProvider
  1256. this, // IBinarySourceProvider
  1257. state.getBinarySourceMap(), buildConfig.isTerminateAfterCompilation(), buildConfig.getProceedOnError(),
  1258. buildConfig.isNoAtAspectJAnnotationProcessing(), buildConfig.isMakeReflectable(), state);
  1259. } else {
  1260. return new AjCompilerAdapter(forCompiler, batchCompile, getBcelWorld(), getWeaver(), factory,
  1261. getInterimResultRequestor(), progressListener,
  1262. this, // IOutputFilenameProvider
  1263. this, // IBinarySourceProvider
  1264. state.getBinarySourceMap(), buildConfig.isTerminateAfterCompilation(), buildConfig.getProceedOnError(),
  1265. buildConfig.isNoAtAspectJAnnotationProcessing(), buildConfig.isMakeReflectable(), state);
  1266. }
  1267. }
  1268. /**
  1269. * Some AspectJ lint options need to be known about in the compiler. This is how we pass them over...
  1270. *
  1271. * @param forCompiler
  1272. */
  1273. private void populateCompilerOptionsFromLintSettings(org.aspectj.org.eclipse.jdt.internal.compiler.Compiler forCompiler) {
  1274. BcelWorld world = this.state.getBcelWorld();
  1275. IMessage.Kind swallowedExceptionKind = world.getLint().swallowedExceptionInCatchBlock.getKind();
  1276. Map optionsMap = new HashMap();
  1277. optionsMap.put(CompilerOptions.OPTION_ReportSwallowedExceptionInCatchBlock, swallowedExceptionKind == null ? "ignore"
  1278. : swallowedExceptionKind.toString());
  1279. forCompiler.options.set(optionsMap);
  1280. }
  1281. /*
  1282. * (non-Javadoc)
  1283. *
  1284. * @see org.aspectj.ajdt.internal.compiler.IBinarySourceProvider#getBinarySourcesForThisWeave()
  1285. */
  1286. public Map getBinarySourcesForThisWeave() {
  1287. return binarySourcesForTheNextCompile;
  1288. }
  1289. public static AsmHierarchyBuilder getAsmHierarchyBuilder() {
  1290. return asmHierarchyBuilder;
  1291. }
  1292. /**
  1293. * Override the the default hierarchy builder.
  1294. */
  1295. public static void setAsmHierarchyBuilder(AsmHierarchyBuilder newBuilder) {
  1296. asmHierarchyBuilder = newBuilder;
  1297. }
  1298. public AjState getState() {
  1299. return state;
  1300. }
  1301. public void setState(AjState buildState) {
  1302. state = buildState;
  1303. }
  1304. private static class AjBuildContexFormatter implements ContextFormatter {
  1305. public String formatEntry(int phaseId, Object data) {
  1306. StringBuffer sb = new StringBuffer();
  1307. if (phaseId == CompilationAndWeavingContext.BATCH_BUILD) {
  1308. sb.append("batch building ");
  1309. } else {
  1310. sb.append("incrementally building ");
  1311. }
  1312. AjBuildConfig config = (AjBuildConfig) data;
  1313. List classpath = config.getClasspath();
  1314. sb.append("with classpath: ");
  1315. for (Iterator iter = classpath.iterator(); iter.hasNext();) {
  1316. sb.append(iter.next().toString());
  1317. sb.append(File.pathSeparator);
  1318. }
  1319. return sb.toString();
  1320. }
  1321. }
  1322. public boolean wasFullBuild() {
  1323. return wasFullBuild;
  1324. }
  1325. }