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
.fileEditor
.FileDocumentManager
;
27 import com
.intellij
.openapi
.module
.Module
;
28 import com
.intellij
.openapi
.project
.DumbAwareRunnable
;
29 import com
.intellij
.openapi
.project
.Project
;
30 import com
.intellij
.openapi
.roots
.ModuleRootManager
;
31 import com
.intellij
.openapi
.roots
.ProjectRootManager
;
32 import com
.intellij
.openapi
.util
.Computable
;
33 import com
.intellij
.openapi
.util
.Disposer
;
34 import com
.intellij
.openapi
.util
.Pair
;
35 import com
.intellij
.openapi
.util
.Ref
;
36 import com
.intellij
.openapi
.util
.io
.FileUtil
;
37 import com
.intellij
.openapi
.vfs
.VirtualFile
;
38 import com
.intellij
.openapi
.vfs
.VirtualFileManager
;
39 import com
.intellij
.psi
.PsiFile
;
40 import com
.intellij
.psi
.PsiManager
;
41 import com
.intellij
.util
.EventDispatcher
;
42 import com
.intellij
.util
.containers
.ContainerUtil
;
43 import com
.intellij
.util
.ui
.update
.Update
;
44 import gnu
.trove
.THashMap
;
45 import gnu
.trove
.THashSet
;
46 import org
.jetbrains
.annotations
.Nullable
;
47 import org
.jetbrains
.annotations
.TestOnly
;
48 import org
.jetbrains
.idea
.maven
.dom
.MavenDomUtil
;
49 import org
.jetbrains
.idea
.maven
.dom
.model
.MavenDomDependency
;
50 import org
.jetbrains
.idea
.maven
.dom
.model
.MavenDomProjectModel
;
51 import org
.jetbrains
.idea
.maven
.execution
.SoutMavenConsole
;
52 import org
.jetbrains
.idea
.maven
.importing
.MavenDefaultModifiableModelsProvider
;
53 import org
.jetbrains
.idea
.maven
.importing
.MavenFoldersImporter
;
54 import org
.jetbrains
.idea
.maven
.importing
.MavenModifiableModelsProvider
;
55 import org
.jetbrains
.idea
.maven
.importing
.MavenProjectImporter
;
56 import org
.jetbrains
.idea
.maven
.utils
.*;
59 import java
.io
.IOException
;
61 import java
.util
.concurrent
.atomic
.AtomicBoolean
;
63 @State(name
= "MavenProjectsManager", storages
= {@Storage(id
= "default", file
= "$PROJECT_FILE$")})
64 public class MavenProjectsManager
extends SimpleProjectComponent
implements PersistentStateComponent
<MavenProjectsManagerState
>,
65 SettingsSavingComponent
{
66 private static final int IMPORT_DELAY
= 1000;
68 static final Object SCHEDULE_IMPORT_MESSAGE
= "SCHEDULE_IMPORT_MESSAGE";
69 static final Object FORCE_IMPORT_MESSAGE
= "FORCE_IMPORT_MESSAGE";
71 private final AtomicBoolean isInitialized
= new AtomicBoolean();
73 private MavenProjectsManagerState myState
= new MavenProjectsManagerState();
75 private MavenEmbeddersManager myEmbeddersManager
;
77 private MavenProjectsTree myProjectsTree
;
78 private MavenProjectsManagerWatcher myWatcher
;
80 private MavenProjectsProcessor myReadingProcessor
;
81 private MavenProjectsProcessor myResolvingProcessor
;
82 private MavenProjectsProcessor myPluginsResolvingProcessor
;
83 private MavenProjectsProcessor myFoldersResolvingProcessor
;
84 private MavenProjectsProcessor myArtifactsDownloadingProcessor
;
85 private MavenProjectsProcessor myPostProcessor
;
87 private MavenMergingUpdateQueue myImportingQueue
;
88 private final Object myImportingDataLock
= new Object();
89 private final Map
<MavenProject
, MavenProjectChanges
> myProjectsToImport
= new THashMap
<MavenProject
, MavenProjectChanges
>();
90 private boolean myImportModuleGroupsRequired
= false;
92 private MavenMergingUpdateQueue mySchedulesQueue
;
94 private final EventDispatcher
<MavenProjectsTree
.Listener
> myProjectsTreeDispatcher
95 = EventDispatcher
.create(MavenProjectsTree
.Listener
.class);
96 private final List
<Listener
> myManagerListeners
= ContainerUtil
.createEmptyCOWList();
98 public static MavenProjectsManager
getInstance(Project p
) {
99 return p
.getComponent(MavenProjectsManager
.class);
102 public MavenProjectsManager(Project project
) {
106 public MavenProjectsManagerState
getState() {
107 if (isInitialized()) {
113 public void loadState(MavenProjectsManagerState state
) {
115 if (isInitialized()) {
117 scheduleUpdateAllProjects(false);
121 public MavenGeneralSettings
getGeneralSettings() {
122 return getWorkspaceSettings().generalSettings
;
125 public MavenImportingSettings
getImportingSettings() {
126 return getWorkspaceSettings().importingSettings
;
129 private MavenWorkspaceSettings
getWorkspaceSettings() {
130 return MavenWorkspaceSettingsComponent
.getInstance(myProject
).getState();
133 public File
getLocalRepository() {
134 return getGeneralSettings().getEffectiveLocalRepository();
138 public void initComponent() {
139 if (!isNormalProject()) return;
141 StartupManagerEx
.getInstanceEx(myProject
).registerStartupActivity(new Runnable() {
143 boolean wasMavenized
= !myState
.originalFiles
.isEmpty();
144 if (!wasMavenized
) return;
150 private void initMavenized() {
154 private void initNew(List
<VirtualFile
> files
, List
<String
> explicitProfiles
) {
155 myState
.originalFiles
= MavenUtil
.collectPaths(files
);
156 myState
.activeProfiles
= explicitProfiles
;
161 public void initForTests() {
165 private void doInit(final boolean isNew
) {
166 if (isInitialized
.getAndSet(true)) return;
168 initProjectsTree(!isNew
);
171 listenForSettingsChanges();
172 listenForProjectsTreeChanges();
174 MavenUtil
.runWhenInitialized(myProject
, new DumbAwareRunnable() {
176 if (!isUnitTestMode()) {
178 listenForExternalChanges();
180 scheduleUpdateAllProjects(isNew
);
185 private void initProjectsTree(boolean tryToLoadExisting
) {
186 if (tryToLoadExisting
) {
187 File file
= getProjectsTreeFile();
190 myProjectsTree
= MavenProjectsTree
.read(file
);
193 catch (IOException e
) {
194 MavenLog
.LOG
.info(e
);
198 if (myProjectsTree
== null) myProjectsTree
= new MavenProjectsTree();
200 myProjectsTree
.addListener(myProjectsTreeDispatcher
.getMulticaster());
203 private void applyTreeToState() {
204 myState
.originalFiles
= myProjectsTree
.getManagedFilesPaths();
205 myState
.activeProfiles
= new ArrayList
<String
>(myProjectsTree
.getExplicitProfiles());
206 myState
.ignoredFiles
= new THashSet
<String
>(myProjectsTree
.getIgnoredFilesPaths());
207 myState
.ignoredPathMasks
= myProjectsTree
.getIgnoredFilesPatterns();
210 private void applyStateToTree() {
211 myProjectsTree
.resetManagedFilesPathsAndProfiles(myState
.originalFiles
, myState
.activeProfiles
);
212 myProjectsTree
.setIgnoredFilesPaths(new ArrayList
<String
>(myState
.ignoredFiles
));
213 myProjectsTree
.setIgnoredFilesPatterns(myState
.ignoredPathMasks
);
217 if (myProjectsTree
!= null) {
219 myProjectsTree
.save(getProjectsTreeFile());
221 catch (IOException e
) {
222 MavenLog
.LOG
.error(e
);
227 private File
getProjectsTreeFile() {
228 File file
= new File(getProjectsTreesDir(), myProject
.getLocationHash() + "/tree.dat");
229 file
.getParentFile().mkdirs();
233 private static File
getProjectsTreesDir() {
234 return MavenUtil
.getPluginSystemDir("Projects");
237 private void initWorkers() {
238 myEmbeddersManager
= new MavenEmbeddersManager(getGeneralSettings());
240 myReadingProcessor
= new MavenProjectsProcessor(myProject
,
241 ProjectBundle
.message("maven.reading"),
244 myResolvingProcessor
= new MavenProjectsProcessor(myProject
,
245 ProjectBundle
.message("maven.resolving"),
248 myPluginsResolvingProcessor
= new MavenProjectsProcessor(myProject
,
249 ProjectBundle
.message("maven.downloading.plugins"),
252 myFoldersResolvingProcessor
= new MavenProjectsProcessor(myProject
,
253 ProjectBundle
.message("maven.updating.folders"),
256 myArtifactsDownloadingProcessor
= new MavenProjectsProcessor(myProject
,
257 ProjectBundle
.message("maven.downloading"),
260 myPostProcessor
= new MavenProjectsProcessor(myProject
,
261 ProjectBundle
.message("maven.post.processing"),
265 myWatcher
= new MavenProjectsManagerWatcher(myProject
, myProjectsTree
, getGeneralSettings(), myReadingProcessor
, myEmbeddersManager
);
267 myImportingQueue
= new MavenMergingUpdateQueue(getComponentName() + ": Importing queue", IMPORT_DELAY
, !isUnitTestMode(), myProject
);
268 myImportingQueue
.setPassThrough(false);
270 myImportingQueue
.makeUserAware(myProject
);
271 myImportingQueue
.makeDumbAware(myProject
);
272 myImportingQueue
.makeModalAware(myProject
);
274 mySchedulesQueue
= new MavenMergingUpdateQueue(getComponentName() + ": Schedules queue", 500, !isUnitTestMode(), myProject
);
275 mySchedulesQueue
.setPassThrough(false);
278 private void listenForSettingsChanges() {
279 getImportingSettings().addListener(new MavenImportingSettings
.Listener() {
280 public void autoImportChanged() {
281 scheduleImportSettings();
284 public void createModuleGroupsChanged() {
285 scheduleImportSettings(true);
288 public void createModuleForAggregatorsChanged() {
289 scheduleImportSettings();
294 private void listenForProjectsTreeChanges() {
295 myProjectsTree
.addListener(new MavenProjectsTree
.ListenerAdapter() {
297 public void projectsIgnoredStateChanged(List
<MavenProject
> ignored
, List
<MavenProject
> unignored
, Object message
) {
298 if (message
instanceof MavenProjectImporter
) return;
299 scheduleImport(false);
303 public void projectsUpdated(List
<Pair
<MavenProject
, MavenProjectChanges
>> updated
, List
<MavenProject
> deleted
, Object message
) {
304 myEmbeddersManager
.clearCaches();
306 unscheduleAllTasks(deleted
);
308 List
<MavenProject
> updatedProjects
= MavenUtil
.collectFirsts(updated
);
310 // import only updated and the dependents (we need to update faced-deps, packaging etc);
311 List
<Pair
<MavenProject
, MavenProjectChanges
>> toImport
= new ArrayList
<Pair
<MavenProject
, MavenProjectChanges
>>(updated
);
312 for (MavenProject each
: updatedProjects
) {
313 for (MavenProject eachDependent
: myProjectsTree
.getDependentProjects(each
)) {
314 toImport
.add(Pair
.create(eachDependent
, MavenProjectChanges
.DEPENDENCIES
));
318 // resolve updated, theirs dependents, and dependents of deleted
319 Set
<MavenProject
> toResolve
= new THashSet
<MavenProject
>(updatedProjects
);
320 for (MavenProject each
: ContainerUtil
.concat(updatedProjects
, deleted
)) {
321 toResolve
.addAll(myProjectsTree
.getDependentProjects(each
));
324 // do not try to resolve projects with syntactic errors
325 Iterator
<MavenProject
> it
= toResolve
.iterator();
326 while (it
.hasNext()) {
327 MavenProject each
= it
.next();
328 if (each
.hasReadingProblems()) it
.remove();
331 if (haveChanges(toImport
) || !deleted
.isEmpty()) {
332 scheduleImport(toImport
, message
== FORCE_IMPORT_MESSAGE
);
334 scheduleResolve(toResolve
, message
== FORCE_IMPORT_MESSAGE
);
337 private boolean haveChanges(List
<Pair
<MavenProject
, MavenProjectChanges
>> projectsWithChanges
) {
338 for (MavenProjectChanges each
: MavenUtil
.collectSeconds(projectsWithChanges
)) {
339 if (each
.hasChanges()) return true;
345 public void projectResolved(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
,
346 org
.apache
.maven
.project
.MavenProject nativeMavenProject
,
348 if (shouldScheduleProject(projectWithChanges
)) {
349 if (projectWithChanges
.first
.hasUnresolvedPlugins()) {
350 schedulePluginsResolving(projectWithChanges
.first
, nativeMavenProject
);
352 scheduleArtifactsDownloading(Collections
.singleton(projectWithChanges
.first
),
353 getImportingSettings().shouldDownloadSourcesAutomatically(),
354 getImportingSettings().shouldDownloadDocsAutomatically());
355 scheduleForNextImport(projectWithChanges
);
357 processMessage(message
);
361 public void foldersResolved(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
, Object message
) {
362 if (shouldScheduleProject(projectWithChanges
)) {
363 scheduleForNextImport(projectWithChanges
);
365 processMessage(message
);
368 private boolean shouldScheduleProject(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
) {
369 return !projectWithChanges
.first
.hasReadingProblems() && projectWithChanges
.second
.hasChanges();
372 private void processMessage(Object message
) {
373 if (getScheduledProjectsCount() == 0) return;
375 if (message
== SCHEDULE_IMPORT_MESSAGE
) {
376 scheduleImport(false);
378 else if (message
== FORCE_IMPORT_MESSAGE
) {
379 scheduleImport(true);
385 public void listenForExternalChanges() {
390 public void projectClosed() {
391 if (!isInitialized
.getAndSet(false)) return;
393 Disposer
.dispose(mySchedulesQueue
);
394 Disposer
.dispose(myImportingQueue
);
398 myReadingProcessor
.stop();
399 myResolvingProcessor
.stop();
400 myPluginsResolvingProcessor
.stop();
401 myFoldersResolvingProcessor
.stop();
402 myArtifactsDownloadingProcessor
.stop();
403 myPostProcessor
.stop();
405 myEmbeddersManager
.release();
407 if (isUnitTestMode()) {
408 FileUtil
.delete(getProjectsTreesDir());
413 public MavenEmbeddersManager
getEmbeddersManagerInTests() {
414 return myEmbeddersManager
;
417 private boolean isInitialized() {
418 return isInitialized
.get();
421 public boolean isMavenizedProject() {
422 return isInitialized();
425 public boolean isMavenizedModule(final Module m
) {
426 return ApplicationManager
.getApplication().runReadAction(new Computable
<Boolean
>() {
427 public Boolean
compute() {
428 return "true".equals(m
.getOptionValue(getMavenizedModuleOptionName()));
433 public void setMavenizedModules(Collection
<Module
> modules
, boolean mavenized
) {
434 ApplicationManager
.getApplication().assertWriteAccessAllowed();
435 for (Module m
: modules
) {
437 m
.setOption(getMavenizedModuleOptionName(), "true");
440 m
.clearOption(getMavenizedModuleOptionName());
445 private String
getMavenizedModuleOptionName() {
446 return getComponentName() + ".isMavenModule";
450 public void resetManagedFilesAndProfilesInTests(List
<VirtualFile
> files
, List
<String
> profiles
) {
451 myWatcher
.resetManagedFilesAndProfilesInTests(files
, profiles
);
454 public void addManagedFilesWithProfiles(List
<VirtualFile
> files
, List
<String
> profiles
) {
455 if (!isInitialized()) {
456 initNew(files
, profiles
);
459 myWatcher
.addManagedFilesWithProfiles(files
, profiles
);
463 public void addManagedFiles(List
<VirtualFile
> files
) {
464 addManagedFilesWithProfiles(files
, Collections
.<String
>emptyList());
467 public void removeManagedFiles(List
<VirtualFile
> files
) {
468 myWatcher
.removeManagedFiles(files
);
471 public boolean isManagedFile(VirtualFile f
) {
472 if (!isInitialized()) return false;
473 return myProjectsTree
.isManagedFile(f
);
476 public Collection
<String
> getExplicitProfiles() {
477 if (!isInitialized()) return Collections
.emptyList();
478 return myProjectsTree
.getExplicitProfiles();
481 public void setExplicitProfiles(Collection
<String
> profiles
) {
482 myWatcher
.setExplicitProfiles(profiles
);
485 public Collection
<String
> getAvailableProfiles() {
486 if (!isInitialized()) return Collections
.emptyList();
487 return myProjectsTree
.getAvailableProfiles();
490 public Collection
<Pair
<String
, MavenProfileState
>> getProfilesWithStates() {
491 if (!isInitialized()) return Collections
.emptyList();
492 return myProjectsTree
.getProfilesWithStates();
495 public boolean hasProjects() {
496 if (!isInitialized()) return false;
497 return myProjectsTree
.hasProjects();
500 public List
<MavenProject
> getProjects() {
501 if (!isInitialized()) return Collections
.emptyList();
502 return myProjectsTree
.getProjects();
505 public List
<MavenProject
> getNonIgnoredProjects() {
506 if (!isInitialized()) return Collections
.emptyList();
507 return myProjectsTree
.getNonIgnoredProjects();
510 public List
<VirtualFile
> getProjectsFiles() {
511 if (!isInitialized()) return Collections
.emptyList();
512 return myProjectsTree
.getProjectsFiles();
515 public MavenProject
findProject(VirtualFile f
) {
516 if (!isInitialized()) return null;
517 return myProjectsTree
.findProject(f
);
520 public MavenProject
findProject(MavenId id
) {
521 if (!isInitialized()) return null;
522 return myProjectsTree
.findProject(id
);
525 public MavenProject
findProject(MavenArtifact artifact
) {
526 if (!isInitialized()) return null;
527 return myProjectsTree
.findProject(artifact
);
530 public MavenProject
findProject(Module module
) {
531 VirtualFile f
= findPomFile(module
, new MavenModelsProvider() {
532 public Module
[] getModules() {
533 throw new UnsupportedOperationException();
536 public VirtualFile
[] getContentRoots(Module module
) {
537 return ModuleRootManager
.getInstance(module
).getContentRoots();
540 return f
== null ?
null : findProject(f
);
544 public Module
findModule(MavenProject project
) {
545 if (!isInitialized()) return null;
546 return ProjectRootManager
.getInstance(myProject
).getFileIndex().getModuleForFile(project
.getFile());
549 public MavenProject
findContainingProject(VirtualFile file
) {
550 if (!isInitialized()) return null;
551 Module module
= ProjectRootManager
.getInstance(myProject
).getFileIndex().getModuleForFile(file
);
552 return module
== null ?
null : findProject(module
);
555 private static VirtualFile
findPomFile(Module module
, MavenModelsProvider modelsProvider
) {
556 for (VirtualFile root
: modelsProvider
.getContentRoots(module
)) {
557 final VirtualFile virtualFile
= root
.findChild(MavenConstants
.POM_XML
);
558 if (virtualFile
!= null) {
565 public MavenProject
findAggregator(MavenProject module
) {
566 if (!isInitialized()) return null;
567 return myProjectsTree
.findAggregator(module
);
570 public List
<MavenProject
> getModules(MavenProject aggregator
) {
571 if (!isInitialized()) return Collections
.emptyList();
572 return myProjectsTree
.getModules(aggregator
);
575 public List
<String
> getIgnoredFilesPaths() {
576 if (!isInitialized()) return Collections
.emptyList();
577 return myProjectsTree
.getIgnoredFilesPaths();
580 public void setIgnoredFilesPaths(List
<String
> paths
) {
581 if (!isInitialized()) return;
582 myProjectsTree
.setIgnoredFilesPaths(paths
);
585 public boolean getIgnoredState(MavenProject project
) {
586 if (!isInitialized()) return false;
587 return myProjectsTree
.getIgnoredState(project
);
590 public void setIgnoredState(List
<MavenProject
> projects
, boolean ignored
) {
591 if (!isInitialized()) return;
592 myProjectsTree
.setIgnoredState(projects
, ignored
);
595 public List
<String
> getIgnoredFilesPatterns() {
596 if (!isInitialized()) return Collections
.emptyList();
597 return myProjectsTree
.getIgnoredFilesPatterns();
600 public void setIgnoredFilesPatterns(List
<String
> patterns
) {
601 if (!isInitialized()) return;
602 myProjectsTree
.setIgnoredFilesPatterns(patterns
);
605 public boolean isIgnored(MavenProject project
) {
606 if (!isInitialized()) return false;
607 return myProjectsTree
.isIgnored(project
);
610 public Set
<MavenRemoteRepository
> getRemoteRepositories() {
611 Set
<MavenRemoteRepository
> result
= new THashSet
<MavenRemoteRepository
>();
612 for (MavenProject each
: getProjects()) {
613 for (MavenRemoteRepository eachRepository
: each
.getRemoteRepositories()) {
614 result
.add(eachRepository
);
621 public MavenProjectsTree
getProjectsTreeForTests() {
622 return myProjectsTree
;
625 private void scheduleUpdateAllProjects(boolean forceImport
) {
626 doScheduleUpdateProjects(null, false, forceImport
);
629 public void forceUpdateProjects(Collection
<MavenProject
> projects
) {
630 doScheduleUpdateProjects(projects
, true, true);
633 public void forceUpdateAllProjectsOrFindAllAvailablePomFiles() {
634 if (!isMavenizedProject()) {
635 addManagedFiles(collectAllAvailablePomFiles());
637 doScheduleUpdateProjects(null, true, true);
640 private void doScheduleUpdateProjects(final Collection
<MavenProject
> projects
, final boolean force
, final boolean forceImport
) {
641 // read when postStartupActivitias start
642 MavenUtil
.runWhenInitialized(myProject
, new DumbAwareRunnable() {
644 if (projects
== null) {
645 myWatcher
.scheduleUpdateAll(force
, forceImport
);
648 myWatcher
.scheduleUpdate(MavenUtil
.collectFiles(projects
), Collections
.EMPTY_LIST
, force
, forceImport
);
654 private void scheduleResolve(final Collection
<MavenProject
> projects
, final boolean forceImport
) {
655 runWhenFullyOpen(new Runnable() {
657 Iterator
<MavenProject
> it
= projects
.iterator();
658 while (it
.hasNext()) {
659 MavenProject each
= it
.next();
660 Object message
= it
.hasNext() ?
null : (forceImport ? FORCE_IMPORT_MESSAGE
: SCHEDULE_IMPORT_MESSAGE
);
661 myResolvingProcessor
.scheduleTask(new MavenProjectsProcessorResolvingTask(each
,
663 getGeneralSettings(),
671 public void scheduleResolveInTests(Collection
<MavenProject
> projects
) {
672 scheduleResolve(projects
, false);
676 public void scheduleResolveAllInTests() {
677 scheduleResolve(getProjects(), false);
680 public void scheduleFoldersResolving(final Collection
<MavenProject
> projects
) {
681 runWhenFullyOpen(new Runnable() {
683 Iterator
<MavenProject
> it
= projects
.iterator();
684 while (it
.hasNext()) {
685 MavenProject each
= it
.next();
686 Object message
= it
.hasNext() ?
null : FORCE_IMPORT_MESSAGE
;
687 myFoldersResolvingProcessor
.scheduleTask(new MavenProjectsProcessorFoldersResolvingTask(each
,
688 getGeneralSettings(),
689 getImportingSettings(),
697 public void scheduleFoldersResolvingForAllProjects() {
698 scheduleFoldersResolving(getProjects());
701 private void schedulePluginsResolving(final MavenProject project
, final org
.apache
.maven
.project
.MavenProject nativeMavenProject
) {
702 runWhenFullyOpen(new Runnable() {
704 myPluginsResolvingProcessor
.scheduleTask(new MavenProjectsProcessorPluginsResolvingTask(project
,
711 public void scheduleArtifactsDownloading(final Collection
<MavenProject
> projects
, final boolean sources
, final boolean docs
) {
712 if (!sources
&& !docs
) return;
714 runWhenFullyOpen(new Runnable() {
716 for (MavenProject each
: projects
) {
717 myArtifactsDownloadingProcessor
.scheduleTask(
718 new MavenProjectsProcessorArtifactsDownloadingTask(each
, myProjectsTree
, sources
, docs
));
724 public void scheduleArtifactsDownloading(final Collection
<MavenProject
> projects
) {
725 scheduleArtifactsDownloading(projects
, true, true);
728 public void scheduleArtifactsDownloadingForAllProjects() {
729 scheduleArtifactsDownloading(getProjects());
732 private void scheduleImport(List
<Pair
<MavenProject
, MavenProjectChanges
>> projectsWithChanges
, boolean forceImport
) {
733 scheduleForNextImport(projectsWithChanges
);
734 scheduleImport(forceImport
);
737 private void scheduleImportSettings() {
738 scheduleImportSettings(false);
741 private void scheduleImportSettings(boolean importModuleGroupsRequired
) {
742 synchronized (myImportingDataLock
) {
743 myImportModuleGroupsRequired
= importModuleGroupsRequired
;
745 scheduleImport(false);
748 private void scheduleImport(final boolean forceImport
) {
749 runWhenFullyOpen(new Runnable() {
751 final boolean autoImport
= getImportingSettings().isImportAutomatically();
752 // postpone activation to prevent import from being called from events poster
753 mySchedulesQueue
.queue(new Update(new Object()) {
755 if (autoImport
|| forceImport
) {
756 myImportingQueue
.activate();
759 myImportingQueue
.deactivate();
763 myImportingQueue
.queue(new Update(MavenProjectsManager
.this) {
766 if (!autoImport
) myImportingQueue
.deactivate();
769 if (!forceImport
) fireScheduledImportsChanged();
775 public void scheduleImportInTests(List
<VirtualFile
> projectFiles
) {
776 List
<Pair
<MavenProject
, MavenProjectChanges
>> toImport
= new ArrayList
<Pair
<MavenProject
, MavenProjectChanges
>>();
777 for (VirtualFile each
: projectFiles
) {
778 MavenProject project
= findProject(each
);
779 if (project
!= null) {
780 toImport
.add(Pair
.create(project
, MavenProjectChanges
.ALL
));
783 scheduleImport(toImport
, false);
786 private void scheduleForNextImport(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
) {
787 scheduleForNextImport(Collections
.singletonList(projectWithChanges
));
790 private void scheduleForNextImport(List
<Pair
<MavenProject
, MavenProjectChanges
>> projectsWithChanges
) {
791 synchronized (myImportingDataLock
) {
792 for (Pair
<MavenProject
, MavenProjectChanges
> each
: projectsWithChanges
) {
793 MavenProjectChanges changes
= each
.second
.mergedWith(myProjectsToImport
.get(each
.first
));
794 myProjectsToImport
.put(each
.first
, changes
);
799 public boolean hasScheduledImports() {
800 if (!isInitialized()) return false;
801 return !myImportingQueue
.isEmpty();
804 public int getScheduledProjectsCount() {
805 if (!isInitialized()) return 0;
806 synchronized (myImportingDataLock
) {
807 return myProjectsToImport
.size();
811 public void performScheduledImport() {
812 performScheduledImport(true);
815 public void performScheduledImport(final boolean force
) {
816 if (!isInitialized()) return;
817 runWhenFullyOpen(new Runnable() {
819 // ensure all pending schedules are processed
820 mySchedulesQueue
.flush(false);
821 if (!force
&& !myImportingQueue
.isActive()) return;
822 myImportingQueue
.flush(false);
827 private void runWhenFullyOpen(final Runnable runnable
) {
828 if (!isInitialized()) return; // may be called from scheduleImport after project started closing and before it is closed.
830 if (isNoBackgroundMode()) {
835 final Ref
<Runnable
> wrapper
= new Ref
<Runnable
>();
836 wrapper
.set(new Runnable() {
838 if (!StartupManagerEx
.getInstanceEx(myProject
).postStartupActivityPassed()) {
839 mySchedulesQueue
.queue(new Update(runnable
) { // should not remove previously schedules tasks
850 MavenUtil
.runWhenInitialized(myProject
, wrapper
.get());
853 private void schedulePostImportTasts(List
<MavenProjectsProcessorTask
> postTasks
) {
854 for (MavenProjectsProcessorTask each
: postTasks
) {
855 myPostProcessor
.scheduleTask(each
);
859 private void unscheduleAllTasks(List
<MavenProject
> projects
) {
860 for (MavenProject each
: projects
) {
861 MavenProjectsProcessorEmptyTask dummyTask
= new MavenProjectsProcessorEmptyTask(each
);
863 synchronized (myImportingDataLock
) {
864 myProjectsToImport
.remove(each
);
867 myResolvingProcessor
.removeTask(dummyTask
);
868 myPluginsResolvingProcessor
.removeTask(dummyTask
);
869 myFoldersResolvingProcessor
.removeTask(dummyTask
);
870 myArtifactsDownloadingProcessor
.removeTask(dummyTask
);
871 myPostProcessor
.removeTask(dummyTask
);
876 public void unscheduleAllTasksInTests() {
877 unscheduleAllTasks(getProjects());
880 public void waitForReadingCompletion() {
881 waitForTasksCompletion(Collections
.<MavenProjectsProcessor
>emptyList());
884 public void waitForResolvingCompletion() {
885 waitForTasksCompletion(myResolvingProcessor
);
888 public void waitForFoldersResolvingCompletion() {
889 waitForTasksCompletion(myFoldersResolvingProcessor
);
892 public void waitForPluginsResolvingCompletion() {
893 waitForTasksCompletion(myPluginsResolvingProcessor
);
896 public void waitForArtifactsDownloadingCompletion() {
897 waitForTasksCompletion(Arrays
.asList(myResolvingProcessor
, myArtifactsDownloadingProcessor
));
900 public void waitForPostImportTasksCompletion() {
901 myPostProcessor
.waitForCompletion();
904 private void waitForTasksCompletion(MavenProjectsProcessor processor
) {
905 waitForTasksCompletion(Collections
.singletonList(processor
));
908 private void waitForTasksCompletion(List
<MavenProjectsProcessor
> processors
) {
909 FileDocumentManager
.getInstance().saveAllDocuments();
911 myReadingProcessor
.waitForCompletion();
912 for (MavenProjectsProcessor each
: processors
) {
913 each
.waitForCompletion();
917 public void updateProjectTargetFolders() {
918 updateProjectFolders(true);
921 private void updateProjectFolders(final boolean targetFoldersOnly
) {
922 MavenUtil
.invokeLater(myProject
, new Runnable() {
924 MavenFoldersImporter
.updateProjectFolders(myProject
, targetFoldersOnly
);
925 VirtualFileManager
.getInstance().refresh(false);
930 public List
<Module
> importProjects() {
931 return importProjects(new MavenDefaultModifiableModelsProvider(myProject
));
934 public List
<Module
> importProjects(final MavenModifiableModelsProvider modelsProvider
) {
935 final Map
<MavenProject
, MavenProjectChanges
> projectsToImportWithChanges
;
936 final boolean importModuleGroupsRequired
;
937 synchronized (myImportingDataLock
) {
938 projectsToImportWithChanges
= new THashMap
<MavenProject
, MavenProjectChanges
>(myProjectsToImport
);
939 myProjectsToImport
.clear();
940 importModuleGroupsRequired
= myImportModuleGroupsRequired
;
942 fireScheduledImportsChanged();
944 final Ref
<MavenProjectImporter
> importer
= new Ref
<MavenProjectImporter
>();
945 final Ref
<List
<MavenProjectsProcessorTask
>> postTasks
= new Ref
<List
<MavenProjectsProcessorTask
>>();
947 final Runnable r
= new Runnable() {
949 importer
.set(new MavenProjectImporter(myProject
,
951 getFileToModuleMapping(modelsProvider
),
952 projectsToImportWithChanges
,
953 importModuleGroupsRequired
,
955 getImportingSettings()));
956 postTasks
.set(importer
.get().importProject());
960 // called from wizard or ui
961 if (ApplicationManager
.getApplication().isDispatchThread()) {
965 MavenUtil
.runInBackground(myProject
, ProjectBundle
.message("maven.project.importing"), false, new MavenTask() {
966 public void run(MavenProgressIndicator indicator
) throws MavenProcessCanceledException
{
973 VirtualFileManager
.getInstance().refresh(isNormalProject());
974 schedulePostImportTasts(postTasks
.get());
976 // do not block user too often
977 myImportingQueue
.restartTimer();
979 return importer
.get().getCreatedModules();
982 private Map
<VirtualFile
, Module
> getFileToModuleMapping(MavenModelsProvider modelsProvider
) {
983 Map
<VirtualFile
, Module
> result
= new THashMap
<VirtualFile
, Module
>();
984 for (Module each
: modelsProvider
.getModules()) {
985 VirtualFile f
= findPomFile(each
, modelsProvider
);
986 if (f
!= null) result
.put(f
, each
);
991 private List
<VirtualFile
> collectAllAvailablePomFiles() {
992 List
<VirtualFile
> result
= new ArrayList
<VirtualFile
>(getFileToModuleMapping(new MavenDefaultModelsProvider(myProject
)).keySet());
994 VirtualFile pom
= myProject
.getBaseDir().findChild(MavenConstants
.POM_XML
);
995 if (pom
!= null) result
.add(pom
);
1000 public MavenDomDependency
addDependency(final MavenProject mavenProject
, final MavenId id
) {
1001 final MavenArtifact
[] artifact
= new MavenArtifact
[1];
1004 MavenUtil
.run(myProject
, "Downloading dependency...", new MavenTask() {
1005 public void run(MavenProgressIndicator indicator
) throws MavenProcessCanceledException
{
1006 artifact
[0] = myProjectsTree
.downloadArtifact(mavenProject
, id
, myEmbeddersManager
, new SoutMavenConsole(), indicator
);
1010 catch (MavenProcessCanceledException ignore
) {
1014 VirtualFile file
= mavenProject
.getFile();
1015 PsiFile psiFile
= PsiManager
.getInstance(myProject
).findFile(file
);
1017 MavenDomDependency result
= new WriteCommandAction
<MavenDomDependency
>(myProject
, "Add Maven Dependency", psiFile
) {
1018 protected void run(Result
<MavenDomDependency
> result
) throws Throwable
{
1019 MavenDomProjectModel model
= MavenDomUtil
.getMavenDomProjectModel(myProject
, mavenProject
.getFile());
1020 MavenDomDependency domDependency
= model
.getDependencies().addDependency();
1021 domDependency
.getGroupId().setStringValue(artifact
[0].getGroupId());
1022 domDependency
.getArtifactId().setStringValue(artifact
[0].getArtifactId());
1023 domDependency
.getVersion().setStringValue(artifact
[0].getVersion());
1025 mavenProject
.addDependency(artifact
[0]);
1026 result
.setResult(domDependency
);
1028 }.execute().getResultObject();
1030 scheduleImport(Collections
.singletonList(Pair
.create(mavenProject
, MavenProjectChanges
.DEPENDENCIES
)), true);
1035 public void addManagerListener(Listener listener
) {
1036 myManagerListeners
.add(listener
);
1039 public void addProjectsTreeListener(MavenProjectsTree
.Listener listener
) {
1040 myProjectsTreeDispatcher
.addListener(listener
);
1044 public void fireActivatedInTests() {
1048 private void fireActivated() {
1049 for (Listener each
: myManagerListeners
) {
1054 private void fireScheduledImportsChanged() {
1055 for (Listener each
: myManagerListeners
) {
1056 each
.scheduledImportsChanged();
1060 public interface Listener
{
1063 void scheduledImportsChanged();