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

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