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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  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<File> outputDirs = compilerConfig.getOutputLocationManager().getAllOutputLocations();
  233. for (File dir : outputDirs) {
  234. sb.append(dir.getAbsolutePath() + File.pathSeparator);
  235. }
  236. classpath = LangUtil.makeClasspath(null, compilerConfig.getClasspath(), sb.toString(), compilerConfig.getOutJar());
  237. if (LangUtil.isEmpty(classpath)) {
  238. showWarningMessage("No classpath specified");
  239. } else {
  240. args = LangUtil.split(runtimeProperties.getExecutionArgs());
  241. valid = true;
  242. }
  243. }
  244. this.mainClass = mainClass;
  245. this.classpath = classpath;
  246. this.args = args;
  247. this.valid = valid;
  248. }
  249. private void showWarningMessage(String message) {
  250. JOptionPane.showMessageDialog(rootFrame, message, "Warning", JOptionPane.WARNING_MESSAGE);
  251. }
  252. }
  253. /**
  254. * Set the build off in the same thread
  255. *
  256. * @param configFile
  257. * @param buildFresh - true if want to do a full build, false otherwise
  258. */
  259. public void runBuildInSameThread(String configFile, boolean buildFresh) {
  260. AjCompiler c = getCompilerForConfigFile(configFile);
  261. if (c == null)
  262. return;
  263. if (buildFresh) {
  264. c.buildFresh();
  265. } else {
  266. c.build();
  267. }
  268. }
  269. /**
  270. * Set the build off in a different thread. Would need to set the build off in a different thread if using a swing application
  271. * to display the build progress.
  272. *
  273. * @param configFile
  274. * @param buildFresh - true if want to do a full build, false otherwise
  275. */
  276. public void runBuildInDifferentThread(String configFile, boolean buildFresh) {
  277. AjCompiler c = getCompilerForConfigFile(configFile);
  278. if (c == null)
  279. return;
  280. CompilerThread compilerThread = new CompilerThread(c, buildFresh);
  281. compilerThread.start();
  282. }
  283. static class CompilerThread extends Thread {
  284. private final AjCompiler compiler;
  285. private final boolean buildFresh;
  286. public CompilerThread(AjCompiler compiler, boolean buildFresh) {
  287. this.compiler = compiler;
  288. this.buildFresh = buildFresh;
  289. }
  290. public void run() {
  291. if (buildFresh) {
  292. compiler.buildFresh();
  293. } else {
  294. compiler.build();
  295. }
  296. }
  297. }
  298. // ---------- getter methods for the ui --------------
  299. /**
  300. * @return the singleton instance
  301. */
  302. public static Ajde getDefault() {
  303. return INSTANCE;
  304. }
  305. /**
  306. * @return the BrowserViewManager
  307. */
  308. public BrowserViewManager getViewManager() {
  309. return viewManager;
  310. }
  311. /**
  312. * @return the main frame
  313. */
  314. public Frame getRootFrame() {
  315. return rootFrame;
  316. }
  317. /**
  318. * @return the parent frame for the options panel
  319. */
  320. public OptionsFrame getOptionsFrame() {
  321. return optionsFrame;
  322. }
  323. /**
  324. * @return the IdeUIAdapter
  325. */
  326. public IdeUIAdapter getIdeUIAdapter() {
  327. return ideUIAdapter;
  328. }
  329. /**
  330. * @return the EditorAdapter
  331. */
  332. public EditorAdapter getEditorAdapter() {
  333. return editorAdapter;
  334. }
  335. /**
  336. * @return the TreeViewBuildConfigEditor
  337. */
  338. public TreeViewBuildConfigEditor getBuildConfigEditor() {
  339. return buildConfigEditor;
  340. }
  341. /**
  342. * @return the StructureViewPanel
  343. */
  344. public StructureViewPanel getFileStructurePanel() {
  345. return fileStructurePanel;
  346. }
  347. /**
  348. * @return the IconRegistry
  349. */
  350. public IconRegistry getIconRegistry() {
  351. return iconRegistry;
  352. }
  353. /**
  354. * @return the StructureViewManager
  355. */
  356. public StructureViewManager getStructureViewManager() {
  357. return structureViewManager;
  358. }
  359. /**
  360. * @return the StructureSearchManager
  361. */
  362. public StructureSearchManager getStructureSearchManager() {
  363. return structureSearchManager;
  364. }
  365. /**
  366. * @return the BuildConfigManager
  367. */
  368. public BuildConfigManager getBuildConfigManager() {
  369. return configurationManager;
  370. }
  371. // -------------- getter methods for the compiler -------------
  372. /**
  373. * @return the ICompilerConfiguration
  374. */
  375. public ICompilerConfiguration getCompilerConfig() {
  376. return compilerConfig;
  377. }
  378. /**
  379. * @return the IUIBuildMessageHandler
  380. */
  381. public IUIBuildMessageHandler getMessageHandler() {
  382. return uiBuildMsgHandler;
  383. }
  384. /**
  385. * @return the IBuildProgressMonitor
  386. */
  387. public IBuildProgressMonitor getBuildProgressMonitor() {
  388. return buildProgressMonitor;
  389. }
  390. /**
  391. * If the provided configFile is the same as the id for the last compiler then returns that, otherwise clears the state for the
  392. * saved compiler and creates a new one for the provided configFile
  393. *
  394. * @param configFile
  395. * @return the AjCompiler with the id of the given configFile
  396. */
  397. public AjCompiler getCompilerForConfigFile(String configFile) {
  398. if (configFile == null) {
  399. return null;
  400. }
  401. if ((compiler == null || !compiler.getId().equals(configFile))) {
  402. if (compiler != null) {
  403. // have to remove the incremental state of the previous
  404. // compiler - this will remove it from the
  405. // IncrementalStateManager's
  406. // list
  407. compiler.clearLastState();
  408. }
  409. getMessageHandler().reset();
  410. compiler = new AjCompiler(configFile, getCompilerConfig(), getBuildProgressMonitor(), getMessageHandler());
  411. }
  412. return compiler;
  413. }
  414. public AsmManager getModelForConfigFile(String configFile) {
  415. return compiler.getModel();
  416. // if ((compiler == null || !compiler.getId().equals(configFile))) {
  417. // if (compiler != null) {
  418. // // have to remove the incremental state of the previous
  419. // // compiler - this will remove it from the
  420. // // IncrementalStateManager's
  421. // // list
  422. // compiler.clearLastState();
  423. // }
  424. // getMessageHandler().reset();
  425. // compiler = new AjCompiler(configFile, getCompilerConfig(), getBuildProgressMonitor(), getMessageHandler());
  426. // }
  427. }
  428. }