1 package com
.intellij
.lang
.ant
.config
.impl
;
3 import com
.intellij
.codeInsight
.daemon
.DaemonCodeAnalyzer
;
4 import com
.intellij
.execution
.configurations
.ConfigurationType
;
5 import com
.intellij
.execution
.configurations
.RunConfiguration
;
6 import com
.intellij
.ide
.DataAccessors
;
7 import com
.intellij
.lang
.ant
.AntBundle
;
8 import com
.intellij
.lang
.ant
.AntSupport
;
9 import com
.intellij
.lang
.ant
.config
.*;
10 import com
.intellij
.lang
.ant
.config
.actions
.TargetAction
;
11 import com
.intellij
.lang
.ant
.psi
.AntFile
;
12 import com
.intellij
.lang
.ant
.psi
.impl
.AntFileImpl
;
13 import com
.intellij
.openapi
.actionSystem
.AnAction
;
14 import com
.intellij
.openapi
.actionSystem
.DataContext
;
15 import com
.intellij
.openapi
.actionSystem
.ex
.ActionManagerEx
;
16 import com
.intellij
.openapi
.application
.Application
;
17 import com
.intellij
.openapi
.application
.ApplicationManager
;
18 import com
.intellij
.openapi
.application
.ModalityState
;
19 import com
.intellij
.openapi
.components
.PersistentStateComponent
;
20 import com
.intellij
.openapi
.components
.State
;
21 import com
.intellij
.openapi
.components
.Storage
;
22 import com
.intellij
.openapi
.components
.StorageScheme
;
23 import com
.intellij
.openapi
.diagnostic
.Logger
;
24 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
25 import com
.intellij
.openapi
.progress
.ProgressManager
;
26 import com
.intellij
.openapi
.progress
.Task
;
27 import com
.intellij
.openapi
.project
.Project
;
28 import com
.intellij
.openapi
.roots
.ProjectRootManager
;
29 import com
.intellij
.openapi
.startup
.StartupManager
;
30 import com
.intellij
.openapi
.util
.*;
31 import com
.intellij
.openapi
.vfs
.VirtualFile
;
32 import com
.intellij
.openapi
.vfs
.VirtualFileAdapter
;
33 import com
.intellij
.openapi
.vfs
.VirtualFileEvent
;
34 import com
.intellij
.openapi
.vfs
.VirtualFileManager
;
35 import com
.intellij
.psi
.PsiDocumentManager
;
36 import com
.intellij
.psi
.PsiElement
;
37 import com
.intellij
.psi
.PsiFile
;
38 import com
.intellij
.psi
.PsiManager
;
39 import com
.intellij
.psi
.xml
.XmlFile
;
40 import com
.intellij
.util
.ActionRunner
;
41 import com
.intellij
.util
.EventDispatcher
;
42 import com
.intellij
.util
.StringSetSpinAllocator
;
43 import com
.intellij
.util
.concurrency
.Semaphore
;
44 import com
.intellij
.util
.config
.AbstractProperty
;
45 import com
.intellij
.util
.config
.ValueProperty
;
46 import com
.intellij
.util
.containers
.HashMap
;
47 import org
.jdom
.Element
;
48 import org
.jetbrains
.annotations
.NonNls
;
49 import org
.jetbrains
.annotations
.NotNull
;
50 import org
.jetbrains
.annotations
.Nullable
;
56 name
= "AntConfiguration",
58 @Storage(id
= "default", file
= "$PROJECT_FILE$"),
59 @Storage(id
= "dir", file
= "$PROJECT_CONFIG_DIR$/ant.xml", scheme
= StorageScheme
.DIRECTORY_BASED
)
62 public class AntConfigurationImpl
extends AntConfigurationBase
implements PersistentStateComponent
<Element
>, ModificationTracker
{
64 public static final ValueProperty
<AntReference
> DEFAULT_ANT
= new ValueProperty
<AntReference
>("defaultAnt", AntReference
.BUNDLED_ANT
);
65 public static final ValueProperty
<AntConfiguration
> INSTANCE
= new ValueProperty
<AntConfiguration
>("$instance", null);
66 public static final AbstractProperty
<String
> DEFAULT_JDK_NAME
= new AbstractProperty
<String
>() {
67 public String
getName() {
68 return "$defaultJDKName";
72 public String
getDefault(final AbstractPropertyContainer container
) {
73 return get(container
);
77 public String
get(final AbstractPropertyContainer container
) {
78 if (!container
.hasProperty(this)) return null;
79 AntConfiguration antConfiguration
= AntConfigurationImpl
.INSTANCE
.get(container
);
80 return ProjectRootManager
.getInstance(antConfiguration
.getProject()).getProjectJdkName();
83 public String
copy(final String jdkName
) {
88 private static final Logger LOG
= Logger
.getInstance("#com.intellij.lang.ant.config.impl.AntConfigurationImpl");
89 @NonNls private static final String BUILD_FILE
= "buildFile";
90 @NonNls private static final String CONTEXT_MAPPING
= "contextMapping";
91 @NonNls private static final String CONTEXT
= "context";
92 @NonNls private static final String URL
= "url";
93 @NonNls private static final String EXECUTE_ON_ELEMENT
= "executeOn";
94 @NonNls private static final String EVENT_ELEMENT
= "event";
95 @NonNls private static final String TARGET_ELEMENT
= "target";
97 private final PsiManager myPsiManager
;
98 private final Map
<ExecutionEvent
, Pair
<AntBuildFile
, String
>> myEventToTargetMap
=
99 new HashMap
<ExecutionEvent
, Pair
<AntBuildFile
, String
>>();
100 private final List
<AntBuildFile
> myBuildFiles
= new ArrayList
<AntBuildFile
>();
101 private AntBuildFile
[] myBuildFilesArray
= null; // cached result of call to myBuildFiles.toArray()
102 private final Map
<AntBuildFile
, AntBuildModelBase
> myModelToBuildFileMap
= new HashMap
<AntBuildFile
, AntBuildModelBase
>();
103 private final Map
<VirtualFile
, VirtualFile
> myAntFileToContextFileMap
= new java
.util
.HashMap
<VirtualFile
, VirtualFile
>();
104 private final EventDispatcher
<AntConfigurationListener
> myEventDispatcher
= EventDispatcher
.create(AntConfigurationListener
.class);
105 private final AntWorkspaceConfiguration myAntWorkspaceConfiguration
;
106 private final StartupManager myStartupManager
;
107 private boolean myInitializing
;
108 private volatile long myModificationCount
= 0;
110 public AntConfigurationImpl(final Project project
, final AntWorkspaceConfiguration antWorkspaceConfiguration
, final DaemonCodeAnalyzer daemon
) {
112 getProperties().registerProperty(DEFAULT_ANT
, AntReference
.EXTERNALIZER
);
113 getProperties().rememberKey(INSTANCE
);
114 getProperties().rememberKey(DEFAULT_JDK_NAME
);
115 INSTANCE
.set(getProperties(), this);
116 myAntWorkspaceConfiguration
= antWorkspaceConfiguration
;
117 myPsiManager
= PsiManager
.getInstance(project
);
118 myStartupManager
= StartupManager
.getInstance(project
);
119 addAntConfigurationListener(new AntConfigurationListener() {
120 public void configurationLoaded() {
123 public void buildFileChanged(final AntBuildFile buildFile
) {
126 public void buildFileAdded(final AntBuildFile buildFile
) {
129 public void buildFileRemoved(final AntBuildFile buildFile
) {
132 private void restartDaemon() {
133 if (ApplicationManager
.getApplication().isDispatchThread()) {
137 SwingUtilities
.invokeLater(new Runnable() {
145 VirtualFileManager
.getInstance().addVirtualFileListener(new VirtualFileAdapter() {
146 public void beforeFileDeletion(final VirtualFileEvent event
) {
147 final VirtualFile vFile
= event
.getFile();
149 for (AntBuildFile file
: getBuildFiles()) {
150 if (vFile
.equals(file
.getVirtualFile())) {
151 removeBuildFile(file
);
155 for (Iterator
<Map
.Entry
<VirtualFile
,VirtualFile
>> it
= myAntFileToContextFileMap
.entrySet().iterator(); it
.hasNext();) {
156 final Map
.Entry
<VirtualFile
, VirtualFile
> entry
= it
.next();
157 if (vFile
.equals(entry
.getKey()) || vFile
.equals(entry
.getValue())) {
166 public Element
getState() {
168 final Element e
= new Element("state");
172 catch (WriteExternalException e1
) {
178 public void loadState(Element state
) {
182 catch (InvalidDataException e
) {
187 private volatile Boolean myIsInitialized
= null;
189 public boolean isInitialized() {
190 final Boolean initialized
= myIsInitialized
;
191 return initialized
== null || initialized
.booleanValue();
194 public AntBuildFile
[] getBuildFiles() {
195 synchronized (myBuildFiles
) {
196 if (myBuildFilesArray
== null) {
197 myBuildFilesArray
= myBuildFiles
.toArray(new AntBuildFile
[myBuildFiles
.size()]);
199 return myBuildFilesArray
;
203 public AntBuildFile
addBuildFile(final VirtualFile file
) throws AntNoFileException
{
204 final AntBuildFile
[] result
= new AntBuildFile
[]{null};
205 final AntNoFileException
[] ex
= new AntNoFileException
[]{null};
206 final String title
= AntBundle
.message("register.ant.build.progress", file
.getPresentableUrl());
207 ProgressManager
.getInstance().run(new Task
.Modal(getProject(), title
, false) {
209 public NotificationInfo
getNotificationInfo() {
210 return new NotificationInfo("Ant", "Ant Task Finished", "");
213 public void run(@NotNull final ProgressIndicator indicator
) {
214 indicator
.setIndeterminate(true);
215 indicator
.pushState();
217 indicator
.setText(title
);
218 myModificationCount
++;
219 ApplicationManager
.getApplication().runReadAction(new Runnable() {
222 result
[0] = addBuildFileImpl(file
);
223 updateRegisteredActions();
225 catch (AntNoFileException e
) {
230 if (result
[0] != null) {
231 ApplicationManager
.getApplication().invokeLater(new Runnable() {
233 myEventDispatcher
.getMulticaster().buildFileAdded(result
[0]);
239 indicator
.popState();
249 public void removeBuildFile(final AntBuildFile file
) {
250 myModificationCount
++;
251 removeBuildFileImpl(file
);
252 updateRegisteredActions();
255 public void addAntConfigurationListener(final AntConfigurationListener listener
) {
256 myEventDispatcher
.addListener(listener
);
259 public void removeAntConfigurationListener(final AntConfigurationListener listener
) {
260 myEventDispatcher
.removeListener(listener
);
263 public boolean isFilterTargets() {
264 return myAntWorkspaceConfiguration
.FILTER_TARGETS
;
267 public void setFilterTargets(final boolean value
) {
268 myAntWorkspaceConfiguration
.FILTER_TARGETS
= value
;
271 public AntBuildTarget
[] getMetaTargets(final AntBuildFile buildFile
) {
272 final List
<ExecutionEvent
> events
= getEventsByClass(ExecuteCompositeTargetEvent
.class);
273 if (events
.size() == 0) {
274 return AntBuildTargetBase
.EMPTY_ARRAY
;
276 final List
<AntBuildTargetBase
> targets
= new ArrayList
<AntBuildTargetBase
>();
277 for (ExecutionEvent event
: events
) {
278 final MetaTarget target
= (MetaTarget
)getTargetForEvent(event
);
279 if (target
!= null && buildFile
.equals(target
.getBuildFile())) {
283 return targets
.toArray(new AntBuildTargetBase
[targets
.size()]);
286 public List
<ExecutionEvent
> getEventsForTarget(final AntBuildTarget target
) {
287 final List
<ExecutionEvent
> list
= new ArrayList
<ExecutionEvent
>();
288 synchronized (myEventToTargetMap
) {
289 for (final ExecutionEvent event
: myEventToTargetMap
.keySet()) {
290 final AntBuildTarget targetForEvent
= getTargetForEvent(event
);
291 if (target
.equals(targetForEvent
)) {
300 public AntBuildTarget
getTargetForEvent(final ExecutionEvent event
) {
301 final Pair
<AntBuildFile
, String
> pair
;
302 synchronized (myEventToTargetMap
) {
303 pair
= myEventToTargetMap
.get(event
);
308 final AntBuildFileBase buildFile
= (AntBuildFileBase
)pair
.first
;
309 synchronized (myBuildFiles
) {
310 if (!myBuildFiles
.contains(buildFile
)) {
311 return null; // file was removed
314 final String targetName
= (String
)pair
.second
;
316 final AntBuildTarget antBuildTarget
= buildFile
.getModel().findTarget(targetName
);
317 if (antBuildTarget
!= null) {
318 return antBuildTarget
;
320 final List
<ExecutionEvent
> events
= getEventsByClass(ExecuteCompositeTargetEvent
.class);
321 if (events
.size() == 0) {
324 for (ExecutionEvent ev
: events
) {
325 final String presentableName
= ev
.getPresentableName();
326 if (Comparing
.strEqual(targetName
, presentableName
)) {
327 return new MetaTarget(buildFile
, presentableName
, ((ExecuteCompositeTargetEvent
)ev
).getTargetNames());
333 public void setTargetForEvent(final AntBuildFile buildFile
, final String targetName
, final ExecutionEvent event
) {
334 synchronized (myEventToTargetMap
) {
335 myEventToTargetMap
.put(event
, new Pair
<AntBuildFile
, String
>(buildFile
, targetName
));
339 public void clearTargetForEvent(final ExecutionEvent event
) {
340 synchronized (myEventToTargetMap
) {
341 myEventToTargetMap
.remove(event
);
345 public void updateBuildFile(final AntBuildFile buildFile
) {
346 myModificationCount
++;
347 myEventDispatcher
.getMulticaster().buildFileChanged(buildFile
);
348 updateRegisteredActions();
351 public boolean isAutoScrollToSource() {
352 return myAntWorkspaceConfiguration
.IS_AUTOSCROLL_TO_SOURCE
;
355 public void setAutoScrollToSource(final boolean value
) {
356 myAntWorkspaceConfiguration
.IS_AUTOSCROLL_TO_SOURCE
= value
;
359 public AntInstallation
getProjectDefaultAnt() {
360 return DEFAULT_ANT
.get(getProperties()).find(GlobalAntConfiguration
.getInstance());
364 public AntBuildModel
getModelIfRegistered(final AntBuildFile buildFile
) {
365 synchronized (myBuildFiles
) {
366 if (!myBuildFiles
.contains(buildFile
)) {
370 return getModel(buildFile
);
373 public long getModificationCount() {
374 return myModificationCount
;
377 private void readExternal(final Element parentNode
) throws InvalidDataException
{
378 myIsInitialized
= Boolean
.FALSE
;
379 myAntWorkspaceConfiguration
.loadFromProjectSettings(parentNode
);
380 getProperties().readExternal(parentNode
);
381 runWhenInitialized(new Runnable() {
383 loadBuildFileProjectProperties(parentNode
);
388 private void runWhenInitialized(final Runnable runnable
) {
389 if (getProject().isInitialized()) {
390 ApplicationManager
.getApplication().runReadAction(new Runnable() {
397 myStartupManager
.registerPostStartupActivity(new Runnable() {
405 private void writeExternal(final Element parentNode
) throws WriteExternalException
{
406 getProperties().writeExternal(parentNode
);
408 ActionRunner
.runInsideReadAction(new ActionRunner
.InterruptibleRunnable() {
409 public void run() throws WriteExternalException
{
410 for (final AntBuildFile buildFile
: getBuildFiles()) {
411 final Element element
= new Element(BUILD_FILE
);
412 element
.setAttribute(URL
, buildFile
.getVirtualFile().getUrl());
413 ((AntBuildFileBase
)buildFile
).writeProperties(element
);
414 saveEvents(element
, buildFile
);
415 parentNode
.addContent(element
);
417 final List
<VirtualFile
> files
= new ArrayList
<VirtualFile
>(myAntFileToContextFileMap
.keySet());
418 // sort in order to minimize changes
419 Collections
.sort(files
, new Comparator
<VirtualFile
>() {
420 public int compare(final VirtualFile o1
, final VirtualFile o2
) {
421 return o1
.getUrl().compareTo(o2
.getUrl());
424 for (VirtualFile file
: files
) {
425 final Element element
= new Element(CONTEXT_MAPPING
);
426 final VirtualFile contextFile
= myAntFileToContextFileMap
.get(file
);
427 element
.setAttribute(URL
, file
.getUrl());
428 element
.setAttribute(CONTEXT
, contextFile
.getUrl());
429 parentNode
.addContent(element
);
434 catch (WriteExternalException e
) {
438 catch (RuntimeException e
) {
442 catch (Exception e
) {
447 private void saveEvents(final Element element
, final AntBuildFile buildFile
) {
448 List
<Element
> events
= null;
449 final Set
<String
> savedEvents
= new HashSet
<String
>();
450 synchronized (myEventToTargetMap
) {
451 for (final ExecutionEvent event
: myEventToTargetMap
.keySet()) {
452 final Pair
<AntBuildFile
, String
> pair
= myEventToTargetMap
.get(event
);
453 if (!buildFile
.equals(pair
.first
)) {
456 Element eventElement
= new Element(EXECUTE_ON_ELEMENT
);
457 eventElement
.setAttribute(EVENT_ELEMENT
, event
.getTypeId());
458 eventElement
.setAttribute(TARGET_ELEMENT
, pair
.second
);
460 final String id
= event
.writeExternal(eventElement
, getProject());
461 if (savedEvents
.contains(id
)) continue;
464 if (events
== null) {
465 events
= new ArrayList
<Element
>();
467 events
.add(eventElement
);
471 if (events
!= null) {
472 Collections
.sort(events
, EventElementComparator
.INSTANCE
);
473 for (Element eventElement
: events
) {
474 element
.addContent(eventElement
);
479 public AntBuildModel
getModel(final AntBuildFile buildFile
) {
480 AntBuildModelBase model
= myModelToBuildFileMap
.get(buildFile
);
482 model
= createModel(buildFile
);
483 myModelToBuildFileMap
.put(buildFile
, model
);
489 public AntBuildFile
findBuildFileByActionId(final String id
) {
490 for (AntBuildFile buildFile
: getBuildFiles()) {
491 AntBuildModelBase model
= (AntBuildModelBase
)buildFile
.getModel();
492 if (id
.equals(model
.getDefaultTargetActionId())) {
495 if (model
.hasTargetWithActionId(id
)) return buildFile
;
500 public boolean hasTasksToExecuteBeforeRun(final RunConfiguration configuration
) {
501 return findExecuteBeforeRunEvent(configuration
) != null;
504 public boolean executeTaskBeforeRun(final DataContext context
, final RunConfiguration configuration
) {
505 final ExecuteBeforeRunEvent foundEvent
= findExecuteBeforeRunEvent(configuration
);
506 return runTargetSynchronously(context
, foundEvent
);
509 public AntBuildTarget
getTargetForBeforeRunEvent(RunConfiguration configuration
) {
510 return getTargetForEvent(new ExecuteBeforeRunEvent(configuration
));
513 public void setTargetForBeforeRunEvent(AntBuildFile buildFile
,
515 RunConfiguration configuration
) {
516 setTargetForEvent(buildFile
, targetName
, new ExecuteBeforeRunEvent(configuration
));
519 private AntBuildModelBase
createModel(final AntBuildFile buildFile
) {
520 if (ApplicationManager
.getApplication().isDispatchThread()) {
521 // otherwise commitAllDocuments() must have been called before the whole process was started
522 PsiDocumentManager
.getInstance(getProject()).commitAllDocuments();
524 return new AntBuildModelImpl(buildFile
);
527 private AntBuildFileBase
addBuildFileImpl(final VirtualFile file
) throws AntNoFileException
{
528 PsiFile psiFile
= myPsiManager
.findFile(file
);
529 if (psiFile
== null) {
530 throw new AntNoFileException(AntBundle
.message("cant.add.file.error.message"), file
);
532 AntSupport
.markFileAsAntFile(file
, psiFile
.getViewProvider(), true);
533 psiFile
= AntSupport
.getAntFile(psiFile
);
534 if (psiFile
== null) {
535 throw new AntNoFileException(AntBundle
.message("cant.add.file.error.message"), file
);
537 final AntFile antFile
= (AntFile
)psiFile
;
538 final AntBuildFileImpl buildFile
= new AntBuildFileImpl(antFile
, this);
539 antFile
.getSourceElement().putCopyableUserData(AntFileImpl
.ANT_BUILD_FILE
, buildFile
);
540 synchronized (myBuildFiles
) {
541 myBuildFilesArray
= null;
542 myBuildFiles
.add(buildFile
);
547 private void updateRegisteredActions() {
549 final List
<Pair
<String
, AnAction
>> actionList
= new ArrayList
<Pair
<String
, AnAction
>>();
550 for (final AntBuildFile buildFile
: getBuildFiles()) {
551 final AntBuildModelBase model
= (AntBuildModelBase
)buildFile
.getModel();
552 String defaultTargetActionId
= model
.getDefaultTargetActionId();
553 if (defaultTargetActionId
!= null) {
554 final TargetAction action
=
555 new TargetAction(buildFile
, TargetAction
.DEFAULT_TARGET_NAME
, new String
[]{TargetAction
.DEFAULT_TARGET_NAME
}, null);
556 actionList
.add(new Pair
<String
, AnAction
>(defaultTargetActionId
, action
));
559 collectTargetActions(model
.getFilteredTargets(), actionList
, buildFile
);
560 collectTargetActions(getMetaTargets(buildFile
), actionList
, buildFile
);
563 synchronized (this) {
564 // unregister Ant actions
565 ActionManagerEx actionManager
= ActionManagerEx
.getInstanceEx();
566 final String
[] oldIds
= actionManager
.getActionIds(AntConfiguration
.getActionIdPrefix(getProject()));
567 for (String oldId
: oldIds
) {
568 actionManager
.unregisterAction(oldId
);
570 final Set
<String
> registeredIds
= StringSetSpinAllocator
.alloc();
572 for (Pair
<String
, AnAction
> pair
: actionList
) {
573 if (!registeredIds
.contains(pair
.first
)) {
574 registeredIds
.add(pair
.first
);
575 actionManager
.registerAction(pair
.first
, pair
.second
);
580 StringSetSpinAllocator
.dispose(registeredIds
);
585 private static void collectTargetActions(final AntBuildTarget
[] targets
,
586 final List
<Pair
<String
, AnAction
>> actionList
,
587 final AntBuildFile buildFile
) {
588 for (final AntBuildTarget target
: targets
) {
589 final String actionId
= ((AntBuildTargetBase
)target
).getActionId();
590 if (actionId
!= null) {
591 final TargetAction action
=
592 new TargetAction(buildFile
, target
.getName(), new String
[]{target
.getName()}, target
.getNotEmptyDescription());
593 actionList
.add(new Pair
<String
, AnAction
>(actionId
, action
));
598 private void removeBuildFileImpl(AntBuildFile buildFile
) {
599 final XmlFile xmlFile
= ((AntFile
)buildFile
.getAntFile()).getSourceElement();
600 xmlFile
.putCopyableUserData(AntFileImpl
.ANT_BUILD_FILE
, null);
601 AntSupport
.markFileAsAntFile(xmlFile
.getVirtualFile(), xmlFile
.getViewProvider(), false);
602 synchronized (myBuildFiles
) {
603 myBuildFilesArray
= null;
604 myBuildFiles
.remove(buildFile
);
606 myModelToBuildFileMap
.remove(buildFile
);
607 myEventDispatcher
.getMulticaster().buildFileRemoved(buildFile
);
610 public boolean executeTargetBeforeCompile(final DataContext context
) {
611 return runTargetSynchronously(context
, ExecuteBeforeCompilationEvent
.getInstance());
614 public boolean executeTargetAfterCompile(final DataContext context
) {
615 return runTargetSynchronously(context
, ExecuteAfterCompilationEvent
.getInstance());
618 private boolean runTargetSynchronously(final DataContext dataContext
, ExecutionEvent event
) {
619 if (ApplicationManager
.getApplication().isDispatchThread()) {
620 throw new IllegalStateException("Called in the event dispatch thread");
622 final AntBuildTarget target
= getTargetForEvent(event
);
623 if (target
== null) {
627 final Semaphore targetDone
= new Semaphore();
628 final boolean[] result
= new boolean[1];
630 ApplicationManager
.getApplication().invokeAndWait(new Runnable() {
633 Project project
= DataAccessors
.PROJECT
.from(dataContext
);
634 if (project
== null || project
.isDisposed()) {
639 target
.run(dataContext
, new AntBuildListener() {
640 public void buildFinished(int state
, int errorCount
) {
641 result
[0] = (state
== AntBuildListener
.FINISHED_SUCCESSFULLY
) && (errorCount
== 0);
646 }, ModalityState
.NON_MODAL
);
648 catch (Exception e
) {
652 targetDone
.waitFor();
656 private List
<ExecutionEvent
> getEventsByClass(Class eventClass
) {
657 if (!myInitializing
) ensureInitialized();
658 final List
<ExecutionEvent
> list
= new ArrayList
<ExecutionEvent
>();
659 synchronized (myEventToTargetMap
) {
660 for (final ExecutionEvent event
: myEventToTargetMap
.keySet()) {
661 if (eventClass
.isInstance(event
)) {
669 private void loadBuildFileProjectProperties(final Element parentNode
) {
670 final List
<Pair
<Element
, VirtualFile
>> files
= new ArrayList
<Pair
<Element
, VirtualFile
>>();
671 final VirtualFileManager vfManager
= VirtualFileManager
.getInstance();
672 for (final Object o
: parentNode
.getChildren(BUILD_FILE
)) {
673 final Element element
= (Element
)o
;
674 final String url
= element
.getAttributeValue(URL
);
675 final VirtualFile file
= vfManager
.findFileByUrl(url
);
677 files
.add(new Pair
<Element
, VirtualFile
>(element
, file
));
682 myAntFileToContextFileMap
.clear();
683 for (final Object o
: parentNode
.getChildren(CONTEXT_MAPPING
)) {
684 final Element element
= (Element
)o
;
685 final String url
= element
.getAttributeValue(URL
);
686 final String contextUrl
= element
.getAttributeValue(CONTEXT
);
687 final VirtualFile file
= vfManager
.findFileByUrl(url
);
688 final VirtualFile contextFile
= vfManager
.findFileByUrl(contextUrl
);
689 if (file
!= null && contextFile
!= null) {
690 myAntFileToContextFileMap
.put(file
, contextFile
);
694 final String title
= AntBundle
.message("loading.ant.config.progress");
695 queueLater(new Task
.Backgroundable(getProject(), title
, false) {
696 public void run(@NotNull final ProgressIndicator indicator
) {
697 indicator
.setIndeterminate(true);
698 indicator
.pushState();
700 indicator
.setText(title
);
701 ApplicationManager
.getApplication().runReadAction(new Runnable() {
704 myInitializing
= true;
705 // first, remove existing files
706 final AntBuildFile
[] currentFiles
= getBuildFiles();
707 for (AntBuildFile file
: currentFiles
) {
708 removeBuildFile(file
);
710 // then fill the configuration with the files configured in xml
711 List
<Pair
<Element
, AntBuildFileBase
>> buildFiles
= new ArrayList
<Pair
<Element
, AntBuildFileBase
>>(files
.size());
712 for (Pair
<Element
, VirtualFile
> pair
: files
) {
713 final Element element
= pair
.getFirst();
714 final VirtualFile file
= pair
.getSecond();
716 final AntBuildFileBase buildFile
= addBuildFileImpl(file
);
717 buildFile
.readProperties(element
);
718 buildFiles
.add(new Pair
<Element
, AntBuildFileBase
>(element
, buildFile
));
720 catch (AntNoFileException ignored
) {
722 catch (InvalidDataException e
) {
726 // updating properties separately to avoid unnecesary building of PSI after clearing caches
727 for (Pair
<Element
, AntBuildFileBase
> pair
: buildFiles
) {
728 final AntBuildFileBase buildFile
= pair
.getSecond();
729 buildFile
.updateProperties();
730 for (final Object o1
: pair
.getFirst().getChildren(EXECUTE_ON_ELEMENT
)) {
731 Element e
= (Element
)o1
;
732 String eventId
= e
.getAttributeValue(EVENT_ELEMENT
);
733 ExecutionEvent event
= null;
734 String targetName
= e
.getAttributeValue(TARGET_ELEMENT
);
735 if (ExecuteBeforeCompilationEvent
.TYPE_ID
.equals(eventId
)) {
736 event
= ExecuteBeforeCompilationEvent
.getInstance();
738 else if (ExecuteAfterCompilationEvent
.TYPE_ID
.equals(eventId
)) {
739 event
= ExecuteAfterCompilationEvent
.getInstance();
741 else if (ExecuteBeforeRunEvent
.TYPE_ID
.equals(eventId
)) {
742 event
= new ExecuteBeforeRunEvent();
744 else if (ExecuteCompositeTargetEvent
.TYPE_ID
.equals(eventId
)) {
746 event
= new ExecuteCompositeTargetEvent(targetName
);
748 catch (WrongNameFormatException e1
) {
755 event
.readExternal(e
, getProject());
756 setTargetForEvent(buildFile
, targetName
, event
);
758 catch (InvalidDataException readFailed
) {
759 LOG
.info(readFailed
.getMessage());
764 AntWorkspaceConfiguration
.getInstance(getProject()).loadFileProperties();
766 catch (InvalidDataException e
) {
770 updateRegisteredActions();
771 myInitializing
= false;
772 myIsInitialized
= Boolean
.TRUE
;
773 ApplicationManager
.getApplication().invokeLater(new Runnable() {
775 myEventDispatcher
.getMulticaster().configurationLoaded();
783 indicator
.popState();
789 private static void queueLater(final Task task
) {
790 final Application app
= ApplicationManager
.getApplication();
791 if (app
.isDispatchThread()) {
794 app
.invokeLater(new Runnable() {
802 public void setContextFile(@NotNull AntFile file
, @Nullable AntFile context
) {
803 if (context
!= null) {
804 myAntFileToContextFileMap
.put(file
.getVirtualFile(), context
.getVirtualFile());
807 myAntFileToContextFileMap
.remove(file
.getVirtualFile());
812 public AntFile
getContextFile(@Nullable final AntFile file
) {
813 return file
!= null? AntSupport
.toAntFile(myAntFileToContextFileMap
.get(file
.getVirtualFile()), getProject()) : null;
817 public AntFile
getEffectiveContextFile(final AntFile file
) {
818 return new Object() {
820 AntFile
findContext(final AntFile file
, Set
<PsiElement
> processed
) {
823 final AntFile contextFile
= AntSupport
.toAntFile(myAntFileToContextFileMap
.get(file
.getVirtualFile()), getProject());
824 return (contextFile
== null || processed
.contains(contextFile
))? file
: findContext(contextFile
, processed
);
828 }.findContext(file
, new HashSet
<PsiElement
>());
832 ExecuteBeforeRunEvent
findExecuteBeforeRunEvent(RunConfiguration configuration
) {
833 final ConfigurationType type
= configuration
.getType();
834 for (final ExecutionEvent e
: getEventsByClass(ExecuteBeforeRunEvent
.class)) {
835 final ExecuteBeforeRunEvent event
= (ExecuteBeforeRunEvent
)e
;
836 if (event
.isFor(type
) || event
.isFor(configuration
)) return event
;
841 private static class EventElementComparator
implements Comparator
<Element
> {
842 static final Comparator
<?
super Element
> INSTANCE
= new EventElementComparator();
844 private static final String
[] COMPARABLE_ATTRIB_NAMES
= new String
[] {
847 ExecuteBeforeRunEvent
.RUN_CONFIGURATION_TYPE_ATTR
,
848 ExecuteBeforeRunEvent
.RUN_CONFIUGRATION_NAME_ATTR
,
849 ExecuteCompositeTargetEvent
.PRESENTABLE_NAME
852 public int compare(final Element o1
, final Element o2
) {
853 for (String attribName
: COMPARABLE_ATTRIB_NAMES
) {
854 final int valuesEqual
= Comparing
.compare(o1
.getAttributeValue(attribName
), o2
.getAttributeValue(attribName
));
855 if (valuesEqual
!= 0) {