1 | /*
|
---|
2 | * Copyright 2001-2002,2004 The Apache Software Foundation
|
---|
3 | *
|
---|
4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
---|
5 | * you may not use this file except in compliance with the License.
|
---|
6 | * You may obtain a copy of the License at
|
---|
7 | *
|
---|
8 | * http://www.apache.org/licenses/LICENSE-2.0
|
---|
9 | *
|
---|
10 | * Unless required by applicable law or agreed to in writing, software
|
---|
11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
---|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
13 | * See the License for the specific language governing permissions and
|
---|
14 | * limitations under the License.
|
---|
15 | *
|
---|
16 | */
|
---|
17 |
|
---|
18 | package org.apache.tools.ant.taskdefs.optional.ide;
|
---|
19 |
|
---|
20 |
|
---|
21 | import java.beans.PropertyChangeListener;
|
---|
22 | import java.beans.PropertyChangeSupport;
|
---|
23 | import java.io.File;
|
---|
24 | import java.util.Enumeration;
|
---|
25 | import java.util.StringTokenizer;
|
---|
26 | import java.util.Vector;
|
---|
27 | import org.apache.tools.ant.BuildEvent;
|
---|
28 | import org.apache.tools.ant.BuildException;
|
---|
29 | import org.apache.tools.ant.BuildListener;
|
---|
30 | import org.apache.tools.ant.Project;
|
---|
31 | import org.apache.tools.ant.ProjectHelper;
|
---|
32 | import org.apache.tools.ant.Target;
|
---|
33 |
|
---|
34 | /**
|
---|
35 | * This class wraps the Ant project information needed to
|
---|
36 | * start Ant from Visual Age.
|
---|
37 | * It serves the following purposes:
|
---|
38 | * - acts as model for AntMakeFrame
|
---|
39 | * - converts itself to/from String (to store the information
|
---|
40 | * as ToolData in the VA repository)
|
---|
41 | * - wraps Project functions for the GUI (get target list,
|
---|
42 | * execute target)
|
---|
43 | * - manages a seperate thread for Ant project execution
|
---|
44 | * this allows interrupting a running build from a GUI
|
---|
45 | *
|
---|
46 | */
|
---|
47 |
|
---|
48 | class VAJBuildInfo implements Runnable {
|
---|
49 | /**
|
---|
50 | * This exception is thrown when a build is interrupted
|
---|
51 | */
|
---|
52 | public static class BuildInterruptedException extends BuildException {
|
---|
53 | public String toString() {
|
---|
54 | return "BUILD INTERRUPTED";
|
---|
55 | }
|
---|
56 | }
|
---|
57 |
|
---|
58 | /**
|
---|
59 | * BuildListener which checks for interruption and throws Exception
|
---|
60 | * if build process is interrupted. This class is a wrapper around
|
---|
61 | * a 'real' listener.
|
---|
62 | */
|
---|
63 | private class InterruptedChecker implements BuildListener {
|
---|
64 | // the real listener
|
---|
65 | BuildListener wrappedListener;
|
---|
66 |
|
---|
67 | /**
|
---|
68 | * Can only be constructed as wrapper around a real listener
|
---|
69 | * @param listener the real listener
|
---|
70 | */
|
---|
71 | public InterruptedChecker(BuildListener listener) {
|
---|
72 | super();
|
---|
73 | wrappedListener = listener;
|
---|
74 | }
|
---|
75 |
|
---|
76 | /**
|
---|
77 | * checks if the thread was interrupted. When an
|
---|
78 | * interrupt occurred, throw an Exception to stop
|
---|
79 | * the execution.
|
---|
80 | */
|
---|
81 | protected void checkInterrupted() {
|
---|
82 | if (buildThread.isInterrupted()) {
|
---|
83 | throw new BuildInterruptedException();
|
---|
84 | }
|
---|
85 | }
|
---|
86 |
|
---|
87 | /**
|
---|
88 | * Fired after the last target has finished. This event
|
---|
89 | * will still be thrown if an error occurred during the build.
|
---|
90 | */
|
---|
91 | public void buildFinished(BuildEvent event) {
|
---|
92 | wrappedListener.buildFinished(event);
|
---|
93 | checkInterrupted();
|
---|
94 | }
|
---|
95 |
|
---|
96 | /**
|
---|
97 | * Fired before any targets are started.
|
---|
98 | */
|
---|
99 | public void buildStarted(BuildEvent event) {
|
---|
100 | wrappedListener.buildStarted(event);
|
---|
101 | checkInterrupted();
|
---|
102 | }
|
---|
103 |
|
---|
104 | /**
|
---|
105 | * Fired whenever a message is logged.
|
---|
106 | */
|
---|
107 | public void messageLogged(BuildEvent event) {
|
---|
108 | wrappedListener.messageLogged(event);
|
---|
109 | checkInterrupted();
|
---|
110 | }
|
---|
111 |
|
---|
112 | /**
|
---|
113 | * Fired when a target has finished. This event will
|
---|
114 | * still be thrown if an error occurred during the build.
|
---|
115 | */
|
---|
116 | public void targetFinished(BuildEvent event) {
|
---|
117 | wrappedListener.targetFinished(event);
|
---|
118 | checkInterrupted();
|
---|
119 | }
|
---|
120 |
|
---|
121 | /**
|
---|
122 | * Fired when a target is started.
|
---|
123 | */
|
---|
124 | public void targetStarted(BuildEvent event) {
|
---|
125 | wrappedListener.targetStarted(event);
|
---|
126 | checkInterrupted();
|
---|
127 | }
|
---|
128 |
|
---|
129 | /**
|
---|
130 | * Fired when a task has finished. This event will still
|
---|
131 | * be throw if an error occurred during the build.
|
---|
132 | */
|
---|
133 | public void taskFinished(BuildEvent event) {
|
---|
134 | wrappedListener.taskFinished(event);
|
---|
135 | checkInterrupted();
|
---|
136 | }
|
---|
137 |
|
---|
138 | /**
|
---|
139 | * Fired when a task is started.
|
---|
140 | */
|
---|
141 | public void taskStarted(BuildEvent event) {
|
---|
142 | wrappedListener.taskStarted(event);
|
---|
143 | checkInterrupted();
|
---|
144 | }
|
---|
145 | }
|
---|
146 |
|
---|
147 | // name of the VA project this BuildInfo belongs to
|
---|
148 | private String vajProjectName = "";
|
---|
149 |
|
---|
150 | // name of the Ant build file
|
---|
151 | private String buildFileName = "";
|
---|
152 |
|
---|
153 | // main targets found in the build file
|
---|
154 | private Vector projectTargets = new Vector();
|
---|
155 |
|
---|
156 | // target selected for execution
|
---|
157 | private String target = "";
|
---|
158 |
|
---|
159 | // log level
|
---|
160 | private int outputMessageLevel = Project.MSG_INFO;
|
---|
161 |
|
---|
162 | // Ant Project created from build file
|
---|
163 | private transient Project project;
|
---|
164 |
|
---|
165 | // is true if Project initialization was successful
|
---|
166 | private transient boolean projectInitialized = false;
|
---|
167 |
|
---|
168 | // Support for bound properties
|
---|
169 | protected transient PropertyChangeSupport propertyChange;
|
---|
170 |
|
---|
171 | // thread for Ant build execution
|
---|
172 | private Thread buildThread;
|
---|
173 |
|
---|
174 | // the listener used to log output.
|
---|
175 | private BuildListener projectLogger;
|
---|
176 |
|
---|
177 |
|
---|
178 | /**
|
---|
179 | * The addPropertyChangeListener method was generated to support the
|
---|
180 | * propertyChange field.
|
---|
181 | */
|
---|
182 | public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
|
---|
183 | getPropertyChange().addPropertyChangeListener(listener);
|
---|
184 | }
|
---|
185 |
|
---|
186 | /**
|
---|
187 | * Returns the BuildInfo information as String. The BuildInfo can
|
---|
188 | * be rebuilt from that String by calling parse().
|
---|
189 | * @return String
|
---|
190 | */
|
---|
191 | public String asDataString() {
|
---|
192 | String result = getOutputMessageLevel() + "|" + getBuildFileName()
|
---|
193 | + "|" + getTarget();
|
---|
194 | for (Enumeration e = getProjectTargets().elements();
|
---|
195 | e.hasMoreElements();) {
|
---|
196 | result = result + "|" + e.nextElement();
|
---|
197 | }
|
---|
198 |
|
---|
199 | return result;
|
---|
200 | }
|
---|
201 |
|
---|
202 | /**
|
---|
203 | * Search for the insert position to keep names a sorted list of Strings
|
---|
204 | * This method has been copied from org.apache.tools.ant.Main
|
---|
205 | */
|
---|
206 | private static int findTargetPosition(Vector names, String name) {
|
---|
207 | int res = names.size();
|
---|
208 | for (int i = 0; i < names.size() && res == names.size(); i++) {
|
---|
209 | if (name.compareTo((String) names.elementAt(i)) < 0) {
|
---|
210 | res = i;
|
---|
211 | }
|
---|
212 | }
|
---|
213 | return res;
|
---|
214 | }
|
---|
215 |
|
---|
216 | /**
|
---|
217 | * The firePropertyChange method was generated to support the propertyChange field.
|
---|
218 | */
|
---|
219 | public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
|
---|
220 | getPropertyChange().firePropertyChange(propertyName, oldValue, newValue);
|
---|
221 | }
|
---|
222 |
|
---|
223 | /**
|
---|
224 | * Returns the build file name.
|
---|
225 | * @return build file name.
|
---|
226 | */
|
---|
227 | public String getBuildFileName() {
|
---|
228 | return buildFileName;
|
---|
229 | }
|
---|
230 |
|
---|
231 | /**
|
---|
232 | * Returns the log level
|
---|
233 | * @return log level.
|
---|
234 | */
|
---|
235 | public int getOutputMessageLevel() {
|
---|
236 | return outputMessageLevel;
|
---|
237 | }
|
---|
238 |
|
---|
239 | /**
|
---|
240 | * Returns the Ant project
|
---|
241 | * @return org.apache.tools.ant.Project
|
---|
242 | */
|
---|
243 | private Project getProject() {
|
---|
244 | if (project == null) {
|
---|
245 | project = new Project();
|
---|
246 | }
|
---|
247 | return project;
|
---|
248 | }
|
---|
249 |
|
---|
250 | /**
|
---|
251 | * return a list of all targets in the current buildfile
|
---|
252 | */
|
---|
253 | public Vector getProjectTargets() {
|
---|
254 | return projectTargets;
|
---|
255 | }
|
---|
256 |
|
---|
257 | /**
|
---|
258 | * Accessor for the propertyChange field.
|
---|
259 | */
|
---|
260 | protected PropertyChangeSupport getPropertyChange() {
|
---|
261 | if (propertyChange == null) {
|
---|
262 | propertyChange = new PropertyChangeSupport(this);
|
---|
263 | }
|
---|
264 | return propertyChange;
|
---|
265 | }
|
---|
266 |
|
---|
267 | /**
|
---|
268 | * returns the selected target.
|
---|
269 | */
|
---|
270 | public String getTarget() {
|
---|
271 | return target;
|
---|
272 | }
|
---|
273 |
|
---|
274 | /**
|
---|
275 | * returns the VA project name
|
---|
276 | */
|
---|
277 | public String getVAJProjectName() {
|
---|
278 | return vajProjectName;
|
---|
279 | }
|
---|
280 |
|
---|
281 | /**
|
---|
282 | * Initializes the Ant project. Assumes that the
|
---|
283 | * project attribute is already set.
|
---|
284 | */
|
---|
285 | private void initProject() {
|
---|
286 | try {
|
---|
287 | project.init();
|
---|
288 | File buildFile = new File(getBuildFileName());
|
---|
289 | project.setUserProperty("ant.file", buildFile.getAbsolutePath());
|
---|
290 | ProjectHelper.configureProject(project, buildFile);
|
---|
291 | setProjectInitialized(true);
|
---|
292 | } catch (RuntimeException exc) {
|
---|
293 | setProjectInitialized(false);
|
---|
294 | throw exc;
|
---|
295 | } catch (Error err) {
|
---|
296 | setProjectInitialized(false);
|
---|
297 | throw err;
|
---|
298 | }
|
---|
299 | }
|
---|
300 |
|
---|
301 | /**
|
---|
302 | * Returns true, if the Ant project is initialized.
|
---|
303 | * (i.e., if the buildfile loaded).
|
---|
304 | */
|
---|
305 | public boolean isProjectInitialized() {
|
---|
306 | return projectInitialized;
|
---|
307 | }
|
---|
308 |
|
---|
309 | /**
|
---|
310 | * Creates a BuildInfo object from a String
|
---|
311 | * The String must be in the format
|
---|
312 | * outputMessageLevel'|'buildFileName'|'defaultTarget'|'(project target'|')*
|
---|
313 | *
|
---|
314 | * @return org.apache.tools.ant.taskdefs.optional.vaj.BuildInfo
|
---|
315 | * @param data String
|
---|
316 | */
|
---|
317 | public static VAJBuildInfo parse(String data) {
|
---|
318 | VAJBuildInfo result = new VAJBuildInfo();
|
---|
319 |
|
---|
320 | try {
|
---|
321 | StringTokenizer tok = new StringTokenizer(data, "|");
|
---|
322 | result.setOutputMessageLevel(tok.nextToken());
|
---|
323 | result.setBuildFileName(tok.nextToken());
|
---|
324 | result.setTarget(tok.nextToken());
|
---|
325 | while (tok.hasMoreTokens()) {
|
---|
326 | result.projectTargets.addElement(tok.nextToken());
|
---|
327 | }
|
---|
328 | } catch (Throwable t) {
|
---|
329 | // if parsing the info fails, just return
|
---|
330 | // an empty VAJBuildInfo
|
---|
331 | }
|
---|
332 | return result;
|
---|
333 | }
|
---|
334 |
|
---|
335 | /**
|
---|
336 | * The removePropertyChangeListener method was generated
|
---|
337 | * to support the propertyChange field.
|
---|
338 | */
|
---|
339 | public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
|
---|
340 | getPropertyChange().removePropertyChangeListener(listener);
|
---|
341 | }
|
---|
342 |
|
---|
343 | /**
|
---|
344 | * Sets the build file name
|
---|
345 | * @param buildFileName build file name
|
---|
346 | */
|
---|
347 | public void setBuildFileName(String newBuildFileName) {
|
---|
348 | String oldValue = buildFileName;
|
---|
349 | buildFileName = newBuildFileName;
|
---|
350 | setProjectInitialized(false);
|
---|
351 | firePropertyChange("buildFileName", oldValue, buildFileName);
|
---|
352 | }
|
---|
353 |
|
---|
354 | /**
|
---|
355 | * Sets the log level (value must be one of the constants in Project)
|
---|
356 | * @param outputMessageLevel log level.
|
---|
357 | */
|
---|
358 | public void setOutputMessageLevel(int newOutputMessageLevel) {
|
---|
359 | int oldValue = outputMessageLevel;
|
---|
360 | outputMessageLevel = newOutputMessageLevel;
|
---|
361 | firePropertyChange("outputMessageLevel",
|
---|
362 | new Integer(oldValue), new Integer(outputMessageLevel));
|
---|
363 | }
|
---|
364 |
|
---|
365 | /**
|
---|
366 | * Sets the log level (value must be one of the constants in Project)
|
---|
367 | * @param outputMessageLevel log level as String.
|
---|
368 | */
|
---|
369 | private void setOutputMessageLevel(String outputMessageLevel) {
|
---|
370 | int level = Integer.parseInt(outputMessageLevel);
|
---|
371 | setOutputMessageLevel(level);
|
---|
372 | }
|
---|
373 |
|
---|
374 | /**
|
---|
375 | * sets the initialized flag
|
---|
376 | */
|
---|
377 | private void setProjectInitialized(boolean initialized) {
|
---|
378 | Boolean oldValue = new Boolean(projectInitialized);
|
---|
379 | projectInitialized = initialized;
|
---|
380 | firePropertyChange("projectInitialized", oldValue, new Boolean(projectInitialized));
|
---|
381 | }
|
---|
382 |
|
---|
383 | /**
|
---|
384 | * Sets the target to execute when executeBuild is called
|
---|
385 | * @param newTarget build target
|
---|
386 | */
|
---|
387 | public void setTarget(String newTarget) {
|
---|
388 | String oldValue = target;
|
---|
389 | target = newTarget;
|
---|
390 | firePropertyChange("target", oldValue, target);
|
---|
391 | }
|
---|
392 |
|
---|
393 | /**
|
---|
394 | * Sets the name of the Visual Age for Java project where
|
---|
395 | * this BuildInfo belongs to
|
---|
396 | * @param newProjectName VAJ project
|
---|
397 | */
|
---|
398 | public void setVAJProjectName(String newVAJProjectName) {
|
---|
399 | String oldValue = vajProjectName;
|
---|
400 | vajProjectName = newVAJProjectName;
|
---|
401 | firePropertyChange("VAJProjectName", oldValue, vajProjectName);
|
---|
402 | }
|
---|
403 |
|
---|
404 | /**
|
---|
405 | * reloads the build file and updates the target list
|
---|
406 | */
|
---|
407 | public void updateTargetList() {
|
---|
408 | project = new Project();
|
---|
409 | initProject();
|
---|
410 | projectTargets.removeAllElements();
|
---|
411 | Enumeration ptargets = project.getTargets().elements();
|
---|
412 | while (ptargets.hasMoreElements()) {
|
---|
413 | Target currentTarget = (Target) ptargets.nextElement();
|
---|
414 | if (currentTarget.getDescription() != null) {
|
---|
415 | String targetName = currentTarget.getName();
|
---|
416 | int pos = findTargetPosition(projectTargets, targetName);
|
---|
417 | projectTargets.insertElementAt(targetName, pos);
|
---|
418 | }
|
---|
419 | }
|
---|
420 | }
|
---|
421 |
|
---|
422 |
|
---|
423 | /**
|
---|
424 | * cancels a build.
|
---|
425 | */
|
---|
426 | public void cancelBuild() {
|
---|
427 | buildThread.interrupt();
|
---|
428 | }
|
---|
429 |
|
---|
430 | /**
|
---|
431 | * Executes the target set by setTarget().
|
---|
432 | * @param listener BuildListener for the output of the build
|
---|
433 | */
|
---|
434 | public void executeProject(BuildListener logger) {
|
---|
435 | Throwable error;
|
---|
436 | projectLogger = logger;
|
---|
437 | try {
|
---|
438 | buildThread = new Thread(this);
|
---|
439 | buildThread.setPriority(Thread.MIN_PRIORITY);
|
---|
440 | buildThread.start();
|
---|
441 | } catch (RuntimeException exc) {
|
---|
442 | error = exc;
|
---|
443 | throw exc;
|
---|
444 | } catch (Error err) {
|
---|
445 | error = err;
|
---|
446 | throw err;
|
---|
447 | }
|
---|
448 | }
|
---|
449 |
|
---|
450 | /**
|
---|
451 | * Executes a build. This method is executed by
|
---|
452 | * the Ant execution thread
|
---|
453 | */
|
---|
454 | public void run() {
|
---|
455 | try {
|
---|
456 | InterruptedChecker ic = new InterruptedChecker(projectLogger);
|
---|
457 | BuildEvent e = new BuildEvent(getProject());
|
---|
458 | try {
|
---|
459 | ic.buildStarted(e);
|
---|
460 |
|
---|
461 | if (!isProjectInitialized()) {
|
---|
462 | initProject();
|
---|
463 | }
|
---|
464 |
|
---|
465 | project.addBuildListener(ic);
|
---|
466 | project.executeTarget(target);
|
---|
467 |
|
---|
468 | ic.buildFinished(e);
|
---|
469 | } catch (Throwable t) {
|
---|
470 | e.setException(t);
|
---|
471 | ic.buildFinished(e);
|
---|
472 | } finally {
|
---|
473 | project.removeBuildListener(ic);
|
---|
474 | }
|
---|
475 | } catch (Throwable t2) {
|
---|
476 | System.out.println("unexpected exception!");
|
---|
477 | t2.printStackTrace();
|
---|
478 | }
|
---|
479 | }
|
---|
480 | }
|
---|