aae43998a29157145e2df38b3b08fa692c491011
[fedora-idea.git] / plugins / maven / src / main / java / org / jetbrains / idea / maven / project / MavenProjectsManager.java
blobaae43998a29157145e2df38b3b08fa692c491011
1 /*
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.*;
58 import java.io.File;
59 import java.io.IOException;
60 import java.util.*;
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) {
103 super(project);
106 public MavenProjectsManagerState getState() {
107 if (isInitialized()) {
108 applyTreeToState();
110 return myState;
113 public void loadState(MavenProjectsManagerState state) {
114 myState = state;
115 if (isInitialized()) {
116 applyStateToTree();
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();
137 @Override
138 public void initComponent() {
139 if (!isNormalProject()) return;
141 StartupManagerEx.getInstanceEx(myProject).registerStartupActivity(new Runnable() {
142 public void run() {
143 boolean wasMavenized = !myState.originalFiles.isEmpty();
144 if (!wasMavenized) return;
145 initMavenized();
150 private void initMavenized() {
151 doInit(false);
154 private void initNew(List<VirtualFile> files, List<String> explicitProfiles) {
155 myState.originalFiles = MavenUtil.collectPaths(files);
156 myState.activeProfiles = explicitProfiles;
157 doInit(true);
160 @TestOnly
161 public void initForTests() {
162 doInit(false);
165 private void doInit(final boolean isNew) {
166 if (isInitialized.getAndSet(true)) return;
168 initProjectsTree(!isNew);
170 initWorkers();
171 listenForSettingsChanges();
172 listenForProjectsTreeChanges();
174 MavenUtil.runWhenInitialized(myProject, new DumbAwareRunnable() {
175 public void run() {
176 if (!isUnitTestMode()) {
177 fireActivated();
178 listenForExternalChanges();
180 scheduleUpdateAllProjects(isNew);
185 private void initProjectsTree(boolean tryToLoadExisting) {
186 if (tryToLoadExisting) {
187 File file = getProjectsTreeFile();
188 try {
189 if (file.exists()) {
190 myProjectsTree = MavenProjectsTree.read(file);
193 catch (IOException e) {
194 MavenLog.LOG.info(e);
198 if (myProjectsTree == null) myProjectsTree = new MavenProjectsTree();
199 applyStateToTree();
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);
216 public void save() {
217 if (myProjectsTree != null) {
218 try {
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();
230 return file;
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"),
242 false,
243 myEmbeddersManager);
244 myResolvingProcessor = new MavenProjectsProcessor(myProject,
245 ProjectBundle.message("maven.resolving"),
246 true,
247 myEmbeddersManager);
248 myPluginsResolvingProcessor = new MavenProjectsProcessor(myProject,
249 ProjectBundle.message("maven.downloading.plugins"),
250 true,
251 myEmbeddersManager);
252 myFoldersResolvingProcessor = new MavenProjectsProcessor(myProject,
253 ProjectBundle.message("maven.updating.folders"),
254 true,
255 myEmbeddersManager);
256 myArtifactsDownloadingProcessor = new MavenProjectsProcessor(myProject,
257 ProjectBundle.message("maven.downloading"),
258 true,
259 myEmbeddersManager);
260 myPostProcessor = new MavenProjectsProcessor(myProject,
261 ProjectBundle.message("maven.post.processing"),
262 true,
263 myEmbeddersManager);
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() {
296 @Override
297 public void projectsIgnoredStateChanged(List<MavenProject> ignored, List<MavenProject> unignored, Object message) {
298 if (message instanceof MavenProjectImporter) return;
299 scheduleImport(false);
302 @Override
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;
341 return false;
344 @Override
345 public void projectResolved(Pair<MavenProject, MavenProjectChanges> projectWithChanges,
346 org.apache.maven.project.MavenProject nativeMavenProject,
347 Object message) {
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);
360 @Override
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() {
386 myWatcher.start();
389 @Override
390 public void projectClosed() {
391 if (!isInitialized.getAndSet(false)) return;
393 Disposer.dispose(mySchedulesQueue);
394 Disposer.dispose(myImportingQueue);
396 myWatcher.stop();
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());
412 @TestOnly
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) {
436 if (mavenized) {
437 m.setOption(getMavenizedModuleOptionName(), "true");
439 else {
440 m.clearOption(getMavenizedModuleOptionName());
445 private String getMavenizedModuleOptionName() {
446 return getComponentName() + ".isMavenModule";
449 @TestOnly
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);
458 else {
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);
543 @Nullable
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) {
559 return virtualFile;
562 return 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);
617 return result;
620 @TestOnly
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() {
643 public void run() {
644 if (projects == null) {
645 myWatcher.scheduleUpdateAll(force, forceImport);
647 else {
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() {
656 public void run() {
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,
662 myProjectsTree,
663 getGeneralSettings(),
664 message));
670 @TestOnly
671 public void scheduleResolveInTests(Collection<MavenProject> projects) {
672 scheduleResolve(projects, false);
675 @TestOnly
676 public void scheduleResolveAllInTests() {
677 scheduleResolve(getProjects(), false);
680 public void scheduleFoldersResolving(final Collection<MavenProject> projects) {
681 runWhenFullyOpen(new Runnable() {
682 public void run() {
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(),
690 myProjectsTree,
691 message));
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() {
703 public void run() {
704 myPluginsResolvingProcessor.scheduleTask(new MavenProjectsProcessorPluginsResolvingTask(project,
705 nativeMavenProject,
706 myProjectsTree));
711 public void scheduleArtifactsDownloading(final Collection<MavenProject> projects, final boolean sources, final boolean docs) {
712 if (!sources && !docs) return;
714 runWhenFullyOpen(new Runnable() {
715 public void run() {
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() {
750 public void run() {
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()) {
754 public void run() {
755 if (autoImport || forceImport) {
756 myImportingQueue.activate();
758 else {
759 myImportingQueue.deactivate();
763 myImportingQueue.queue(new Update(MavenProjectsManager.this) {
764 public void run() {
765 importProjects();
766 if (!autoImport) myImportingQueue.deactivate();
769 if (!forceImport) fireScheduledImportsChanged();
774 @TestOnly
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() {
818 public void run() {
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()) {
831 runnable.run();
832 return;
835 final Ref<Runnable> wrapper = new Ref<Runnable>();
836 wrapper.set(new Runnable() {
837 public void run() {
838 if (!StartupManagerEx.getInstanceEx(myProject).postStartupActivityPassed()) {
839 mySchedulesQueue.queue(new Update(runnable) { // should not remove previously schedules tasks
841 public void run() {
842 wrapper.get().run();
845 return;
847 runnable.run();
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);
875 @TestOnly
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() {
923 public void run() {
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() {
948 public void run() {
949 importer.set(new MavenProjectImporter(myProject,
950 myProjectsTree,
951 getFileToModuleMapping(modelsProvider),
952 projectsToImportWithChanges,
953 importModuleGroupsRequired,
954 modelsProvider,
955 getImportingSettings()));
956 postTasks.set(importer.get().importProject());
960 // called from wizard or ui
961 if (ApplicationManager.getApplication().isDispatchThread()) {
962 r.run();
964 else {
965 MavenUtil.runInBackground(myProject, ProjectBundle.message("maven.project.importing"), false, new MavenTask() {
966 public void run(MavenProgressIndicator indicator) throws MavenProcessCanceledException {
967 r.run();
969 }).waitFor();
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);
988 return result;
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);
997 return result;
1000 public MavenDomDependency addDependency(final MavenProject mavenProject, final MavenId id) {
1001 final MavenArtifact[] artifact = new MavenArtifact[1];
1003 try {
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) {
1011 return null;
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);
1032 return result;
1035 public void addManagerListener(Listener listener) {
1036 myManagerListeners.add(listener);
1039 public void addProjectsTreeListener(MavenProjectsTree.Listener listener) {
1040 myProjectsTreeDispatcher.addListener(listener);
1043 @TestOnly
1044 public void fireActivatedInTests() {
1045 fireActivated();
1048 private void fireActivated() {
1049 for (Listener each : myManagerListeners) {
1050 each.activated();
1054 private void fireScheduledImportsChanged() {
1055 for (Listener each : myManagerListeners) {
1056 each.scheduledImportsChanged();
1060 public interface Listener {
1061 void activated();
1063 void scheduledImportsChanged();