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.

Ajde.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  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 Eclipse Public License v 2.0
  7. * which accompanies this distribution and is available at
  8. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  9. *
  10. * Contributors:
  11. * Xerox/PARC initial implementation
  12. * Helen Hawkins Converted to new interface (bug 148190)
  13. *******************************************************************/
  14. package org.aspectj.ajde;
  15. import java.awt.Frame;
  16. import java.io.File;
  17. import java.util.Arrays;
  18. import java.util.Collections;
  19. import java.util.List;
  20. import javax.swing.JOptionPane;
  21. import org.aspectj.ajde.core.AjCompiler;
  22. import org.aspectj.ajde.core.IBuildProgressMonitor;
  23. import org.aspectj.ajde.core.ICompilerConfiguration;
  24. import org.aspectj.ajde.internal.BuildConfigListener;
  25. import org.aspectj.ajde.internal.BuildConfigManager;
  26. import org.aspectj.ajde.internal.LstBuildConfigManager;
  27. import org.aspectj.ajde.ui.FileStructureView;
  28. import org.aspectj.ajde.ui.StructureSearchManager;
  29. import org.aspectj.ajde.ui.StructureViewManager;
  30. import org.aspectj.ajde.ui.swing.BrowserViewManager;
  31. import org.aspectj.ajde.ui.swing.OptionsFrame;
  32. import org.aspectj.ajde.ui.swing.StructureViewPanel;
  33. import org.aspectj.ajde.ui.swing.SwingTreeViewNodeFactory;
  34. import org.aspectj.ajde.ui.swing.TreeViewBuildConfigEditor;
  35. import org.aspectj.asm.AsmManager;
  36. import org.aspectj.bridge.IMessage;
  37. import org.aspectj.bridge.Message;
  38. import org.aspectj.util.LangUtil;
  39. import org.aspectj.util.Reflection;
  40. /**
  41. * Singleton class used to initialize the Ajde ui as well as the properties required to run the compiler. Users must call
  42. * "Ajde.init(...)" before doing anything else. There are getter methods for the various properties that are set in the
  43. * initialization.
  44. *
  45. * This also defines the factory for getting new AjCompiler instances.
  46. *
  47. * @author Mik Kersten
  48. * @author Andy Clement
  49. */
  50. public class Ajde {
  51. protected static final Ajde INSTANCE = new Ajde();
  52. private BrowserViewManager viewManager = null;
  53. private IdeUIAdapter ideUIAdapter = null;
  54. private TreeViewBuildConfigEditor buildConfigEditor = null;
  55. private IconRegistry iconRegistry;
  56. private IRuntimeProperties runtimeProperties;
  57. private boolean initialized = false;
  58. private AsmManager asm;
  59. private OptionsFrame optionsFrame = null;
  60. private Frame rootFrame = null;
  61. private StructureViewPanel fileStructurePanel = null;
  62. private EditorAdapter editorAdapter;
  63. private StructureViewManager structureViewManager;
  64. private StructureSearchManager structureSearchManager;
  65. private final BuildConfigManager configurationManager;
  66. // all to do with building....
  67. private ICompilerConfiguration compilerConfig;
  68. private IUIBuildMessageHandler uiBuildMsgHandler;
  69. private IBuildProgressMonitor buildProgressMonitor;
  70. private AjCompiler compiler;
  71. public AsmManager getModel() {
  72. return asm;
  73. }
  74. /**
  75. * This class can only be constructured by itself (as a singleton) or by sub-classes.
  76. */
  77. protected Ajde() {
  78. configurationManager = new LstBuildConfigManager();
  79. }
  80. /**
  81. * Initializes the ajde ui and sets up the compiler
  82. */
  83. public void init(ICompilerConfiguration compilerConfig, IUIBuildMessageHandler uiBuildMessageHandler,
  84. IBuildProgressMonitor monitor, EditorAdapter editorAdapter, IdeUIAdapter ideUIAdapter, IconRegistry iconRegistry,
  85. Frame rootFrame, IRuntimeProperties runtimeProperties, boolean useFileView) {
  86. try {
  87. INSTANCE.compilerConfig = compilerConfig;
  88. INSTANCE.uiBuildMsgHandler = uiBuildMessageHandler;
  89. INSTANCE.buildProgressMonitor = monitor;
  90. INSTANCE.asm = AsmManager.createNewStructureModel(Collections.<File,String>emptyMap());
  91. INSTANCE.iconRegistry = iconRegistry;
  92. INSTANCE.ideUIAdapter = ideUIAdapter;
  93. INSTANCE.buildConfigEditor = new TreeViewBuildConfigEditor();
  94. INSTANCE.rootFrame = rootFrame;
  95. INSTANCE.runtimeProperties = runtimeProperties;
  96. INSTANCE.configurationManager.addListener(INSTANCE.STRUCTURE_UPDATE_CONFIG_LISTENER);
  97. INSTANCE.ideUIAdapter = ideUIAdapter;
  98. INSTANCE.editorAdapter = editorAdapter;
  99. INSTANCE.structureSearchManager = new StructureSearchManager();
  100. INSTANCE.structureViewManager = new StructureViewManager(new SwingTreeViewNodeFactory(iconRegistry));
  101. if (useFileView) {
  102. FileStructureView structureView = structureViewManager.createViewForSourceFile(editorAdapter.getCurrFile(),
  103. structureViewManager.getDefaultViewProperties());
  104. structureViewManager.setDefaultFileView(structureView);
  105. fileStructurePanel = new StructureViewPanel(structureView);
  106. }
  107. viewManager = new BrowserViewManager();
  108. optionsFrame = new OptionsFrame(iconRegistry);
  109. initialized = true;
  110. } catch (Throwable t) {
  111. Message error = new Message("AJDE UI failed to initialize", IMessage.ABORT, t, null);
  112. uiBuildMsgHandler.handleMessage(error);
  113. }
  114. }
  115. public void showOptionsFrame() {
  116. int x = (rootFrame.getWidth() / 2) + rootFrame.getX() - optionsFrame.getWidth() / 2;
  117. int y = (rootFrame.getHeight() / 2) + rootFrame.getY() - optionsFrame.getHeight() / 2;
  118. optionsFrame.setLocation(x, y);
  119. optionsFrame.setVisible(true);
  120. }
  121. /**
  122. * @return true if init(..) has been run, false otherwise
  123. */
  124. public boolean isInitialized() {
  125. return initialized;
  126. }
  127. private final BuildConfigListener STRUCTURE_UPDATE_CONFIG_LISTENER = new BuildConfigListener() {
  128. public void currConfigChanged(String configFilePath) {
  129. if (configFilePath != null) {
  130. Ajde.getDefault().asm.readStructureModel(configFilePath);
  131. }
  132. }
  133. public void configsListUpdated(List configsList) {
  134. }
  135. };
  136. /**
  137. * Utility to run the project main class from the project properties in the same VM using a class loader populated with the
  138. * classpath and output path or jar. Errors are logged to the ErrorHandler.
  139. *
  140. * @return Thread running with process, or null if unable to start
  141. */
  142. public Thread runInSameVM() {
  143. final RunProperties props = new RunProperties(compilerConfig, runtimeProperties, uiBuildMsgHandler, rootFrame);
  144. if (!props.valid) {
  145. return null; // error already handled
  146. }
  147. Runnable runner = new Runnable() {
  148. public void run() {
  149. try {
  150. Reflection.runMainInSameVM(props.classpath, props.mainClass, props.args);
  151. } catch (Throwable e) {
  152. Message msg = new Message("Error running " + props.mainClass, IMessage.ERROR, e, null);
  153. uiBuildMsgHandler.handleMessage(msg);
  154. }
  155. }
  156. };
  157. Thread result = new Thread(runner, props.mainClass);
  158. result.start();
  159. return result;
  160. }
  161. /**
  162. * Utility to run the project main class from the project properties in a new VM. Errors are logged to the ErrorHandler.
  163. *
  164. * @return LangUtil.ProcessController running with process, or null if unable to start
  165. */
  166. public LangUtil.ProcessController runInNewVM() {
  167. final RunProperties props = new RunProperties(compilerConfig, runtimeProperties, uiBuildMsgHandler, rootFrame);
  168. if (!props.valid) {
  169. return null; // error already handled
  170. }
  171. // setup to run asynchronously, pipe streams through, and report errors
  172. final StringBuffer command = new StringBuffer();
  173. LangUtil.ProcessController controller = new LangUtil.ProcessController() {
  174. public void doCompleting(Throwable thrown, int result) {
  175. LangUtil.ProcessController.Thrown any = getThrown();
  176. if (!any.thrown && (null == thrown) && (0 == result)) {
  177. return; // no errors
  178. }
  179. // handle errors
  180. String context = props.mainClass + " command \"" + command + "\"";
  181. if (null != thrown) {
  182. String m = "Exception running " + context;
  183. uiBuildMsgHandler.handleMessage(new Message(m, IMessage.ERROR, thrown, null));
  184. } else if (0 != result) {
  185. String m = "Result of running " + context;
  186. uiBuildMsgHandler.handleMessage(new Message(m, IMessage.ERROR, null, null));
  187. }
  188. if (null != any.fromInPipe) {
  189. String m = "Error processing input pipe for " + context;
  190. uiBuildMsgHandler.handleMessage(new Message(m, IMessage.ERROR, thrown, null));
  191. }
  192. if (null != any.fromOutPipe) {
  193. String m = "Error processing output pipe for " + context;
  194. uiBuildMsgHandler.handleMessage(new Message(m, IMessage.ERROR, thrown, null));
  195. }
  196. if (null != any.fromErrPipe) {
  197. String m = "Error processing error pipe for " + context;
  198. uiBuildMsgHandler.handleMessage(new Message(m, IMessage.ERROR, thrown, null));
  199. }
  200. }
  201. };
  202. controller = LangUtil.makeProcess(controller, props.classpath, props.mainClass, props.args);
  203. command.append(Arrays.asList(controller.getCommand()).toString());
  204. // now run the process
  205. controller.start();
  206. return controller;
  207. }
  208. /** struct class to interpret project properties */
  209. private static class RunProperties {
  210. final String mainClass;
  211. final String classpath;
  212. final String[] args;
  213. final boolean valid;
  214. private final Frame rootFrame;
  215. RunProperties(ICompilerConfiguration compilerConfig, IRuntimeProperties runtimeProperties, IUIBuildMessageHandler handler,
  216. Frame rootFrame) {
  217. // XXX really run arbitrary handler in constructor? hmm.
  218. LangUtil.throwIaxIfNull(runtimeProperties, "runtime properties");
  219. LangUtil.throwIaxIfNull(compilerConfig, "compiler configuration");
  220. LangUtil.throwIaxIfNull(handler, "handler");
  221. LangUtil.throwIaxIfNull(rootFrame, "rootFrame");
  222. String mainClass = null;
  223. String classpath = null;
  224. String[] args = null;
  225. boolean valid = false;
  226. this.rootFrame = rootFrame;
  227. mainClass = runtimeProperties.getClassToExecute();
  228. if (LangUtil.isEmpty(mainClass)) {
  229. showWarningMessage("No main class specified");
  230. } else {
  231. StringBuilder sb = new StringBuilder();
  232. List outputDirs = compilerConfig.getOutputLocationManager().getAllOutputLocations();
  233. for (Object outputDir : outputDirs) {
  234. File dir = (File) outputDir;
  235. sb.append(dir.getAbsolutePath() + File.pathSeparator);
  236. }
  237. classpath = LangUtil.makeClasspath(null, compilerConfig.getClasspath(), sb.toString(), compilerConfig.getOutJar());
  238. if (LangUtil.isEmpty(classpath)) {
  239. showWarningMessage("No classpath specified");
  240. } else {
  241. args = LangUtil.split(runtimeProperties.getExecutionArgs());
  242. valid = true;
  243. }
  244. }
  245. this.mainClass = mainClass;
  246. this.classpath = classpath;
  247. this.args = args;
  248. this.valid = valid;
  249. }
  250. private void showWarningMessage(String message) {
  251. JOptionPane.showMessageDialog(rootFrame, message, "Warning", JOptionPane.WARNING_MESSAGE);
  252. }
  253. }
  254. /**
  255. * Set the build off in the same thread
  256. *
  257. * @param configFile
  258. * @param buildFresh - true if want to do a full build, false otherwise
  259. */
  260. public void runBuildInSameThread(String configFile, boolean buildFresh) {
  261. AjCompiler c = getCompilerForConfigFile(configFile);
  262. if (c == null)
  263. return;
  264. if (buildFresh) {
  265. c.buildFresh();
  266. } else {
  267. c.build();
  268. }
  269. }
  270. /**
  271. * Set the build off in a different thread. Would need to set the build off in a different thread if using a swing application
  272. * to display the build progress.
  273. *
  274. * @param configFile
  275. * @param buildFresh - true if want to do a full build, false otherwise
  276. */
  277. public void runBuildInDifferentThread(String configFile, boolean buildFresh) {
  278. AjCompiler c = getCompilerForConfigFile(configFile);
  279. if (c == null)
  280. return;
  281. CompilerThread compilerThread = new CompilerThread(c, buildFresh);
  282. compilerThread.start();
  283. }
  284. static class CompilerThread extends Thread {
  285. private final AjCompiler compiler;
  286. private final boolean buildFresh;
  287. public CompilerThread(AjCompiler compiler, boolean buildFresh) {
  288. this.compiler = compiler;
  289. this.buildFresh = buildFresh;
  290. }
  291. public void run() {
  292. if (buildFresh) {
  293. compiler.buildFresh();
  294. } else {
  295. compiler.build();
  296. }
  297. }
  298. }
  299. // ---------- getter methods for the ui --------------
  300. /**
  301. * @return the singleton instance
  302. */
  303. public static Ajde getDefault() {
  304. return INSTANCE;
  305. }
  306. /**
  307. * @return the BrowserViewManager
  308. */
  309. public BrowserViewManager getViewManager() {
  310. return viewManager;
  311. }
  312. /**
  313. * @return the main frame
  314. */
  315. public Frame getRootFrame() {
  316. return rootFrame;
  317. }
  318. /**
  319. * @return the parent frame for the options panel
  320. */
  321. public OptionsFrame getOptionsFrame() {
  322. return optionsFrame;
  323. }
  324. /**
  325. * @return the IdeUIAdapter
  326. */
  327. public IdeUIAdapter getIdeUIAdapter() {
  328. return ideUIAdapter;
  329. }
  330. /**
  331. * @return the EditorAdapter
  332. */
  333. public EditorAdapter getEditorAdapter() {
  334. return editorAdapter;
  335. }
  336. /**
  337. * @return the TreeViewBuildConfigEditor
  338. */
  339. public TreeViewBuildConfigEditor getBuildConfigEditor() {
  340. return buildConfigEditor;
  341. }
  342. /**
  343. * @return the StructureViewPanel
  344. */
  345. public StructureViewPanel getFileStructurePanel() {
  346. return fileStructurePanel;
  347. }
  348. /**
  349. * @return the IconRegistry
  350. */
  351. public IconRegistry getIconRegistry() {
  352. return iconRegistry;
  353. }
  354. /**
  355. * @return the StructureViewManager
  356. */
  357. public StructureViewManager getStructureViewManager() {
  358. return structureViewManager;
  359. }
  360. /**
  361. * @return the StructureSearchManager
  362. */
  363. public StructureSearchManager getStructureSearchManager() {
  364. return structureSearchManager;
  365. }
  366. /**
  367. * @return the BuildConfigManager
  368. */
  369. public BuildConfigManager getBuildConfigManager() {
  370. return configurationManager;
  371. }
  372. // -------------- getter methods for the compiler -------------
  373. /**
  374. * @return the ICompilerConfiguration
  375. */
  376. public ICompilerConfiguration getCompilerConfig() {
  377. return compilerConfig;
  378. }
  379. /**
  380. * @return the IUIBuildMessageHandler
  381. */
  382. public IUIBuildMessageHandler getMessageHandler() {
  383. return uiBuildMsgHandler;
  384. }
  385. /**
  386. * @return the IBuildProgressMonitor
  387. */
  388. public IBuildProgressMonitor getBuildProgressMonitor() {
  389. return buildProgressMonitor;
  390. }
  391. /**
  392. * If the provided configFile is the same as the id for the last compiler then returns that, otherwise clears the state for the
  393. * saved compiler and creates a new one for the provided configFile
  394. *
  395. * @param configFile
  396. * @return the AjCompiler with the id of the given configFile
  397. */
  398. public AjCompiler getCompilerForConfigFile(String configFile) {
  399. if (configFile == null) {
  400. return null;
  401. }
  402. if ((compiler == null || !compiler.getId().equals(configFile))) {
  403. if (compiler != null) {
  404. // have to remove the incremental state of the previous
  405. // compiler - this will remove it from the
  406. // IncrementalStateManager's
  407. // list
  408. compiler.clearLastState();
  409. }
  410. getMessageHandler().reset();
  411. compiler = new AjCompiler(configFile, getCompilerConfig(), getBuildProgressMonitor(), getMessageHandler());
  412. }
  413. return compiler;
  414. }
  415. public AsmManager getModelForConfigFile(String configFile) {
  416. return compiler.getModel();
  417. // if ((compiler == null || !compiler.getId().equals(configFile))) {
  418. // if (compiler != null) {
  419. // // have to remove the incremental state of the previous
  420. // // compiler - this will remove it from the
  421. // // IncrementalStateManager's
  422. // // list
  423. // compiler.clearLastState();
  424. // }
  425. // getMessageHandler().reset();
  426. // compiler = new AjCompiler(configFile, getCompilerConfig(), getBuildProgressMonitor(), getMessageHandler());
  427. // }
  428. }
  429. }