maven dependency management gutter support (override icons)
[fedora-idea.git] / plugins / maven / src / main / java / org / jetbrains / idea / maven / project / MavenProjectsManager.java
blob1a704e7b357e5fcd36b83a5252e8da0457c84048
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.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.*;
59 import java.io.File;
60 import java.io.IOException;
61 import java.util.*;
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) {
104 super(project);
107 public MavenProjectsManagerState getState() {
108 if (isInitialized()) {
109 applyTreeToState();
111 return myState;
114 public void loadState(MavenProjectsManagerState state) {
115 myState = state;
116 if (isInitialized()) {
117 applyStateToTree();
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();
138 @Override
139 public void initComponent() {
140 if (!isNormalProject()) return;
142 StartupManagerEx.getInstanceEx(myProject).registerStartupActivity(new Runnable() {
143 public void run() {
144 boolean wasMavenized = !myState.originalFiles.isEmpty();
145 if (!wasMavenized) return;
146 initMavenized();
151 private void initMavenized() {
152 doInit(false);
155 private void initNew(List<VirtualFile> files, List<String> explicitProfiles) {
156 myState.originalFiles = MavenUtil.collectPaths(files);
157 myState.activeProfiles = explicitProfiles;
158 doInit(true);
161 @TestOnly
162 public void initForTests() {
163 doInit(false);
166 private void doInit(final boolean isNew) {
167 if (isInitialized.getAndSet(true)) return;
169 initProjectsTree(!isNew);
171 initWorkers();
172 listenForSettingsChanges();
173 listenForProjectsTreeChanges();
175 MavenUtil.runWhenInitialized(myProject, new DumbAwareRunnable() {
176 public void run() {
177 if (!isUnitTestMode()) {
178 fireActivated();
179 listenForExternalChanges();
181 scheduleUpdateAllProjects(isNew);
186 private void initProjectsTree(boolean tryToLoadExisting) {
187 if (tryToLoadExisting) {
188 File file = getProjectsTreeFile();
189 try {
190 if (file.exists()) {
191 myProjectsTree = MavenProjectsTree.read(file);
194 catch (IOException e) {
195 MavenLog.LOG.info(e);
199 if (myProjectsTree == null) myProjectsTree = new MavenProjectsTree();
200 applyStateToTree();
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);
217 public void save() {
218 if (myProjectsTree != null) {
219 try {
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();
231 return file;
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"),
243 false,
244 myEmbeddersManager);
245 myResolvingProcessor = new MavenProjectsProcessor(myProject,
246 ProjectBundle.message("maven.resolving"),
247 true,
248 myEmbeddersManager);
249 myPluginsResolvingProcessor = new MavenProjectsProcessor(myProject,
250 ProjectBundle.message("maven.downloading.plugins"),
251 true,
252 myEmbeddersManager);
253 myFoldersResolvingProcessor = new MavenProjectsProcessor(myProject,
254 ProjectBundle.message("maven.updating.folders"),
255 true,
256 myEmbeddersManager);
257 myArtifactsDownloadingProcessor = new MavenProjectsProcessor(myProject,
258 ProjectBundle.message("maven.downloading"),
259 true,
260 myEmbeddersManager);
261 myPostProcessor = new MavenProjectsProcessor(myProject,
262 ProjectBundle.message("maven.post.processing"),
263 true,
264 myEmbeddersManager);
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() {
297 @Override
298 public void projectsIgnoredStateChanged(List<MavenProject> ignored, List<MavenProject> unignored, Object message) {
299 if (message instanceof MavenProjectImporter) return;
300 scheduleImport(false);
303 @Override
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;
342 return false;
345 @Override
346 public void projectResolved(Pair<MavenProject, MavenProjectChanges> projectWithChanges,
347 org.apache.maven.project.MavenProject nativeMavenProject,
348 Object message) {
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);
361 @Override
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() {
387 myWatcher.start();
390 @Override
391 public void projectClosed() {
392 if (!isInitialized.getAndSet(false)) return;
394 Disposer.dispose(mySchedulesQueue);
395 Disposer.dispose(myImportingQueue);
397 myWatcher.stop();
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());
413 @TestOnly
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) {
437 if (mavenized) {
438 m.setOption(getMavenizedModuleOptionName(), "true");
440 else {
441 m.clearOption(getMavenizedModuleOptionName());
446 private String getMavenizedModuleOptionName() {
447 return getComponentName() + ".isMavenModule";
450 @TestOnly
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);
459 else {
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);
544 @Nullable
545 public Module findModule(MavenProject project) {
546 if (!isInitialized()) return null;
547 return ProjectRootManager.getInstance(myProject).getFileIndex().getModuleForFile(project.getFile());
550 @NotNull
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) {
566 return virtualFile;
569 return 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);
624 return result;
627 @TestOnly
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() {
650 public void run() {
651 if (projects == null) {
652 myWatcher.scheduleUpdateAll(force, forceImport);
654 else {
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() {
663 public void run() {
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,
669 myProjectsTree,
670 getGeneralSettings(),
671 message));
677 @TestOnly
678 public void scheduleResolveInTests(Collection<MavenProject> projects) {
679 scheduleResolve(projects, false);
682 @TestOnly
683 public void scheduleResolveAllInTests() {
684 scheduleResolve(getProjects(), false);
687 public void scheduleFoldersResolving(final Collection<MavenProject> projects) {
688 runWhenFullyOpen(new Runnable() {
689 public void run() {
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(),
697 myProjectsTree,
698 message));
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() {
710 public void run() {
711 myPluginsResolvingProcessor.scheduleTask(new MavenProjectsProcessorPluginsResolvingTask(project,
712 nativeMavenProject,
713 myProjectsTree));
718 public void scheduleArtifactsDownloading(final Collection<MavenProject> projects, final boolean sources, final boolean docs) {
719 if (!sources && !docs) return;
721 runWhenFullyOpen(new Runnable() {
722 public void run() {
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() {
757 public void run() {
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()) {
761 public void run() {
762 if (autoImport || forceImport) {
763 myImportingQueue.activate();
765 else {
766 myImportingQueue.deactivate();
770 myImportingQueue.queue(new Update(MavenProjectsManager.this) {
771 public void run() {
772 importProjects();
773 if (!autoImport) myImportingQueue.deactivate();
776 if (!forceImport) fireScheduledImportsChanged();
781 @TestOnly
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() {
825 public void run() {
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()) {
838 runnable.run();
839 return;
842 final Ref<Runnable> wrapper = new Ref<Runnable>();
843 wrapper.set(new Runnable() {
844 public void run() {
845 if (!StartupManagerEx.getInstanceEx(myProject).postStartupActivityPassed()) {
846 mySchedulesQueue.queue(new Update(runnable) { // should not remove previously schedules tasks
848 public void run() {
849 wrapper.get().run();
852 return;
854 runnable.run();
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);
882 @TestOnly
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() {
930 public void run() {
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() {
955 public void run() {
956 importer.set(new MavenProjectImporter(myProject,
957 myProjectsTree,
958 getFileToModuleMapping(modelsProvider),
959 projectsToImportWithChanges,
960 importModuleGroupsRequired,
961 modelsProvider,
962 getImportingSettings()));
963 postTasks.set(importer.get().importProject());
967 // called from wizard or ui
968 if (ApplicationManager.getApplication().isDispatchThread()) {
969 r.run();
971 else {
972 MavenUtil.runInBackground(myProject, ProjectBundle.message("maven.project.importing"), false, new MavenTask() {
973 public void run(MavenProgressIndicator indicator) throws MavenProcessCanceledException {
974 r.run();
976 }).waitFor();
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);
995 return result;
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);
1004 return result;
1007 public MavenDomDependency addDependency(final MavenProject mavenProject, final MavenId id) {
1008 final MavenArtifact[] artifact = new MavenArtifact[1];
1010 try {
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) {
1018 return null;
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);
1039 return result;
1042 public void addManagerListener(Listener listener) {
1043 myManagerListeners.add(listener);
1046 public void addProjectsTreeListener(MavenProjectsTree.Listener listener) {
1047 myProjectsTreeDispatcher.addListener(listener);
1050 @TestOnly
1051 public void fireActivatedInTests() {
1052 fireActivated();
1055 private void fireActivated() {
1056 for (Listener each : myManagerListeners) {
1057 each.activated();
1061 private void fireScheduledImportsChanged() {
1062 for (Listener each : myManagerListeners) {
1063 each.scheduledImportsChanged();
1067 public interface Listener {
1068 void activated();
1070 void scheduledImportsChanged();