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

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