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
.NotNull
;
47 import org
.jetbrains
.annotations
.Nullable
;
48 import org
.jetbrains
.annotations
.TestOnly
;
49 import org
.jetbrains
.idea
.maven
.dom
.MavenDomUtil
;
50 import org
.jetbrains
.idea
.maven
.dom
.model
.MavenDomDependency
;
51 import org
.jetbrains
.idea
.maven
.dom
.model
.MavenDomProjectModel
;
52 import org
.jetbrains
.idea
.maven
.execution
.SoutMavenConsole
;
53 import org
.jetbrains
.idea
.maven
.importing
.MavenDefaultModifiableModelsProvider
;
54 import org
.jetbrains
.idea
.maven
.importing
.MavenFoldersImporter
;
55 import org
.jetbrains
.idea
.maven
.importing
.MavenModifiableModelsProvider
;
56 import org
.jetbrains
.idea
.maven
.importing
.MavenProjectImporter
;
57 import org
.jetbrains
.idea
.maven
.utils
.*;
60 import java
.io
.IOException
;
62 import java
.util
.concurrent
.atomic
.AtomicBoolean
;
64 @State(name
= "MavenProjectsManager", storages
= {@Storage(id
= "default", file
= "$PROJECT_FILE$")})
65 public class MavenProjectsManager
extends SimpleProjectComponent
implements PersistentStateComponent
<MavenProjectsManagerState
>,
66 SettingsSavingComponent
{
67 private static final int IMPORT_DELAY
= 1000;
69 static final Object SCHEDULE_IMPORT_MESSAGE
= "SCHEDULE_IMPORT_MESSAGE";
70 static final Object FORCE_IMPORT_MESSAGE
= "FORCE_IMPORT_MESSAGE";
72 private final AtomicBoolean isInitialized
= new AtomicBoolean();
74 private MavenProjectsManagerState myState
= new MavenProjectsManagerState();
76 private MavenEmbeddersManager myEmbeddersManager
;
78 private MavenProjectsTree myProjectsTree
;
79 private MavenProjectsManagerWatcher myWatcher
;
81 private MavenProjectsProcessor myReadingProcessor
;
82 private MavenProjectsProcessor myResolvingProcessor
;
83 private MavenProjectsProcessor myPluginsResolvingProcessor
;
84 private MavenProjectsProcessor myFoldersResolvingProcessor
;
85 private MavenProjectsProcessor myArtifactsDownloadingProcessor
;
86 private MavenProjectsProcessor myPostProcessor
;
88 private MavenMergingUpdateQueue myImportingQueue
;
89 private final Object myImportingDataLock
= new Object();
90 private final Map
<MavenProject
, MavenProjectChanges
> myProjectsToImport
= new THashMap
<MavenProject
, MavenProjectChanges
>();
91 private boolean myImportModuleGroupsRequired
= false;
93 private MavenMergingUpdateQueue mySchedulesQueue
;
95 private final EventDispatcher
<MavenProjectsTree
.Listener
> myProjectsTreeDispatcher
96 = EventDispatcher
.create(MavenProjectsTree
.Listener
.class);
97 private final List
<Listener
> myManagerListeners
= ContainerUtil
.createEmptyCOWList();
99 public static MavenProjectsManager
getInstance(Project p
) {
100 return p
.getComponent(MavenProjectsManager
.class);
103 public MavenProjectsManager(Project project
) {
107 public MavenProjectsManagerState
getState() {
108 if (isInitialized()) {
114 public void loadState(MavenProjectsManagerState state
) {
116 if (isInitialized()) {
118 scheduleUpdateAllProjects(false);
122 public MavenGeneralSettings
getGeneralSettings() {
123 return getWorkspaceSettings().generalSettings
;
126 public MavenImportingSettings
getImportingSettings() {
127 return getWorkspaceSettings().importingSettings
;
130 private MavenWorkspaceSettings
getWorkspaceSettings() {
131 return MavenWorkspaceSettingsComponent
.getInstance(myProject
).getState();
134 public File
getLocalRepository() {
135 return getGeneralSettings().getEffectiveLocalRepository();
139 public void initComponent() {
140 if (!isNormalProject()) return;
142 StartupManagerEx
.getInstanceEx(myProject
).registerStartupActivity(new Runnable() {
144 boolean wasMavenized
= !myState
.originalFiles
.isEmpty();
145 if (!wasMavenized
) return;
151 private void initMavenized() {
155 private void initNew(List
<VirtualFile
> files
, List
<String
> explicitProfiles
) {
156 myState
.originalFiles
= MavenUtil
.collectPaths(files
);
157 myState
.activeProfiles
= explicitProfiles
;
162 public void initForTests() {
166 private void doInit(final boolean isNew
) {
167 if (isInitialized
.getAndSet(true)) return;
169 initProjectsTree(!isNew
);
172 listenForSettingsChanges();
173 listenForProjectsTreeChanges();
175 MavenUtil
.runWhenInitialized(myProject
, new DumbAwareRunnable() {
177 if (!isUnitTestMode()) {
179 listenForExternalChanges();
181 scheduleUpdateAllProjects(isNew
);
186 private void initProjectsTree(boolean tryToLoadExisting
) {
187 if (tryToLoadExisting
) {
188 File file
= getProjectsTreeFile();
191 myProjectsTree
= MavenProjectsTree
.read(file
);
194 catch (IOException e
) {
195 MavenLog
.LOG
.info(e
);
199 if (myProjectsTree
== null) myProjectsTree
= new MavenProjectsTree();
201 myProjectsTree
.addListener(myProjectsTreeDispatcher
.getMulticaster());
204 private void applyTreeToState() {
205 myState
.originalFiles
= myProjectsTree
.getManagedFilesPaths();
206 myState
.activeProfiles
= new ArrayList
<String
>(myProjectsTree
.getExplicitProfiles());
207 myState
.ignoredFiles
= new THashSet
<String
>(myProjectsTree
.getIgnoredFilesPaths());
208 myState
.ignoredPathMasks
= myProjectsTree
.getIgnoredFilesPatterns();
211 private void applyStateToTree() {
212 myProjectsTree
.resetManagedFilesPathsAndProfiles(myState
.originalFiles
, myState
.activeProfiles
);
213 myProjectsTree
.setIgnoredFilesPaths(new ArrayList
<String
>(myState
.ignoredFiles
));
214 myProjectsTree
.setIgnoredFilesPatterns(myState
.ignoredPathMasks
);
218 if (myProjectsTree
!= null) {
220 myProjectsTree
.save(getProjectsTreeFile());
222 catch (IOException e
) {
223 MavenLog
.LOG
.error(e
);
228 private File
getProjectsTreeFile() {
229 File file
= new File(getProjectsTreesDir(), myProject
.getLocationHash() + "/tree.dat");
230 file
.getParentFile().mkdirs();
234 private static File
getProjectsTreesDir() {
235 return MavenUtil
.getPluginSystemDir("Projects");
238 private void initWorkers() {
239 myEmbeddersManager
= new MavenEmbeddersManager(getGeneralSettings());
241 myReadingProcessor
= new MavenProjectsProcessor(myProject
,
242 ProjectBundle
.message("maven.reading"),
245 myResolvingProcessor
= new MavenProjectsProcessor(myProject
,
246 ProjectBundle
.message("maven.resolving"),
249 myPluginsResolvingProcessor
= new MavenProjectsProcessor(myProject
,
250 ProjectBundle
.message("maven.downloading.plugins"),
253 myFoldersResolvingProcessor
= new MavenProjectsProcessor(myProject
,
254 ProjectBundle
.message("maven.updating.folders"),
257 myArtifactsDownloadingProcessor
= new MavenProjectsProcessor(myProject
,
258 ProjectBundle
.message("maven.downloading"),
261 myPostProcessor
= new MavenProjectsProcessor(myProject
,
262 ProjectBundle
.message("maven.post.processing"),
266 myWatcher
= new MavenProjectsManagerWatcher(myProject
, myProjectsTree
, getGeneralSettings(), myReadingProcessor
, myEmbeddersManager
);
268 myImportingQueue
= new MavenMergingUpdateQueue(getComponentName() + ": Importing queue", IMPORT_DELAY
, !isUnitTestMode(), myProject
);
269 myImportingQueue
.setPassThrough(false);
271 myImportingQueue
.makeUserAware(myProject
);
272 myImportingQueue
.makeDumbAware(myProject
);
273 myImportingQueue
.makeModalAware(myProject
);
275 mySchedulesQueue
= new MavenMergingUpdateQueue(getComponentName() + ": Schedules queue", 500, !isUnitTestMode(), myProject
);
276 mySchedulesQueue
.setPassThrough(false);
279 private void listenForSettingsChanges() {
280 getImportingSettings().addListener(new MavenImportingSettings
.Listener() {
281 public void autoImportChanged() {
282 scheduleImportSettings();
285 public void createModuleGroupsChanged() {
286 scheduleImportSettings(true);
289 public void createModuleForAggregatorsChanged() {
290 scheduleImportSettings();
295 private void listenForProjectsTreeChanges() {
296 myProjectsTree
.addListener(new MavenProjectsTree
.ListenerAdapter() {
298 public void projectsIgnoredStateChanged(List
<MavenProject
> ignored
, List
<MavenProject
> unignored
, Object message
) {
299 if (message
instanceof MavenProjectImporter
) return;
300 scheduleImport(false);
304 public void projectsUpdated(List
<Pair
<MavenProject
, MavenProjectChanges
>> updated
, List
<MavenProject
> deleted
, Object message
) {
305 myEmbeddersManager
.clearCaches();
307 unscheduleAllTasks(deleted
);
309 List
<MavenProject
> updatedProjects
= MavenUtil
.collectFirsts(updated
);
311 // import only updated and the dependents (we need to update faced-deps, packaging etc);
312 List
<Pair
<MavenProject
, MavenProjectChanges
>> toImport
= new ArrayList
<Pair
<MavenProject
, MavenProjectChanges
>>(updated
);
313 for (MavenProject each
: updatedProjects
) {
314 for (MavenProject eachDependent
: myProjectsTree
.getDependentProjects(each
)) {
315 toImport
.add(Pair
.create(eachDependent
, MavenProjectChanges
.DEPENDENCIES
));
319 // resolve updated, theirs dependents, and dependents of deleted
320 Set
<MavenProject
> toResolve
= new THashSet
<MavenProject
>(updatedProjects
);
321 for (MavenProject each
: ContainerUtil
.concat(updatedProjects
, deleted
)) {
322 toResolve
.addAll(myProjectsTree
.getDependentProjects(each
));
325 // do not try to resolve projects with syntactic errors
326 Iterator
<MavenProject
> it
= toResolve
.iterator();
327 while (it
.hasNext()) {
328 MavenProject each
= it
.next();
329 if (each
.hasReadingProblems()) it
.remove();
332 if (haveChanges(toImport
) || !deleted
.isEmpty()) {
333 scheduleImport(toImport
, message
== FORCE_IMPORT_MESSAGE
);
335 scheduleResolve(toResolve
, message
== FORCE_IMPORT_MESSAGE
);
338 private boolean haveChanges(List
<Pair
<MavenProject
, MavenProjectChanges
>> projectsWithChanges
) {
339 for (MavenProjectChanges each
: MavenUtil
.collectSeconds(projectsWithChanges
)) {
340 if (each
.hasChanges()) return true;
346 public void projectResolved(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
,
347 org
.apache
.maven
.project
.MavenProject nativeMavenProject
,
349 if (shouldScheduleProject(projectWithChanges
)) {
350 if (projectWithChanges
.first
.hasUnresolvedPlugins()) {
351 schedulePluginsResolving(projectWithChanges
.first
, nativeMavenProject
);
353 scheduleArtifactsDownloading(Collections
.singleton(projectWithChanges
.first
),
354 getImportingSettings().shouldDownloadSourcesAutomatically(),
355 getImportingSettings().shouldDownloadDocsAutomatically());
356 scheduleForNextImport(projectWithChanges
);
358 processMessage(message
);
362 public void foldersResolved(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
, Object message
) {
363 if (shouldScheduleProject(projectWithChanges
)) {
364 scheduleForNextImport(projectWithChanges
);
366 processMessage(message
);
369 private boolean shouldScheduleProject(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
) {
370 return !projectWithChanges
.first
.hasReadingProblems() && projectWithChanges
.second
.hasChanges();
373 private void processMessage(Object message
) {
374 if (getScheduledProjectsCount() == 0) return;
376 if (message
== SCHEDULE_IMPORT_MESSAGE
) {
377 scheduleImport(false);
379 else if (message
== FORCE_IMPORT_MESSAGE
) {
380 scheduleImport(true);
386 public void listenForExternalChanges() {
391 public void projectClosed() {
392 if (!isInitialized
.getAndSet(false)) return;
394 Disposer
.dispose(mySchedulesQueue
);
395 Disposer
.dispose(myImportingQueue
);
399 myReadingProcessor
.stop();
400 myResolvingProcessor
.stop();
401 myPluginsResolvingProcessor
.stop();
402 myFoldersResolvingProcessor
.stop();
403 myArtifactsDownloadingProcessor
.stop();
404 myPostProcessor
.stop();
406 myEmbeddersManager
.release();
408 if (isUnitTestMode()) {
409 FileUtil
.delete(getProjectsTreesDir());
414 public MavenEmbeddersManager
getEmbeddersManagerInTests() {
415 return myEmbeddersManager
;
418 private boolean isInitialized() {
419 return isInitialized
.get();
422 public boolean isMavenizedProject() {
423 return isInitialized();
426 public boolean isMavenizedModule(final Module m
) {
427 return ApplicationManager
.getApplication().runReadAction(new Computable
<Boolean
>() {
428 public Boolean
compute() {
429 return "true".equals(m
.getOptionValue(getMavenizedModuleOptionName()));
434 public void setMavenizedModules(Collection
<Module
> modules
, boolean mavenized
) {
435 ApplicationManager
.getApplication().assertWriteAccessAllowed();
436 for (Module m
: modules
) {
438 m
.setOption(getMavenizedModuleOptionName(), "true");
441 m
.clearOption(getMavenizedModuleOptionName());
446 private String
getMavenizedModuleOptionName() {
447 return getComponentName() + ".isMavenModule";
451 public void resetManagedFilesAndProfilesInTests(List
<VirtualFile
> files
, List
<String
> profiles
) {
452 myWatcher
.resetManagedFilesAndProfilesInTests(files
, profiles
);
455 public void addManagedFilesWithProfiles(List
<VirtualFile
> files
, List
<String
> profiles
) {
456 if (!isInitialized()) {
457 initNew(files
, profiles
);
460 myWatcher
.addManagedFilesWithProfiles(files
, profiles
);
464 public void addManagedFiles(List
<VirtualFile
> files
) {
465 addManagedFilesWithProfiles(files
, Collections
.<String
>emptyList());
468 public void removeManagedFiles(List
<VirtualFile
> files
) {
469 myWatcher
.removeManagedFiles(files
);
472 public boolean isManagedFile(VirtualFile f
) {
473 if (!isInitialized()) return false;
474 return myProjectsTree
.isManagedFile(f
);
477 public Collection
<String
> getExplicitProfiles() {
478 if (!isInitialized()) return Collections
.emptyList();
479 return myProjectsTree
.getExplicitProfiles();
482 public void setExplicitProfiles(Collection
<String
> profiles
) {
483 myWatcher
.setExplicitProfiles(profiles
);
486 public Collection
<String
> getAvailableProfiles() {
487 if (!isInitialized()) return Collections
.emptyList();
488 return myProjectsTree
.getAvailableProfiles();
491 public Collection
<Pair
<String
, MavenProfileState
>> getProfilesWithStates() {
492 if (!isInitialized()) return Collections
.emptyList();
493 return myProjectsTree
.getProfilesWithStates();
496 public boolean hasProjects() {
497 if (!isInitialized()) return false;
498 return myProjectsTree
.hasProjects();
501 public List
<MavenProject
> getProjects() {
502 if (!isInitialized()) return Collections
.emptyList();
503 return myProjectsTree
.getProjects();
506 public List
<MavenProject
> getNonIgnoredProjects() {
507 if (!isInitialized()) return Collections
.emptyList();
508 return myProjectsTree
.getNonIgnoredProjects();
511 public List
<VirtualFile
> getProjectsFiles() {
512 if (!isInitialized()) return Collections
.emptyList();
513 return myProjectsTree
.getProjectsFiles();
516 public MavenProject
findProject(VirtualFile f
) {
517 if (!isInitialized()) return null;
518 return myProjectsTree
.findProject(f
);
521 public MavenProject
findProject(MavenId id
) {
522 if (!isInitialized()) return null;
523 return myProjectsTree
.findProject(id
);
526 public MavenProject
findProject(MavenArtifact artifact
) {
527 if (!isInitialized()) return null;
528 return myProjectsTree
.findProject(artifact
);
531 public MavenProject
findProject(Module module
) {
532 VirtualFile f
= findPomFile(module
, new MavenModelsProvider() {
533 public Module
[] getModules() {
534 throw new UnsupportedOperationException();
537 public VirtualFile
[] getContentRoots(Module module
) {
538 return ModuleRootManager
.getInstance(module
).getContentRoots();
541 return f
== null ?
null : findProject(f
);
545 public Module
findModule(MavenProject project
) {
546 if (!isInitialized()) return null;
547 return ProjectRootManager
.getInstance(myProject
).getFileIndex().getModuleForFile(project
.getFile());
551 public Set
<MavenProject
> findInheritors(@Nullable MavenProject parent
) {
552 if (parent
== null || !isInitialized()) return Collections
.emptySet();
553 return myProjectsTree
.findInheritors(parent
);
556 public MavenProject
findContainingProject(VirtualFile file
) {
557 if (!isInitialized()) return null;
558 Module module
= ProjectRootManager
.getInstance(myProject
).getFileIndex().getModuleForFile(file
);
559 return module
== null ?
null : findProject(module
);
562 private static VirtualFile
findPomFile(Module module
, MavenModelsProvider modelsProvider
) {
563 for (VirtualFile root
: modelsProvider
.getContentRoots(module
)) {
564 final VirtualFile virtualFile
= root
.findChild(MavenConstants
.POM_XML
);
565 if (virtualFile
!= null) {
572 public MavenProject
findAggregator(MavenProject module
) {
573 if (!isInitialized()) return null;
574 return myProjectsTree
.findAggregator(module
);
577 public List
<MavenProject
> getModules(MavenProject aggregator
) {
578 if (!isInitialized()) return Collections
.emptyList();
579 return myProjectsTree
.getModules(aggregator
);
582 public List
<String
> getIgnoredFilesPaths() {
583 if (!isInitialized()) return Collections
.emptyList();
584 return myProjectsTree
.getIgnoredFilesPaths();
587 public void setIgnoredFilesPaths(List
<String
> paths
) {
588 if (!isInitialized()) return;
589 myProjectsTree
.setIgnoredFilesPaths(paths
);
592 public boolean getIgnoredState(MavenProject project
) {
593 if (!isInitialized()) return false;
594 return myProjectsTree
.getIgnoredState(project
);
597 public void setIgnoredState(List
<MavenProject
> projects
, boolean ignored
) {
598 if (!isInitialized()) return;
599 myProjectsTree
.setIgnoredState(projects
, ignored
);
602 public List
<String
> getIgnoredFilesPatterns() {
603 if (!isInitialized()) return Collections
.emptyList();
604 return myProjectsTree
.getIgnoredFilesPatterns();
607 public void setIgnoredFilesPatterns(List
<String
> patterns
) {
608 if (!isInitialized()) return;
609 myProjectsTree
.setIgnoredFilesPatterns(patterns
);
612 public boolean isIgnored(MavenProject project
) {
613 if (!isInitialized()) return false;
614 return myProjectsTree
.isIgnored(project
);
617 public Set
<MavenRemoteRepository
> getRemoteRepositories() {
618 Set
<MavenRemoteRepository
> result
= new THashSet
<MavenRemoteRepository
>();
619 for (MavenProject each
: getProjects()) {
620 for (MavenRemoteRepository eachRepository
: each
.getRemoteRepositories()) {
621 result
.add(eachRepository
);
628 public MavenProjectsTree
getProjectsTreeForTests() {
629 return myProjectsTree
;
632 private void scheduleUpdateAllProjects(boolean forceImport
) {
633 doScheduleUpdateProjects(null, false, forceImport
);
636 public void forceUpdateProjects(Collection
<MavenProject
> projects
) {
637 doScheduleUpdateProjects(projects
, true, true);
640 public void forceUpdateAllProjectsOrFindAllAvailablePomFiles() {
641 if (!isMavenizedProject()) {
642 addManagedFiles(collectAllAvailablePomFiles());
644 doScheduleUpdateProjects(null, true, true);
647 private void doScheduleUpdateProjects(final Collection
<MavenProject
> projects
, final boolean force
, final boolean forceImport
) {
648 // read when postStartupActivitias start
649 MavenUtil
.runWhenInitialized(myProject
, new DumbAwareRunnable() {
651 if (projects
== null) {
652 myWatcher
.scheduleUpdateAll(force
, forceImport
);
655 myWatcher
.scheduleUpdate(MavenUtil
.collectFiles(projects
), Collections
.EMPTY_LIST
, force
, forceImport
);
661 private void scheduleResolve(final Collection
<MavenProject
> projects
, final boolean forceImport
) {
662 runWhenFullyOpen(new Runnable() {
664 Iterator
<MavenProject
> it
= projects
.iterator();
665 while (it
.hasNext()) {
666 MavenProject each
= it
.next();
667 Object message
= it
.hasNext() ?
null : (forceImport ? FORCE_IMPORT_MESSAGE
: SCHEDULE_IMPORT_MESSAGE
);
668 myResolvingProcessor
.scheduleTask(new MavenProjectsProcessorResolvingTask(each
,
670 getGeneralSettings(),
678 public void scheduleResolveInTests(Collection
<MavenProject
> projects
) {
679 scheduleResolve(projects
, false);
683 public void scheduleResolveAllInTests() {
684 scheduleResolve(getProjects(), false);
687 public void scheduleFoldersResolving(final Collection
<MavenProject
> projects
) {
688 runWhenFullyOpen(new Runnable() {
690 Iterator
<MavenProject
> it
= projects
.iterator();
691 while (it
.hasNext()) {
692 MavenProject each
= it
.next();
693 Object message
= it
.hasNext() ?
null : FORCE_IMPORT_MESSAGE
;
694 myFoldersResolvingProcessor
.scheduleTask(new MavenProjectsProcessorFoldersResolvingTask(each
,
695 getGeneralSettings(),
696 getImportingSettings(),
704 public void scheduleFoldersResolvingForAllProjects() {
705 scheduleFoldersResolving(getProjects());
708 private void schedulePluginsResolving(final MavenProject project
, final org
.apache
.maven
.project
.MavenProject nativeMavenProject
) {
709 runWhenFullyOpen(new Runnable() {
711 myPluginsResolvingProcessor
.scheduleTask(new MavenProjectsProcessorPluginsResolvingTask(project
,
718 public void scheduleArtifactsDownloading(final Collection
<MavenProject
> projects
, final boolean sources
, final boolean docs
) {
719 if (!sources
&& !docs
) return;
721 runWhenFullyOpen(new Runnable() {
723 for (MavenProject each
: projects
) {
724 myArtifactsDownloadingProcessor
.scheduleTask(
725 new MavenProjectsProcessorArtifactsDownloadingTask(each
, myProjectsTree
, sources
, docs
));
731 public void scheduleArtifactsDownloading(final Collection
<MavenProject
> projects
) {
732 scheduleArtifactsDownloading(projects
, true, true);
735 public void scheduleArtifactsDownloadingForAllProjects() {
736 scheduleArtifactsDownloading(getProjects());
739 private void scheduleImport(List
<Pair
<MavenProject
, MavenProjectChanges
>> projectsWithChanges
, boolean forceImport
) {
740 scheduleForNextImport(projectsWithChanges
);
741 scheduleImport(forceImport
);
744 private void scheduleImportSettings() {
745 scheduleImportSettings(false);
748 private void scheduleImportSettings(boolean importModuleGroupsRequired
) {
749 synchronized (myImportingDataLock
) {
750 myImportModuleGroupsRequired
= importModuleGroupsRequired
;
752 scheduleImport(false);
755 private void scheduleImport(final boolean forceImport
) {
756 runWhenFullyOpen(new Runnable() {
758 final boolean autoImport
= getImportingSettings().isImportAutomatically();
759 // postpone activation to prevent import from being called from events poster
760 mySchedulesQueue
.queue(new Update(new Object()) {
762 if (autoImport
|| forceImport
) {
763 myImportingQueue
.activate();
766 myImportingQueue
.deactivate();
770 myImportingQueue
.queue(new Update(MavenProjectsManager
.this) {
773 if (!autoImport
) myImportingQueue
.deactivate();
776 if (!forceImport
) fireScheduledImportsChanged();
782 public void scheduleImportInTests(List
<VirtualFile
> projectFiles
) {
783 List
<Pair
<MavenProject
, MavenProjectChanges
>> toImport
= new ArrayList
<Pair
<MavenProject
, MavenProjectChanges
>>();
784 for (VirtualFile each
: projectFiles
) {
785 MavenProject project
= findProject(each
);
786 if (project
!= null) {
787 toImport
.add(Pair
.create(project
, MavenProjectChanges
.ALL
));
790 scheduleImport(toImport
, false);
793 private void scheduleForNextImport(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
) {
794 scheduleForNextImport(Collections
.singletonList(projectWithChanges
));
797 private void scheduleForNextImport(List
<Pair
<MavenProject
, MavenProjectChanges
>> projectsWithChanges
) {
798 synchronized (myImportingDataLock
) {
799 for (Pair
<MavenProject
, MavenProjectChanges
> each
: projectsWithChanges
) {
800 MavenProjectChanges changes
= each
.second
.mergedWith(myProjectsToImport
.get(each
.first
));
801 myProjectsToImport
.put(each
.first
, changes
);
806 public boolean hasScheduledImports() {
807 if (!isInitialized()) return false;
808 return !myImportingQueue
.isEmpty();
811 public int getScheduledProjectsCount() {
812 if (!isInitialized()) return 0;
813 synchronized (myImportingDataLock
) {
814 return myProjectsToImport
.size();
818 public void performScheduledImport() {
819 performScheduledImport(true);
822 public void performScheduledImport(final boolean force
) {
823 if (!isInitialized()) return;
824 runWhenFullyOpen(new Runnable() {
826 // ensure all pending schedules are processed
827 mySchedulesQueue
.flush(false);
828 if (!force
&& !myImportingQueue
.isActive()) return;
829 myImportingQueue
.flush(false);
834 private void runWhenFullyOpen(final Runnable runnable
) {
835 if (!isInitialized()) return; // may be called from scheduleImport after project started closing and before it is closed.
837 if (isNoBackgroundMode()) {
842 final Ref
<Runnable
> wrapper
= new Ref
<Runnable
>();
843 wrapper
.set(new Runnable() {
845 if (!StartupManagerEx
.getInstanceEx(myProject
).postStartupActivityPassed()) {
846 mySchedulesQueue
.queue(new Update(runnable
) { // should not remove previously schedules tasks
857 MavenUtil
.runWhenInitialized(myProject
, wrapper
.get());
860 private void schedulePostImportTasts(List
<MavenProjectsProcessorTask
> postTasks
) {
861 for (MavenProjectsProcessorTask each
: postTasks
) {
862 myPostProcessor
.scheduleTask(each
);
866 private void unscheduleAllTasks(List
<MavenProject
> projects
) {
867 for (MavenProject each
: projects
) {
868 MavenProjectsProcessorEmptyTask dummyTask
= new MavenProjectsProcessorEmptyTask(each
);
870 synchronized (myImportingDataLock
) {
871 myProjectsToImport
.remove(each
);
874 myResolvingProcessor
.removeTask(dummyTask
);
875 myPluginsResolvingProcessor
.removeTask(dummyTask
);
876 myFoldersResolvingProcessor
.removeTask(dummyTask
);
877 myArtifactsDownloadingProcessor
.removeTask(dummyTask
);
878 myPostProcessor
.removeTask(dummyTask
);
883 public void unscheduleAllTasksInTests() {
884 unscheduleAllTasks(getProjects());
887 public void waitForReadingCompletion() {
888 waitForTasksCompletion(Collections
.<MavenProjectsProcessor
>emptyList());
891 public void waitForResolvingCompletion() {
892 waitForTasksCompletion(myResolvingProcessor
);
895 public void waitForFoldersResolvingCompletion() {
896 waitForTasksCompletion(myFoldersResolvingProcessor
);
899 public void waitForPluginsResolvingCompletion() {
900 waitForTasksCompletion(myPluginsResolvingProcessor
);
903 public void waitForArtifactsDownloadingCompletion() {
904 waitForTasksCompletion(Arrays
.asList(myResolvingProcessor
, myArtifactsDownloadingProcessor
));
907 public void waitForPostImportTasksCompletion() {
908 myPostProcessor
.waitForCompletion();
911 private void waitForTasksCompletion(MavenProjectsProcessor processor
) {
912 waitForTasksCompletion(Collections
.singletonList(processor
));
915 private void waitForTasksCompletion(List
<MavenProjectsProcessor
> processors
) {
916 FileDocumentManager
.getInstance().saveAllDocuments();
918 myReadingProcessor
.waitForCompletion();
919 for (MavenProjectsProcessor each
: processors
) {
920 each
.waitForCompletion();
924 public void updateProjectTargetFolders() {
925 updateProjectFolders(true);
928 private void updateProjectFolders(final boolean targetFoldersOnly
) {
929 MavenUtil
.invokeLater(myProject
, new Runnable() {
931 MavenFoldersImporter
.updateProjectFolders(myProject
, targetFoldersOnly
);
932 VirtualFileManager
.getInstance().refresh(false);
937 public List
<Module
> importProjects() {
938 return importProjects(new MavenDefaultModifiableModelsProvider(myProject
));
941 public List
<Module
> importProjects(final MavenModifiableModelsProvider modelsProvider
) {
942 final Map
<MavenProject
, MavenProjectChanges
> projectsToImportWithChanges
;
943 final boolean importModuleGroupsRequired
;
944 synchronized (myImportingDataLock
) {
945 projectsToImportWithChanges
= new THashMap
<MavenProject
, MavenProjectChanges
>(myProjectsToImport
);
946 myProjectsToImport
.clear();
947 importModuleGroupsRequired
= myImportModuleGroupsRequired
;
949 fireScheduledImportsChanged();
951 final Ref
<MavenProjectImporter
> importer
= new Ref
<MavenProjectImporter
>();
952 final Ref
<List
<MavenProjectsProcessorTask
>> postTasks
= new Ref
<List
<MavenProjectsProcessorTask
>>();
954 final Runnable r
= new Runnable() {
956 importer
.set(new MavenProjectImporter(myProject
,
958 getFileToModuleMapping(modelsProvider
),
959 projectsToImportWithChanges
,
960 importModuleGroupsRequired
,
962 getImportingSettings()));
963 postTasks
.set(importer
.get().importProject());
967 // called from wizard or ui
968 if (ApplicationManager
.getApplication().isDispatchThread()) {
972 MavenUtil
.runInBackground(myProject
, ProjectBundle
.message("maven.project.importing"), false, new MavenTask() {
973 public void run(MavenProgressIndicator indicator
) throws MavenProcessCanceledException
{
980 VirtualFileManager
.getInstance().refresh(isNormalProject());
981 schedulePostImportTasts(postTasks
.get());
983 // do not block user too often
984 myImportingQueue
.restartTimer();
986 return importer
.get().getCreatedModules();
989 private Map
<VirtualFile
, Module
> getFileToModuleMapping(MavenModelsProvider modelsProvider
) {
990 Map
<VirtualFile
, Module
> result
= new THashMap
<VirtualFile
, Module
>();
991 for (Module each
: modelsProvider
.getModules()) {
992 VirtualFile f
= findPomFile(each
, modelsProvider
);
993 if (f
!= null) result
.put(f
, each
);
998 private List
<VirtualFile
> collectAllAvailablePomFiles() {
999 List
<VirtualFile
> result
= new ArrayList
<VirtualFile
>(getFileToModuleMapping(new MavenDefaultModelsProvider(myProject
)).keySet());
1001 VirtualFile pom
= myProject
.getBaseDir().findChild(MavenConstants
.POM_XML
);
1002 if (pom
!= null) result
.add(pom
);
1007 public MavenDomDependency
addDependency(final MavenProject mavenProject
, final MavenId id
) {
1008 final MavenArtifact
[] artifact
= new MavenArtifact
[1];
1011 MavenUtil
.run(myProject
, "Downloading dependency...", new MavenTask() {
1012 public void run(MavenProgressIndicator indicator
) throws MavenProcessCanceledException
{
1013 artifact
[0] = myProjectsTree
.downloadArtifact(mavenProject
, id
, myEmbeddersManager
, new SoutMavenConsole(), indicator
);
1017 catch (MavenProcessCanceledException ignore
) {
1021 VirtualFile file
= mavenProject
.getFile();
1022 PsiFile psiFile
= PsiManager
.getInstance(myProject
).findFile(file
);
1024 MavenDomDependency result
= new WriteCommandAction
<MavenDomDependency
>(myProject
, "Add Maven Dependency", psiFile
) {
1025 protected void run(Result
<MavenDomDependency
> result
) throws Throwable
{
1026 MavenDomProjectModel model
= MavenDomUtil
.getMavenDomProjectModel(myProject
, mavenProject
.getFile());
1027 MavenDomDependency domDependency
= model
.getDependencies().addDependency();
1028 domDependency
.getGroupId().setStringValue(artifact
[0].getGroupId());
1029 domDependency
.getArtifactId().setStringValue(artifact
[0].getArtifactId());
1030 domDependency
.getVersion().setStringValue(artifact
[0].getVersion());
1032 mavenProject
.addDependency(artifact
[0]);
1033 result
.setResult(domDependency
);
1035 }.execute().getResultObject();
1037 scheduleImport(Collections
.singletonList(Pair
.create(mavenProject
, MavenProjectChanges
.DEPENDENCIES
)), true);
1042 public void addManagerListener(Listener listener
) {
1043 myManagerListeners
.add(listener
);
1046 public void addProjectsTreeListener(MavenProjectsTree
.Listener listener
) {
1047 myProjectsTreeDispatcher
.addListener(listener
);
1051 public void fireActivatedInTests() {
1055 private void fireActivated() {
1056 for (Listener each
: myManagerListeners
) {
1061 private void fireScheduledImportsChanged() {
1062 for (Listener each
: myManagerListeners
) {
1063 each
.scheduledImportsChanged();
1067 public interface Listener
{
1070 void scheduledImportsChanged();