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.

AspectJBuildManager.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /* *******************************************************************
  2. * Copyright (c) 1999-2001 Xerox Corporation,
  3. * 2002 Palo Alto Research Center, Incorporated (PARC).
  4. * All rights reserved.
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Common Public License v1.0
  7. * which accompanies this distribution and is available at
  8. * http://www.eclipse.org/legal/cpl-v10.html
  9. *
  10. * Contributors:
  11. * Xerox/PARC initial implementation
  12. * ******************************************************************/
  13. package org.aspectj.ajde.internal;
  14. import java.io.*;
  15. import java.util.*;
  16. import org.aspectj.ajde.*;
  17. import org.aspectj.asm.StructureNode;
  18. import org.aspectj.bridge.*;
  19. import org.aspectj.util.ConfigParser;
  20. /**
  21. * Responsible for the build process, including compiler invocation, threading, and error
  22. * reporting.
  23. *
  24. * @author Mik Kersten
  25. */
  26. public class AspectJBuildManager implements BuildManager {
  27. private CompilerAdapter compiler = null;
  28. private TaskListManager compilerMessages = null;
  29. private BuildProgressMonitor progressMonitor = null;
  30. private BuildOptionsAdapter buildOptions = null;
  31. private ArrayList compilerListeners = new ArrayList();
  32. private String configFile = "";
  33. private int lastCompileTime = 50;
  34. private boolean buildStrucutreOnly = false;
  35. public AspectJBuildManager(
  36. TaskListManager compilerMessages,
  37. BuildProgressMonitor progressMonitor,
  38. BuildOptionsAdapter buildOptions) {
  39. this.compilerMessages = compilerMessages;
  40. this.progressMonitor = progressMonitor;
  41. this.buildOptions = buildOptions;
  42. this.compiler = new CompilerAdapter();
  43. }
  44. public void build() {
  45. if (Ajde.getDefault().getConfigurationManager().getActiveConfigFile() == null) {
  46. Ajde.getDefault().getErrorHandler().handleWarning("Nothing to compile, please add a \".lst\" file.");
  47. return;
  48. } else {
  49. build(Ajde.getDefault().getConfigurationManager().getActiveConfigFile());
  50. }
  51. }
  52. public void buildStructure() {
  53. buildStrucutreOnly = true;
  54. build();
  55. }
  56. public void build(String configFile) {
  57. buildStrucutreOnly = false;
  58. if (configFile == null) {
  59. Ajde.getDefault().getErrorHandler().handleWarning("Please add a configuration file to compile.");
  60. } else {
  61. this.configFile = configFile;
  62. CompilerThread compilerThread = new CompilerThread();
  63. compilerThread.start();
  64. }
  65. }
  66. public void abortBuild() {
  67. if (compiler != null) {
  68. compiler.requestCompileExit();
  69. }
  70. }
  71. // public CompilerAdapter getCurrCompiler() {
  72. // return currCompiler;
  73. // }
  74. public boolean isStructureDirty() {
  75. if (compiler != null) {
  76. return compiler.isStructureDirty();
  77. } else {
  78. return false;
  79. }
  80. }
  81. public void setStructureDirty(boolean structureDirty) {
  82. if (compiler != null) {
  83. compiler.setStructureDirty(structureDirty);
  84. }
  85. }
  86. public void addListener(BuildListener compilerListener) {
  87. compilerListeners.add(compilerListener);
  88. }
  89. public void removeListener(BuildListener compilerListener) {
  90. compilerListeners.remove(compilerListener);
  91. }
  92. private void notifyCompileFinished(String configFile, int buildTime, boolean succeeded, boolean warnings) {
  93. Ajde.getDefault().logEvent("build finished, succeeded: " + succeeded);
  94. for (Iterator it = compilerListeners.iterator(); it.hasNext(); ) {
  95. ((BuildListener)it.next()).compileFinished(configFile, buildTime, succeeded, warnings);
  96. }
  97. }
  98. private void notifyCompileStarted(String configFile) {
  99. Ajde.getDefault().logEvent("build started: " + configFile);
  100. for (Iterator it = compilerListeners.iterator(); it.hasNext(); ) {
  101. ((BuildListener)it.next()).compileStarted(configFile);
  102. }
  103. }
  104. private void notifyCompileAborted(String configFile, String message) {
  105. for (Iterator it = compilerListeners.iterator(); it.hasNext(); ) {
  106. ((BuildListener)it.next()).compileAborted(configFile, message);
  107. }
  108. }
  109. /**
  110. * @todo use structured error messages instead
  111. */
  112. private void displayMessages(CompileResult compileResult) {
  113. String[] descriptions = compileResult.getDescriptions();
  114. String[] files = compileResult.getfiles();
  115. Integer[] lineNumbers = compileResult.getLineNumbers();
  116. if (descriptions.length == 0 && compileResult.getResult().trim() != "") {
  117. //compilerMessages.addSourcelineTask(compileResult.getResult(), "", 0, 0, TaskListManager.ERROR_MESSAGE);
  118. compilerMessages.addSourcelineTask(
  119. compileResult.getResult(),
  120. new SourceLocation(null, 0, 0),
  121. IMessage.ERROR);
  122. return;
  123. }
  124. for ( int i = 0; i < descriptions.length &&
  125. i < files.length &&
  126. i < lineNumbers.length; i++ ) {
  127. String message = "";
  128. if (files[i] != "") {
  129. message += "\"" + files[i] + "\": ";
  130. }
  131. if (lineNumbers[i].intValue() != -1 && lineNumbers[i].intValue() != 0) {
  132. message += descriptions[i] + ", at line: " + lineNumbers[i];
  133. } else {
  134. message += descriptions[i];
  135. }
  136. if (message.startsWith("Nothing to compile.")) {
  137. message = "Nothing to compile, please select the project, package(s), or class(es) to compile.";
  138. }
  139. IMessage.Kind kind = IMessage.ERROR;
  140. if (descriptions[i].endsWith("(warning)")) kind = IMessage.WARNING;
  141. compilerMessages.addSourcelineTask(
  142. message,
  143. new SourceLocation(new File(files[i]), lineNumbers[i].intValue(), 0),
  144. kind);
  145. StructureNode node = Ajde.getDefault().getStructureModelManager().getStructureModel().findNodeForSourceLine(
  146. files[i],
  147. lineNumbers[i].intValue()
  148. );
  149. if (node != null) {
  150. node.setMessage(new Message(message, kind, null, null));
  151. }
  152. }
  153. }
  154. /**
  155. * @todo clean up this mess.
  156. */
  157. public class CompilerThread extends Thread {
  158. public void run() {
  159. boolean succeeded = true;
  160. boolean warnings = false;
  161. try {
  162. long timeStart = System.currentTimeMillis();
  163. notifyCompileStarted(configFile);
  164. progressMonitor.start(configFile);
  165. compilerMessages.clearTasks();
  166. Ajde.getDefault().logEvent("building with options: "
  167. + getFormattedOptionsString(buildOptions, Ajde.getDefault().getProjectProperties()));
  168. succeeded = compiler.compile(configFile, progressMonitor);
  169. long timeEnd = System.currentTimeMillis();
  170. lastCompileTime = (int)(timeEnd - timeStart);
  171. } catch (ConfigParser.ParseException pe) {
  172. Ajde.getDefault().getErrorHandler().handleWarning(
  173. "Config file entry invalid, file: "
  174. + pe.getFile().getPath()
  175. + ", line number: "
  176. + pe.getLine());
  177. // }
  178. // catch (ExitRequestException ere) {
  179. // if (ere.getValue() == 0) {
  180. // notifyCompileAborted(configFile, "Build cancelled by user.");
  181. // } else {
  182. // Ajde.getDefault().getErrorHandler().handleWarning("Compile could not complete. See the console for more details. "
  183. // + "If no console is available re-launch the application from the command line.");
  184. // }
  185. // } catch (InternalCompilerError compilerError) {
  186. // if (compilerError.uncaughtThrowable instanceof OutOfMemoryError) {
  187. // Ajde.getDefault().getErrorHandler().handleError("Out of memory. "
  188. // + "Increase memory by setting the -Xmx parameter that this VM was launched with.\n"
  189. // + "Note that some AJDE structure persists across compiles." ,
  190. // compilerError.uncaughtThrowable);
  191. // } else if (compilerError.uncaughtThrowable instanceof MissingRuntimeError) {
  192. // Ajde.getDefault().getErrorHandler().handleWarning("Compilation aborted because the AspectJ runtime was not found. "
  193. // + "Please place aspectjrt.jar in the lib/ext directory.");
  194. // } else if (compilerError.uncaughtThrowable instanceof BadRuntimeError) {
  195. // Ajde.getDefault().getErrorHandler().handleWarning("Compilation aborted because an out-of-date version of " +
  196. // "the AspectJ runtime was found. "
  197. // + "Please place a current version of aspectjrt.jar in the lib/ext directory.");
  198. // } else {
  199. // Ajde.getDefault().getErrorHandler().handleError("Compile error.", compilerError.uncaughtThrowable);
  200. // }
  201. } catch (Throwable e) {
  202. Ajde.getDefault().getErrorHandler().handleError("Compile error, caught Throwable: " + e.toString(), e);
  203. } finally {
  204. progressMonitor.finish();
  205. }
  206. notifyCompileFinished(configFile, lastCompileTime, succeeded, warnings);
  207. }
  208. private String getFormattedOptionsString(BuildOptionsAdapter buildOptions, ProjectPropertiesAdapter properties) {
  209. return "Building with settings: "
  210. + "\n-> output path: " + properties.getOutputPath()
  211. + "\n-> classpath: " + properties.getClasspath()
  212. + "\n-> bootclasspath: " + properties.getBootClasspath()
  213. + "\n-> non-standard options: " + buildOptions.getNonStandardOptions()
  214. + "\n-> porting mode: " + buildOptions.getPortingMode()
  215. + "\n-> source 1.4 mode: " + buildOptions.getSourceOnePointFourMode()
  216. + "\n-> strict spec mode: " + buildOptions.getStrictSpecMode()
  217. + "\n-> lenient spec mode: " + buildOptions.getLenientSpecMode()
  218. + "\n-> use javac mode: " + buildOptions.getUseJavacMode()
  219. + "\n-> preprocess mode: " + buildOptions.getPreprocessMode()
  220. + "\n-> working dir: " + buildOptions.getWorkingOutputPath();
  221. }
  222. }
  223. public BuildOptionsAdapter getBuildOptions() {
  224. return buildOptions;
  225. }
  226. // private void setCompilerOptions(AjdeCompiler compiler) {
  227. // String nonstandardOptions = buildOptions.getNonStandardOptions();
  228. // if (nonstandardOptions != null && !nonstandardOptions.trim().equals("")) {
  229. // StringTokenizer st = new StringTokenizer(nonstandardOptions, " ");
  230. // while (st.hasMoreTokens()) {
  231. // String flag = (String)st.nextToken();
  232. // compiler.getOptions().set(flag.substring(1, flag.length()), Boolean.TRUE);
  233. // }
  234. // }
  235. //
  236. // if (Ajde.getDefault().getProjectProperties().getOutputPath() != null
  237. // && !compiler.getOptions().XtargetNearSource) {
  238. // compiler.getOptions().outputDir = new File(Ajde.getDefault().getProjectProperties().getOutputPath());
  239. // }
  240. // if (Ajde.getDefault().getProjectProperties().getBootClasspath() != null) {
  241. // compiler.getOptions().bootclasspath = Ajde.getDefault().getProjectProperties().getBootClasspath();
  242. // }
  243. // if (Ajde.getDefault().getProjectProperties().getClasspath() != null) {
  244. // compiler.getOptions().classpath = Ajde.getDefault().getProjectProperties().getClasspath();
  245. // }
  246. // if (buildOptions.getWorkingOutputPath() != null) {
  247. // compiler.getOptions().workingDir = new File(buildOptions.getWorkingOutputPath());
  248. // }
  249. //// if (buildOptions.getCharacterEncoding() != null) {
  250. //// compiler.getOptions().encoding = buildOptions.getCharacterEncoding();
  251. //// }
  252. //
  253. // compiler.getOptions().lenient = buildOptions.getLenientSpecMode();
  254. // compiler.getOptions().strict = buildOptions.getStrictSpecMode();
  255. // compiler.getOptions().usejavac = buildOptions.getUseJavacMode();
  256. // compiler.getOptions().porting = buildOptions.getPortingMode();
  257. // compiler.getOptions().preprocess = buildOptions.getPreprocessMode();
  258. //
  259. // if (buildOptions.getSourceOnePointFourMode()) {
  260. // compiler.getOptions().source = "1.4";
  261. // }
  262. // }
  263. static class CompileResult {
  264. private String[] files = null;
  265. private Integer[] lineNumbers = null;
  266. private String[] descriptions = null;
  267. private String resultString = "";
  268. private boolean resultContainsErrors = false;
  269. /**
  270. * Parses out warning messages, error messages, "file not found" messages, javac "Note:" messages.
  271. *
  272. * @todo get error message structure directly from compiler
  273. */
  274. public CompileResult( String result )
  275. {
  276. resultString = result;
  277. BufferedReader reader = new BufferedReader( new StringReader( result ) );
  278. Vector fileV = new Vector();
  279. Vector lineV = new Vector();
  280. Vector descV = new Vector();
  281. try {
  282. for (String line = reader.readLine(); line != null; line = reader.readLine()) {
  283. String originalLine = line;
  284. String description = "";
  285. String file = "";
  286. Integer lineNo = new Integer(0);
  287. int index = line.indexOf( ":", 2 ); // @todo skip the initial drive ":" (fix, Windows only)
  288. try {
  289. if (line.indexOf("Note: ") != -1) {
  290. int index1 = line.indexOf(".java");
  291. if (index1 != -1) {
  292. description = line.substring(index1+5) + " (warning)";
  293. file = line.substring("Note: ".length(), index1+5);
  294. lineNo = new Integer(0);
  295. } else {
  296. description = line + " (warning)";
  297. file = "";
  298. lineNo = new Integer(-1);
  299. }
  300. }
  301. else if (line.indexOf("file not found: ") != -1) {
  302. description = "file not found: ";
  303. file = line.substring("file not found: ".length());
  304. lineNo = new Integer(0);
  305. }
  306. else if (index != -1 && line.indexOf( "java" ) != -1) {
  307. file = line.substring( 0, index );
  308. line = line.substring( index+1 );
  309. index = line.indexOf( ":" );
  310. lineNo = new Integer( Integer.parseInt( line.substring( 0, index ) ) ) ;
  311. line = line.substring( index+1 );
  312. if (!resultContainsErrors) {
  313. if (!line.endsWith("(warning)")) {
  314. resultContainsErrors = true;
  315. }
  316. }
  317. description = line.substring( line.indexOf( ":" ) + 2 );
  318. }
  319. } catch (Exception e) {
  320. description = "Internal ajc message: " + originalLine;
  321. file = "";
  322. lineNo = new Integer(-1);
  323. }
  324. if (description.trim() != "") {
  325. descV.addElement(description);
  326. fileV.addElement(file);
  327. lineV.addElement(lineNo);
  328. }
  329. }
  330. }
  331. catch ( IOException ioe ) {
  332. resultString = "ERROR: could not parse result at line for string: " + result;
  333. }
  334. files = new String[fileV.size()];
  335. lineNumbers = new Integer[lineV.size()];
  336. descriptions = new String[descV.size()];
  337. fileV.copyInto(files);
  338. lineV.copyInto(lineNumbers);
  339. descV.copyInto(descriptions);
  340. }
  341. public String toString()
  342. {
  343. return resultString;
  344. }
  345. public String[] getfiles()
  346. {
  347. return files;
  348. }
  349. public Integer[] getLineNumbers()
  350. {
  351. return lineNumbers;
  352. }
  353. public String[] getDescriptions()
  354. {
  355. return descriptions;
  356. }
  357. public String getResult()
  358. {
  359. return resultString;
  360. }
  361. public boolean containsErrors() {
  362. return resultContainsErrors;
  363. }
  364. }
  365. }
  366. class ConfigFileDoesNotExistException extends Exception {
  367. public ConfigFileDoesNotExistException(String filePath) {
  368. super(filePath);
  369. }
  370. }