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 60KB

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