2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.jetbrains
.idea
.maven
.project
;
18 import com
.intellij
.ide
.startup
.StartupManagerEx
;
19 import com
.intellij
.openapi
.application
.ApplicationManager
;
20 import com
.intellij
.openapi
.application
.Result
;
21 import com
.intellij
.openapi
.command
.WriteCommandAction
;
22 import com
.intellij
.openapi
.components
.PersistentStateComponent
;
23 import com
.intellij
.openapi
.components
.SettingsSavingComponent
;
24 import com
.intellij
.openapi
.components
.State
;
25 import com
.intellij
.openapi
.components
.Storage
;
26 import com
.intellij
.openapi
.editor
.Editor
;
27 import com
.intellij
.openapi
.fileEditor
.FileDocumentManager
;
28 import com
.intellij
.openapi
.fileEditor
.FileEditorManager
;
29 import com
.intellij
.openapi
.module
.Module
;
30 import com
.intellij
.openapi
.project
.DumbAwareRunnable
;
31 import com
.intellij
.openapi
.project
.Project
;
32 import com
.intellij
.openapi
.roots
.ModuleRootManager
;
33 import com
.intellij
.openapi
.roots
.ProjectRootManager
;
34 import com
.intellij
.openapi
.util
.Computable
;
35 import com
.intellij
.openapi
.util
.Disposer
;
36 import com
.intellij
.openapi
.util
.Pair
;
37 import com
.intellij
.openapi
.util
.Ref
;
38 import com
.intellij
.openapi
.util
.io
.FileUtil
;
39 import com
.intellij
.openapi
.vfs
.VirtualFile
;
40 import com
.intellij
.openapi
.vfs
.VirtualFileManager
;
41 import com
.intellij
.psi
.PsiFile
;
42 import com
.intellij
.psi
.PsiManager
;
43 import com
.intellij
.psi
.xml
.XmlElement
;
44 import com
.intellij
.util
.EventDispatcher
;
45 import com
.intellij
.util
.containers
.ContainerUtil
;
46 import com
.intellij
.util
.ui
.update
.Update
;
47 import com
.intellij
.util
.xml
.DomElement
;
48 import com
.intellij
.util
.xml
.reflect
.DomCollectionChildDescription
;
49 import gnu
.trove
.THashMap
;
50 import gnu
.trove
.THashSet
;
51 import org
.jetbrains
.annotations
.NotNull
;
52 import org
.jetbrains
.annotations
.Nullable
;
53 import org
.jetbrains
.annotations
.TestOnly
;
54 import org
.jetbrains
.idea
.maven
.dom
.MavenDomUtil
;
55 import org
.jetbrains
.idea
.maven
.dom
.model
.MavenDomDependencies
;
56 import org
.jetbrains
.idea
.maven
.dom
.model
.MavenDomDependency
;
57 import org
.jetbrains
.idea
.maven
.dom
.model
.MavenDomProjectModel
;
58 import org
.jetbrains
.idea
.maven
.execution
.SoutMavenConsole
;
59 import org
.jetbrains
.idea
.maven
.importing
.MavenDefaultModifiableModelsProvider
;
60 import org
.jetbrains
.idea
.maven
.importing
.MavenFoldersImporter
;
61 import org
.jetbrains
.idea
.maven
.importing
.MavenModifiableModelsProvider
;
62 import org
.jetbrains
.idea
.maven
.importing
.MavenProjectImporter
;
63 import org
.jetbrains
.idea
.maven
.utils
.*;
66 import java
.io
.IOException
;
68 import java
.util
.concurrent
.atomic
.AtomicBoolean
;
70 @State(name
= "MavenProjectsManager", storages
= {@Storage(id
= "default", file
= "$PROJECT_FILE$")})
71 public class MavenProjectsManager
extends SimpleProjectComponent
72 implements PersistentStateComponent
<MavenProjectsManagerState
>, SettingsSavingComponent
{
73 private static final int IMPORT_DELAY
= 1000;
75 static final Object SCHEDULE_IMPORT_MESSAGE
= "SCHEDULE_IMPORT_MESSAGE";
76 static final Object FORCE_IMPORT_MESSAGE
= "FORCE_IMPORT_MESSAGE";
78 private final AtomicBoolean isInitialized
= new AtomicBoolean();
80 private MavenProjectsManagerState myState
= new MavenProjectsManagerState();
82 private MavenEmbeddersManager myEmbeddersManager
;
84 private MavenProjectsTree myProjectsTree
;
85 private MavenProjectsManagerWatcher myWatcher
;
87 private MavenProjectsProcessor myReadingProcessor
;
88 private MavenProjectsProcessor myResolvingProcessor
;
89 private MavenProjectsProcessor myPluginsResolvingProcessor
;
90 private MavenProjectsProcessor myFoldersResolvingProcessor
;
91 private MavenProjectsProcessor myArtifactsDownloadingProcessor
;
92 private MavenProjectsProcessor myPostProcessor
;
94 private MavenMergingUpdateQueue myImportingQueue
;
95 private final Object myImportingDataLock
= new Object();
96 private final Map
<MavenProject
, MavenProjectChanges
> myProjectsToImport
= new THashMap
<MavenProject
, MavenProjectChanges
>();
97 private boolean myImportModuleGroupsRequired
= false;
99 private MavenMergingUpdateQueue mySchedulesQueue
;
101 private final EventDispatcher
<MavenProjectsTree
.Listener
> myProjectsTreeDispatcher
=
102 EventDispatcher
.create(MavenProjectsTree
.Listener
.class);
103 private final List
<Listener
> myManagerListeners
= ContainerUtil
.createEmptyCOWList();
105 public static MavenProjectsManager
getInstance(Project p
) {
106 return p
.getComponent(MavenProjectsManager
.class);
109 public MavenProjectsManager(Project project
) {
113 public MavenProjectsManagerState
getState() {
114 if (isInitialized()) {
120 public void loadState(MavenProjectsManagerState state
) {
122 if (isInitialized()) {
124 scheduleUpdateAllProjects(false);
128 public MavenGeneralSettings
getGeneralSettings() {
129 return getWorkspaceSettings().generalSettings
;
132 public MavenImportingSettings
getImportingSettings() {
133 return getWorkspaceSettings().importingSettings
;
136 private MavenWorkspaceSettings
getWorkspaceSettings() {
137 return MavenWorkspaceSettingsComponent
.getInstance(myProject
).getState();
140 public File
getLocalRepository() {
141 return getGeneralSettings().getEffectiveLocalRepository();
145 public void initComponent() {
146 if (!isNormalProject()) return;
148 StartupManagerEx
.getInstanceEx(myProject
).registerStartupActivity(new Runnable() {
150 boolean wasMavenized
= !myState
.originalFiles
.isEmpty();
151 if (!wasMavenized
) return;
157 private void initMavenized() {
161 private void initNew(List
<VirtualFile
> files
, List
<String
> explicitProfiles
) {
162 myState
.originalFiles
= MavenUtil
.collectPaths(files
);
163 myState
.activeProfiles
= explicitProfiles
;
168 public void initForTests() {
172 private void doInit(final boolean isNew
) {
173 if (isInitialized
.getAndSet(true)) return;
175 initProjectsTree(!isNew
);
178 listenForSettingsChanges();
179 listenForProjectsTreeChanges();
181 MavenUtil
.runWhenInitialized(myProject
, new DumbAwareRunnable() {
183 if (!isUnitTestMode()) {
185 listenForExternalChanges();
187 scheduleUpdateAllProjects(isNew
);
192 private void initProjectsTree(boolean tryToLoadExisting
) {
193 if (tryToLoadExisting
) {
194 File file
= getProjectsTreeFile();
197 myProjectsTree
= MavenProjectsTree
.read(file
);
200 catch (IOException e
) {
201 MavenLog
.LOG
.info(e
);
205 if (myProjectsTree
== null) myProjectsTree
= new MavenProjectsTree();
207 myProjectsTree
.addListener(myProjectsTreeDispatcher
.getMulticaster());
210 private void applyTreeToState() {
211 myState
.originalFiles
= myProjectsTree
.getManagedFilesPaths();
212 myState
.activeProfiles
= new ArrayList
<String
>(myProjectsTree
.getExplicitProfiles());
213 myState
.ignoredFiles
= new THashSet
<String
>(myProjectsTree
.getIgnoredFilesPaths());
214 myState
.ignoredPathMasks
= myProjectsTree
.getIgnoredFilesPatterns();
217 private void applyStateToTree() {
218 myProjectsTree
.resetManagedFilesPathsAndProfiles(myState
.originalFiles
, myState
.activeProfiles
);
219 myProjectsTree
.setIgnoredFilesPaths(new ArrayList
<String
>(myState
.ignoredFiles
));
220 myProjectsTree
.setIgnoredFilesPatterns(myState
.ignoredPathMasks
);
224 if (myProjectsTree
!= null) {
226 myProjectsTree
.save(getProjectsTreeFile());
228 catch (IOException e
) {
229 MavenLog
.LOG
.error(e
);
234 private File
getProjectsTreeFile() {
235 File file
= new File(getProjectsTreesDir(), myProject
.getLocationHash() + "/tree.dat");
236 file
.getParentFile().mkdirs();
240 private static File
getProjectsTreesDir() {
241 return MavenUtil
.getPluginSystemDir("Projects");
244 private void initWorkers() {
245 myEmbeddersManager
= new MavenEmbeddersManager(getGeneralSettings());
247 myReadingProcessor
= new MavenProjectsProcessor(myProject
, ProjectBundle
.message("maven.reading"), false, myEmbeddersManager
);
248 myResolvingProcessor
= new MavenProjectsProcessor(myProject
, ProjectBundle
.message("maven.resolving"), true, myEmbeddersManager
);
249 myPluginsResolvingProcessor
=
250 new MavenProjectsProcessor(myProject
, ProjectBundle
.message("maven.downloading.plugins"), true, myEmbeddersManager
);
251 myFoldersResolvingProcessor
=
252 new MavenProjectsProcessor(myProject
, ProjectBundle
.message("maven.updating.folders"), true, myEmbeddersManager
);
253 myArtifactsDownloadingProcessor
=
254 new MavenProjectsProcessor(myProject
, ProjectBundle
.message("maven.downloading"), true, myEmbeddersManager
);
255 myPostProcessor
= new MavenProjectsProcessor(myProject
, ProjectBundle
.message("maven.post.processing"), true, myEmbeddersManager
);
257 myWatcher
= new MavenProjectsManagerWatcher(myProject
, myProjectsTree
, getGeneralSettings(), myReadingProcessor
, myEmbeddersManager
);
259 myImportingQueue
= new MavenMergingUpdateQueue(getComponentName() + ": Importing queue", IMPORT_DELAY
, !isUnitTestMode(), myProject
);
260 myImportingQueue
.setPassThrough(false);
262 myImportingQueue
.makeUserAware(myProject
);
263 myImportingQueue
.makeDumbAware(myProject
);
264 myImportingQueue
.makeModalAware(myProject
);
266 mySchedulesQueue
= new MavenMergingUpdateQueue(getComponentName() + ": Schedules queue", 500, !isUnitTestMode(), myProject
);
267 mySchedulesQueue
.setPassThrough(false);
270 private void listenForSettingsChanges() {
271 getImportingSettings().addListener(new MavenImportingSettings
.Listener() {
272 public void autoImportChanged() {
273 scheduleImportSettings();
276 public void createModuleGroupsChanged() {
277 scheduleImportSettings(true);
280 public void createModuleForAggregatorsChanged() {
281 scheduleImportSettings();
286 private void listenForProjectsTreeChanges() {
287 myProjectsTree
.addListener(new MavenProjectsTree
.ListenerAdapter() {
289 public void projectsIgnoredStateChanged(List
<MavenProject
> ignored
, List
<MavenProject
> unignored
, Object message
) {
290 if (message
instanceof MavenProjectImporter
) return;
291 scheduleImport(false);
295 public void projectsUpdated(List
<Pair
<MavenProject
, MavenProjectChanges
>> updated
, List
<MavenProject
> deleted
, Object message
) {
296 myEmbeddersManager
.clearCaches();
298 unscheduleAllTasks(deleted
);
300 List
<MavenProject
> updatedProjects
= MavenUtil
.collectFirsts(updated
);
302 // import only updated and the dependents (we need to update faced-deps, packaging etc);
303 List
<Pair
<MavenProject
, MavenProjectChanges
>> toImport
= new ArrayList
<Pair
<MavenProject
, MavenProjectChanges
>>(updated
);
304 for (MavenProject each
: updatedProjects
) {
305 for (MavenProject eachDependent
: myProjectsTree
.getDependentProjects(each
)) {
306 toImport
.add(Pair
.create(eachDependent
, MavenProjectChanges
.DEPENDENCIES
));
310 // resolve updated, theirs dependents, and dependents of deleted
311 Set
<MavenProject
> toResolve
= new THashSet
<MavenProject
>(updatedProjects
);
312 for (MavenProject each
: ContainerUtil
.concat(updatedProjects
, deleted
)) {
313 toResolve
.addAll(myProjectsTree
.getDependentProjects(each
));
316 // do not try to resolve projects with syntactic errors
317 Iterator
<MavenProject
> it
= toResolve
.iterator();
318 while (it
.hasNext()) {
319 MavenProject each
= it
.next();
320 if (each
.hasReadingProblems()) it
.remove();
323 if (haveChanges(toImport
) || !deleted
.isEmpty()) {
324 scheduleImport(toImport
, message
== FORCE_IMPORT_MESSAGE
);
326 scheduleResolve(toResolve
, message
== FORCE_IMPORT_MESSAGE
);
329 private boolean haveChanges(List
<Pair
<MavenProject
, MavenProjectChanges
>> projectsWithChanges
) {
330 for (MavenProjectChanges each
: MavenUtil
.collectSeconds(projectsWithChanges
)) {
331 if (each
.hasChanges()) return true;
337 public void projectResolved(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
,
338 org
.apache
.maven
.project
.MavenProject nativeMavenProject
,
340 if (shouldScheduleProject(projectWithChanges
)) {
341 if (projectWithChanges
.first
.hasUnresolvedPlugins()) {
342 schedulePluginsResolving(projectWithChanges
.first
, nativeMavenProject
);
344 scheduleArtifactsDownloading(Collections
.singleton(projectWithChanges
.first
),
345 getImportingSettings().shouldDownloadSourcesAutomatically(),
346 getImportingSettings().shouldDownloadDocsAutomatically());
347 scheduleForNextImport(projectWithChanges
);
349 processMessage(message
);
353 public void foldersResolved(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
, Object message
) {
354 if (shouldScheduleProject(projectWithChanges
)) {
355 scheduleForNextImport(projectWithChanges
);
357 processMessage(message
);
360 private boolean shouldScheduleProject(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
) {
361 return !projectWithChanges
.first
.hasReadingProblems() && projectWithChanges
.second
.hasChanges();
364 private void processMessage(Object message
) {
365 if (getScheduledProjectsCount() == 0) return;
367 if (message
== SCHEDULE_IMPORT_MESSAGE
) {
368 scheduleImport(false);
370 else if (message
== FORCE_IMPORT_MESSAGE
) {
371 scheduleImport(true);
377 public void listenForExternalChanges() {
382 public void projectClosed() {
383 if (!isInitialized
.getAndSet(false)) return;
385 Disposer
.dispose(mySchedulesQueue
);
386 Disposer
.dispose(myImportingQueue
);
390 myReadingProcessor
.stop();
391 myResolvingProcessor
.stop();
392 myPluginsResolvingProcessor
.stop();
393 myFoldersResolvingProcessor
.stop();
394 myArtifactsDownloadingProcessor
.stop();
395 myPostProcessor
.stop();
397 myEmbeddersManager
.release();
399 if (isUnitTestMode()) {
400 FileUtil
.delete(getProjectsTreesDir());
405 public MavenEmbeddersManager
getEmbeddersManagerInTests() {
406 return myEmbeddersManager
;
409 private boolean isInitialized() {
410 return isInitialized
.get();
413 public boolean isMavenizedProject() {
414 return isInitialized();
417 public boolean isMavenizedModule(final Module m
) {
418 return ApplicationManager
.getApplication().runReadAction(new Computable
<Boolean
>() {
419 public Boolean
compute() {
420 return "true".equals(m
.getOptionValue(getMavenizedModuleOptionName()));
425 public void setMavenizedModules(Collection
<Module
> modules
, boolean mavenized
) {
426 ApplicationManager
.getApplication().assertWriteAccessAllowed();
427 for (Module m
: modules
) {
429 m
.setOption(getMavenizedModuleOptionName(), "true");
432 m
.clearOption(getMavenizedModuleOptionName());
437 private String
getMavenizedModuleOptionName() {
438 return getComponentName() + ".isMavenModule";
442 public void resetManagedFilesAndProfilesInTests(List
<VirtualFile
> files
, List
<String
> profiles
) {
443 myWatcher
.resetManagedFilesAndProfilesInTests(files
, profiles
);
446 public void addManagedFilesWithProfiles(List
<VirtualFile
> files
, List
<String
> profiles
) {
447 if (!isInitialized()) {
448 initNew(files
, profiles
);
451 myWatcher
.addManagedFilesWithProfiles(files
, profiles
);
455 public void addManagedFiles(List
<VirtualFile
> files
) {
456 addManagedFilesWithProfiles(files
, Collections
.<String
>emptyList());
459 public void removeManagedFiles(List
<VirtualFile
> files
) {
460 myWatcher
.removeManagedFiles(files
);
463 public boolean isManagedFile(VirtualFile f
) {
464 if (!isInitialized()) return false;
465 return myProjectsTree
.isManagedFile(f
);
468 public Collection
<String
> getExplicitProfiles() {
469 if (!isInitialized()) return Collections
.emptyList();
470 return myProjectsTree
.getExplicitProfiles();
473 public void setExplicitProfiles(Collection
<String
> profiles
) {
474 myWatcher
.setExplicitProfiles(profiles
);
477 public Collection
<String
> getAvailableProfiles() {
478 if (!isInitialized()) return Collections
.emptyList();
479 return myProjectsTree
.getAvailableProfiles();
482 public Collection
<Pair
<String
, MavenProfileState
>> getProfilesWithStates() {
483 if (!isInitialized()) return Collections
.emptyList();
484 return myProjectsTree
.getProfilesWithStates();
487 public boolean hasProjects() {
488 if (!isInitialized()) return false;
489 return myProjectsTree
.hasProjects();
492 public List
<MavenProject
> getProjects() {
493 if (!isInitialized()) return Collections
.emptyList();
494 return myProjectsTree
.getProjects();
497 public List
<MavenProject
> getNonIgnoredProjects() {
498 if (!isInitialized()) return Collections
.emptyList();
499 return myProjectsTree
.getNonIgnoredProjects();
502 public List
<VirtualFile
> getProjectsFiles() {
503 if (!isInitialized()) return Collections
.emptyList();
504 return myProjectsTree
.getProjectsFiles();
507 public MavenProject
findProject(VirtualFile f
) {
508 if (!isInitialized()) return null;
509 return myProjectsTree
.findProject(f
);
512 public MavenProject
findProject(MavenId id
) {
513 if (!isInitialized()) return null;
514 return myProjectsTree
.findProject(id
);
517 public MavenProject
findProject(MavenArtifact artifact
) {
518 if (!isInitialized()) return null;
519 return myProjectsTree
.findProject(artifact
);
522 public MavenProject
findProject(Module module
) {
523 VirtualFile f
= findPomFile(module
, new MavenModelsProvider() {
524 public Module
[] getModules() {
525 throw new UnsupportedOperationException();
528 public VirtualFile
[] getContentRoots(Module module
) {
529 return ModuleRootManager
.getInstance(module
).getContentRoots();
532 return f
== null ?
null : findProject(f
);
536 public Module
findModule(MavenProject project
) {
537 if (!isInitialized()) return null;
538 return ProjectRootManager
.getInstance(myProject
).getFileIndex().getModuleForFile(project
.getFile());
542 public Set
<MavenProject
> findInheritors(@Nullable MavenProject parent
) {
543 if (parent
== null || !isInitialized()) return Collections
.emptySet();
544 return myProjectsTree
.findInheritors(parent
);
547 public MavenProject
findContainingProject(VirtualFile file
) {
548 if (!isInitialized()) return null;
549 Module module
= ProjectRootManager
.getInstance(myProject
).getFileIndex().getModuleForFile(file
);
550 return module
== null ?
null : findProject(module
);
553 private static VirtualFile
findPomFile(Module module
, MavenModelsProvider modelsProvider
) {
554 for (VirtualFile root
: modelsProvider
.getContentRoots(module
)) {
555 final VirtualFile virtualFile
= root
.findChild(MavenConstants
.POM_XML
);
556 if (virtualFile
!= null) {
563 public MavenProject
findAggregator(MavenProject module
) {
564 if (!isInitialized()) return null;
565 return myProjectsTree
.findAggregator(module
);
568 public List
<MavenProject
> getModules(MavenProject aggregator
) {
569 if (!isInitialized()) return Collections
.emptyList();
570 return myProjectsTree
.getModules(aggregator
);
573 public List
<String
> getIgnoredFilesPaths() {
574 if (!isInitialized()) return Collections
.emptyList();
575 return myProjectsTree
.getIgnoredFilesPaths();
578 public void setIgnoredFilesPaths(List
<String
> paths
) {
579 if (!isInitialized()) return;
580 myProjectsTree
.setIgnoredFilesPaths(paths
);
583 public boolean getIgnoredState(MavenProject project
) {
584 if (!isInitialized()) return false;
585 return myProjectsTree
.getIgnoredState(project
);
588 public void setIgnoredState(List
<MavenProject
> projects
, boolean ignored
) {
589 if (!isInitialized()) return;
590 myProjectsTree
.setIgnoredState(projects
, ignored
);
593 public List
<String
> getIgnoredFilesPatterns() {
594 if (!isInitialized()) return Collections
.emptyList();
595 return myProjectsTree
.getIgnoredFilesPatterns();
598 public void setIgnoredFilesPatterns(List
<String
> patterns
) {
599 if (!isInitialized()) return;
600 myProjectsTree
.setIgnoredFilesPatterns(patterns
);
603 public boolean isIgnored(MavenProject project
) {
604 if (!isInitialized()) return false;
605 return myProjectsTree
.isIgnored(project
);
608 public Set
<MavenRemoteRepository
> getRemoteRepositories() {
609 Set
<MavenRemoteRepository
> result
= new THashSet
<MavenRemoteRepository
>();
610 for (MavenProject each
: getProjects()) {
611 for (MavenRemoteRepository eachRepository
: each
.getRemoteRepositories()) {
612 result
.add(eachRepository
);
619 public MavenProjectsTree
getProjectsTreeForTests() {
620 return myProjectsTree
;
623 private void scheduleUpdateAllProjects(boolean forceImport
) {
624 doScheduleUpdateProjects(null, false, forceImport
);
627 public void forceUpdateProjects(Collection
<MavenProject
> projects
) {
628 doScheduleUpdateProjects(projects
, true, true);
631 public void forceUpdateAllProjectsOrFindAllAvailablePomFiles() {
632 if (!isMavenizedProject()) {
633 addManagedFiles(collectAllAvailablePomFiles());
635 doScheduleUpdateProjects(null, true, true);
638 private void doScheduleUpdateProjects(final Collection
<MavenProject
> projects
, final boolean force
, final boolean forceImport
) {
639 // read when postStartupActivitias start
640 MavenUtil
.runWhenInitialized(myProject
, new DumbAwareRunnable() {
642 if (projects
== null) {
643 myWatcher
.scheduleUpdateAll(force
, forceImport
);
646 myWatcher
.scheduleUpdate(MavenUtil
.collectFiles(projects
), Collections
.EMPTY_LIST
, force
, forceImport
);
652 private void scheduleResolve(final Collection
<MavenProject
> projects
, final boolean forceImport
) {
653 runWhenFullyOpen(new Runnable() {
655 Iterator
<MavenProject
> it
= projects
.iterator();
656 while (it
.hasNext()) {
657 MavenProject each
= it
.next();
658 Object message
= it
.hasNext() ?
null : (forceImport ? FORCE_IMPORT_MESSAGE
: SCHEDULE_IMPORT_MESSAGE
);
659 myResolvingProcessor
.scheduleTask(new MavenProjectsProcessorResolvingTask(each
, myProjectsTree
, getGeneralSettings(), message
));
666 public void scheduleResolveInTests(Collection
<MavenProject
> projects
) {
667 scheduleResolve(projects
, false);
671 public void scheduleResolveAllInTests() {
672 scheduleResolve(getProjects(), false);
675 public void scheduleFoldersResolving(final Collection
<MavenProject
> projects
) {
676 runWhenFullyOpen(new Runnable() {
678 Iterator
<MavenProject
> it
= projects
.iterator();
679 while (it
.hasNext()) {
680 MavenProject each
= it
.next();
681 Object message
= it
.hasNext() ?
null : FORCE_IMPORT_MESSAGE
;
682 myFoldersResolvingProcessor
.scheduleTask(
683 new MavenProjectsProcessorFoldersResolvingTask(each
, getGeneralSettings(), getImportingSettings(), myProjectsTree
, message
));
689 public void scheduleFoldersResolvingForAllProjects() {
690 scheduleFoldersResolving(getProjects());
693 private void schedulePluginsResolving(final MavenProject project
, final org
.apache
.maven
.project
.MavenProject nativeMavenProject
) {
694 runWhenFullyOpen(new Runnable() {
696 myPluginsResolvingProcessor
697 .scheduleTask(new MavenProjectsProcessorPluginsResolvingTask(project
, nativeMavenProject
, myProjectsTree
));
702 public void scheduleArtifactsDownloading(final Collection
<MavenProject
> projects
, final boolean sources
, final boolean docs
) {
703 if (!sources
&& !docs
) return;
705 runWhenFullyOpen(new Runnable() {
707 for (MavenProject each
: projects
) {
708 myArtifactsDownloadingProcessor
709 .scheduleTask(new MavenProjectsProcessorArtifactsDownloadingTask(each
, myProjectsTree
, sources
, docs
));
715 public void scheduleArtifactsDownloading(final Collection
<MavenProject
> projects
) {
716 scheduleArtifactsDownloading(projects
, true, true);
719 public void scheduleArtifactsDownloadingForAllProjects() {
720 scheduleArtifactsDownloading(getProjects());
723 private void scheduleImport(List
<Pair
<MavenProject
, MavenProjectChanges
>> projectsWithChanges
, boolean forceImport
) {
724 scheduleForNextImport(projectsWithChanges
);
725 scheduleImport(forceImport
);
728 private void scheduleImportSettings() {
729 scheduleImportSettings(false);
732 private void scheduleImportSettings(boolean importModuleGroupsRequired
) {
733 synchronized (myImportingDataLock
) {
734 myImportModuleGroupsRequired
= importModuleGroupsRequired
;
736 scheduleImport(false);
739 private void scheduleImport(final boolean forceImport
) {
740 runWhenFullyOpen(new Runnable() {
742 final boolean autoImport
= getImportingSettings().isImportAutomatically();
743 // postpone activation to prevent import from being called from events poster
744 mySchedulesQueue
.queue(new Update(new Object()) {
746 if (autoImport
|| forceImport
) {
747 myImportingQueue
.activate();
750 myImportingQueue
.deactivate();
754 myImportingQueue
.queue(new Update(MavenProjectsManager
.this) {
757 if (!autoImport
) myImportingQueue
.deactivate();
760 if (!forceImport
) fireScheduledImportsChanged();
766 public void scheduleImportInTests(List
<VirtualFile
> projectFiles
) {
767 List
<Pair
<MavenProject
, MavenProjectChanges
>> toImport
= new ArrayList
<Pair
<MavenProject
, MavenProjectChanges
>>();
768 for (VirtualFile each
: projectFiles
) {
769 MavenProject project
= findProject(each
);
770 if (project
!= null) {
771 toImport
.add(Pair
.create(project
, MavenProjectChanges
.ALL
));
774 scheduleImport(toImport
, false);
777 private void scheduleForNextImport(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
) {
778 scheduleForNextImport(Collections
.singletonList(projectWithChanges
));
781 private void scheduleForNextImport(List
<Pair
<MavenProject
, MavenProjectChanges
>> projectsWithChanges
) {
782 synchronized (myImportingDataLock
) {
783 for (Pair
<MavenProject
, MavenProjectChanges
> each
: projectsWithChanges
) {
784 MavenProjectChanges changes
= each
.second
.mergedWith(myProjectsToImport
.get(each
.first
));
785 myProjectsToImport
.put(each
.first
, changes
);
790 public boolean hasScheduledImports() {
791 if (!isInitialized()) return false;
792 return !myImportingQueue
.isEmpty();
795 public int getScheduledProjectsCount() {
796 if (!isInitialized()) return 0;
797 synchronized (myImportingDataLock
) {
798 return myProjectsToImport
.size();
802 public void performScheduledImport() {
803 performScheduledImport(true);
806 public void performScheduledImport(final boolean force
) {
807 if (!isInitialized()) return;
808 runWhenFullyOpen(new Runnable() {
810 // ensure all pending schedules are processed
811 mySchedulesQueue
.flush(false);
812 if (!force
&& !myImportingQueue
.isActive()) return;
813 myImportingQueue
.flush(false);
818 private void runWhenFullyOpen(final Runnable runnable
) {
819 if (!isInitialized()) return; // may be called from scheduleImport after project started closing and before it is closed.
821 if (isNoBackgroundMode()) {
826 final Ref
<Runnable
> wrapper
= new Ref
<Runnable
>();
827 wrapper
.set(new Runnable() {
829 if (!StartupManagerEx
.getInstanceEx(myProject
).postStartupActivityPassed()) {
830 mySchedulesQueue
.queue(new Update(runnable
) { // should not remove previously schedules tasks
841 MavenUtil
.runWhenInitialized(myProject
, wrapper
.get());
844 private void schedulePostImportTasts(List
<MavenProjectsProcessorTask
> postTasks
) {
845 for (MavenProjectsProcessorTask each
: postTasks
) {
846 myPostProcessor
.scheduleTask(each
);
850 private void unscheduleAllTasks(List
<MavenProject
> projects
) {
851 for (MavenProject each
: projects
) {
852 MavenProjectsProcessorEmptyTask dummyTask
= new MavenProjectsProcessorEmptyTask(each
);
854 synchronized (myImportingDataLock
) {
855 myProjectsToImport
.remove(each
);
858 myResolvingProcessor
.removeTask(dummyTask
);
859 myPluginsResolvingProcessor
.removeTask(dummyTask
);
860 myFoldersResolvingProcessor
.removeTask(dummyTask
);
861 myArtifactsDownloadingProcessor
.removeTask(dummyTask
);
862 myPostProcessor
.removeTask(dummyTask
);
867 public void unscheduleAllTasksInTests() {
868 unscheduleAllTasks(getProjects());
871 public void waitForReadingCompletion() {
872 waitForTasksCompletion(Collections
.<MavenProjectsProcessor
>emptyList());
875 public void waitForResolvingCompletion() {
876 waitForTasksCompletion(myResolvingProcessor
);
879 public void waitForFoldersResolvingCompletion() {
880 waitForTasksCompletion(myFoldersResolvingProcessor
);
883 public void waitForPluginsResolvingCompletion() {
884 waitForTasksCompletion(myPluginsResolvingProcessor
);
887 public void waitForArtifactsDownloadingCompletion() {
888 waitForTasksCompletion(Arrays
.asList(myResolvingProcessor
, myArtifactsDownloadingProcessor
));
891 public void waitForPostImportTasksCompletion() {
892 myPostProcessor
.waitForCompletion();
895 private void waitForTasksCompletion(MavenProjectsProcessor processor
) {
896 waitForTasksCompletion(Collections
.singletonList(processor
));
899 private void waitForTasksCompletion(List
<MavenProjectsProcessor
> processors
) {
900 FileDocumentManager
.getInstance().saveAllDocuments();
902 myReadingProcessor
.waitForCompletion();
903 for (MavenProjectsProcessor each
: processors
) {
904 each
.waitForCompletion();
908 public void updateProjectTargetFolders() {
909 updateProjectFolders(true);
912 private void updateProjectFolders(final boolean targetFoldersOnly
) {
913 MavenUtil
.invokeLater(myProject
, new Runnable() {
915 MavenFoldersImporter
.updateProjectFolders(myProject
, targetFoldersOnly
);
916 VirtualFileManager
.getInstance().refresh(false);
921 public List
<Module
> importProjects() {
922 return importProjects(new MavenDefaultModifiableModelsProvider(myProject
));
925 public List
<Module
> importProjects(final MavenModifiableModelsProvider modelsProvider
) {
926 final Map
<MavenProject
, MavenProjectChanges
> projectsToImportWithChanges
;
927 final boolean importModuleGroupsRequired
;
928 synchronized (myImportingDataLock
) {
929 projectsToImportWithChanges
= new THashMap
<MavenProject
, MavenProjectChanges
>(myProjectsToImport
);
930 myProjectsToImport
.clear();
931 importModuleGroupsRequired
= myImportModuleGroupsRequired
;
933 fireScheduledImportsChanged();
935 final Ref
<MavenProjectImporter
> importer
= new Ref
<MavenProjectImporter
>();
936 final Ref
<List
<MavenProjectsProcessorTask
>> postTasks
= new Ref
<List
<MavenProjectsProcessorTask
>>();
938 final Runnable r
= new Runnable() {
941 new MavenProjectImporter(myProject
, myProjectsTree
, getFileToModuleMapping(modelsProvider
), projectsToImportWithChanges
,
942 importModuleGroupsRequired
, modelsProvider
, getImportingSettings()));
943 postTasks
.set(importer
.get().importProject());
947 // called from wizard or ui
948 if (ApplicationManager
.getApplication().isDispatchThread()) {
952 MavenUtil
.runInBackground(myProject
, ProjectBundle
.message("maven.project.importing"), false, new MavenTask() {
953 public void run(MavenProgressIndicator indicator
) throws MavenProcessCanceledException
{
960 VirtualFileManager
.getInstance().refresh(isNormalProject());
961 schedulePostImportTasts(postTasks
.get());
963 // do not block user too often
964 myImportingQueue
.restartTimer();
966 return importer
.get().getCreatedModules();
969 private Map
<VirtualFile
, Module
> getFileToModuleMapping(MavenModelsProvider modelsProvider
) {
970 Map
<VirtualFile
, Module
> result
= new THashMap
<VirtualFile
, Module
>();
971 for (Module each
: modelsProvider
.getModules()) {
972 VirtualFile f
= findPomFile(each
, modelsProvider
);
973 if (f
!= null) result
.put(f
, each
);
978 private List
<VirtualFile
> collectAllAvailablePomFiles() {
979 List
<VirtualFile
> result
= new ArrayList
<VirtualFile
>(getFileToModuleMapping(new MavenDefaultModelsProvider(myProject
)).keySet());
981 VirtualFile pom
= myProject
.getBaseDir().findChild(MavenConstants
.POM_XML
);
982 if (pom
!= null) result
.add(pom
);
987 public MavenDomDependency
addDependency(final MavenProject mavenProject
, final MavenId id
) {
988 final MavenArtifact
[] artifact
= new MavenArtifact
[1];
991 MavenUtil
.run(myProject
, "Downloading dependency...", new MavenTask() {
992 public void run(MavenProgressIndicator indicator
) throws MavenProcessCanceledException
{
993 artifact
[0] = myProjectsTree
.downloadArtifact(mavenProject
, id
, myEmbeddersManager
, new SoutMavenConsole(), indicator
);
997 catch (MavenProcessCanceledException ignore
) {
1001 VirtualFile file
= mavenProject
.getFile();
1002 PsiFile psiFile
= PsiManager
.getInstance(myProject
).findFile(file
);
1004 MavenDomDependency result
= new WriteCommandAction
<MavenDomDependency
>(myProject
, "Add Maven Dependency", psiFile
) {
1005 protected void run(Result
<MavenDomDependency
> result
) throws Throwable
{
1006 MavenDomProjectModel model
= MavenDomUtil
.getMavenDomProjectModel(myProject
, mavenProject
.getFile());
1008 MavenDomDependency domDependency
= MavenDomUtil
.createDomDependency(model
, artifact
[0], getEditor());
1010 mavenProject
.addDependency(artifact
[0]);
1011 result
.setResult(domDependency
);
1013 }.execute().getResultObject();
1015 scheduleImport(Collections
.singletonList(Pair
.create(mavenProject
, MavenProjectChanges
.DEPENDENCIES
)), true);
1021 private Editor
getEditor() {
1022 return FileEditorManager
.getInstance(myProject
).getSelectedTextEditor();
1025 public void addManagerListener(Listener listener
) {
1026 myManagerListeners
.add(listener
);
1029 public void addProjectsTreeListener(MavenProjectsTree
.Listener listener
) {
1030 myProjectsTreeDispatcher
.addListener(listener
);
1034 public void fireActivatedInTests() {
1038 private void fireActivated() {
1039 for (Listener each
: myManagerListeners
) {
1044 private void fireScheduledImportsChanged() {
1045 for (Listener each
: myManagerListeners
) {
1046 each
.scheduledImportsChanged();
1050 public interface Listener
{
1053 void scheduledImportsChanged();