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