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
.openapi
.application
.ApplicationManager
;
19 import com
.intellij
.openapi
.util
.Comparing
;
20 import com
.intellij
.openapi
.util
.Computable
;
21 import com
.intellij
.openapi
.util
.Pair
;
22 import com
.intellij
.openapi
.util
.io
.FileUtil
;
23 import com
.intellij
.openapi
.vfs
.LocalFileSystem
;
24 import com
.intellij
.openapi
.vfs
.VirtualFile
;
25 import com
.intellij
.util
.Function
;
26 import com
.intellij
.util
.containers
.ArrayListSet
;
27 import com
.intellij
.util
.containers
.ContainerUtil
;
28 import com
.intellij
.util
.containers
.Stack
;
29 import gnu
.trove
.THashMap
;
30 import gnu
.trove
.THashSet
;
31 import org
.apache
.maven
.artifact
.Artifact
;
32 import org
.jetbrains
.annotations
.TestOnly
;
33 import org
.jetbrains
.idea
.maven
.embedder
.MavenConsole
;
34 import org
.jetbrains
.idea
.maven
.embedder
.MavenEmbedderWrapper
;
35 import org
.jetbrains
.idea
.maven
.utils
.*;
39 import java
.util
.concurrent
.locks
.Lock
;
40 import java
.util
.concurrent
.locks
.ReentrantReadWriteLock
;
41 import java
.util
.regex
.Pattern
;
43 public class MavenProjectsTree
{
44 private static final String STORAGE_VERSION
= MavenProjectsTree
.class.getSimpleName() + ".5";
46 private final Object myStateLock
= new Object();
47 private final ReentrantReadWriteLock myStructureLock
= new ReentrantReadWriteLock();
48 private final Lock myStructureReadLock
= myStructureLock
.readLock();
49 private final Lock myStructureWriteLock
= myStructureLock
.writeLock();
51 // TODO replace with sets
52 private volatile List
<String
> myManagedFilesPaths
= new ArrayList
<String
>();
53 private volatile List
<String
> myIgnoredFilesPaths
= new ArrayList
<String
>();
54 private volatile List
<String
> myIgnoredFilesPatterns
= new ArrayList
<String
>();
55 private volatile Pattern myIgnoredFilesPatternsCache
;
57 private volatile Set
<String
> myExplicitProfiles
= new THashSet
<String
>();
58 private volatile Set
<String
> myTemporarilyRemovedExplicitProfiles
= new THashSet
<String
>();
60 private final List
<MavenProject
> myRootProjects
= new ArrayList
<MavenProject
>();
62 private final Map
<MavenProject
, MavenProjectTimestamp
> myTimestamps
= new THashMap
<MavenProject
, MavenProjectTimestamp
>();
63 private final Map
<VirtualFile
, MavenProject
> myVirtualFileToProjectMapping
= new THashMap
<VirtualFile
, MavenProject
>();
64 private final Map
<MavenId
, MavenProject
> myMavenIdToProjectMapping
= new THashMap
<MavenId
, MavenProject
>();
65 private final Map
<MavenId
, VirtualFile
> myMavenIdToFileMapping
= new THashMap
<MavenId
, VirtualFile
>();
66 private final Map
<MavenProject
, List
<MavenProject
>> myAggregatorToModuleMapping
= new THashMap
<MavenProject
, List
<MavenProject
>>();
67 private final Map
<MavenProject
, MavenProject
> myModuleToAggregatorMapping
= new THashMap
<MavenProject
, MavenProject
>();
69 private final List
<Listener
> myListeners
= ContainerUtil
.createEmptyCOWList();
71 private final MavenProjectReaderProjectLocator myProjectLocator
= new MavenProjectReaderProjectLocator() {
72 public VirtualFile
findProjectFile(MavenId coordinates
) {
73 MavenProject project
= findProject(coordinates
);
74 return project
== null ?
null : project
.getFile();
78 public static MavenProjectsTree
read(File file
) throws IOException
{
79 FileInputStream fs
= new FileInputStream(file
);
80 DataInputStream in
= new DataInputStream(fs
);
82 MavenProjectsTree result
= new MavenProjectsTree();
85 if (!STORAGE_VERSION
.equals(in
.readUTF())) return null;
86 result
.myManagedFilesPaths
= readList(in
);
87 result
.myIgnoredFilesPaths
= readList(in
);
88 result
.myIgnoredFilesPatterns
= readList(in
);
89 result
.myExplicitProfiles
= readCollection(in
, new Function
<Integer
, Set
<String
>>() {
90 public Set
<String
> fun(Integer integer
) {
91 return new THashSet
<String
>(integer
);
94 result
.myRootProjects
.addAll(readProjectsRecursively(in
, result
));
97 IOException ioException
= new IOException();
98 ioException
.initCause(e
);
109 private static List
<String
> readList(DataInputStream in
) throws IOException
{
110 return readCollection(in
, new Function
<Integer
, List
<String
>>() {
111 public List
<String
> fun(Integer integer
) {
112 return new ArrayList
<String
>(integer
);
117 private static <T
extends Collection
<String
>> T
readCollection(DataInputStream in
, Function
<Integer
, T
> factory
) throws IOException
{
118 int count
= in
.readInt();
119 T result
= factory
.fun(count
);
120 while (count
-- > 0) {
121 result
.add(in
.readUTF());
126 private static List
<MavenProject
> readProjectsRecursively(DataInputStream in
,
127 MavenProjectsTree tree
) throws IOException
{
128 int count
= in
.readInt();
129 List
<MavenProject
> result
= new ArrayList
<MavenProject
>(count
);
130 while (count
-- > 0) {
131 MavenProject project
= MavenProject
.read(in
);
132 MavenProjectTimestamp timestamp
= MavenProjectTimestamp
.read(in
);
133 List
<MavenProject
> modules
= readProjectsRecursively(in
, tree
);
134 if (project
!= null) {
136 tree
.myTimestamps
.put(project
, timestamp
);
137 tree
.myVirtualFileToProjectMapping
.put(project
.getFile(), project
);
138 tree
.myMavenIdToProjectMapping
.put(project
.getMavenId(), project
);
139 tree
.myMavenIdToFileMapping
.put(project
.getMavenId(), project
.getFile());
140 tree
.myAggregatorToModuleMapping
.put(project
, modules
);
141 for (MavenProject eachModule
: modules
) {
142 tree
.myModuleToAggregatorMapping
.put(eachModule
, project
);
149 public void save(File file
) throws IOException
{
150 synchronized (myStateLock
) {
153 file
.getParentFile().mkdirs();
154 FileOutputStream fs
= new FileOutputStream(file
);
155 DataOutputStream out
= new DataOutputStream(fs
);
157 out
.writeUTF(STORAGE_VERSION
);
158 writeCollection(out
, myManagedFilesPaths
);
159 writeCollection(out
, myIgnoredFilesPaths
);
160 writeCollection(out
, myIgnoredFilesPatterns
);
161 writeCollection(out
, myExplicitProfiles
);
162 writeProjectsRecursively(out
, myRootProjects
);
175 private static void writeCollection(DataOutputStream out
, Collection
<String
> list
) throws IOException
{
176 out
.writeInt(list
.size());
177 for (String each
: list
) {
182 private void writeProjectsRecursively(DataOutputStream out
, List
<MavenProject
> list
) throws IOException
{
183 out
.writeInt(list
.size());
184 for (MavenProject each
: list
) {
186 myTimestamps
.get(each
).write(out
);
187 writeProjectsRecursively(out
, getModules(each
));
191 public List
<String
> getManagedFilesPaths() {
192 synchronized (myStateLock
) {
193 return new ArrayList
<String
>(myManagedFilesPaths
);
197 public void resetManagedFilesPathsAndProfiles(List
<String
> paths
, Collection
<String
> profiles
) {
198 synchronized (myStateLock
) {
199 myManagedFilesPaths
= new ArrayList
<String
>(paths
);
201 setExplicitProfiles(profiles
);
205 public void resetManagedFilesAndProfiles(List
<VirtualFile
> files
, Collection
<String
> profiles
) {
206 resetManagedFilesPathsAndProfiles(MavenUtil
.collectPaths(files
), profiles
);
209 public void addManagedFilesWithProfiles(List
<VirtualFile
> files
, Collection
<String
> profiles
) {
210 List
<String
> newFiles
;
211 Set
<String
> newProfiles
;
212 synchronized (myStateLock
) {
213 newFiles
= new ArrayList
<String
>(myManagedFilesPaths
);
214 newFiles
.addAll(MavenUtil
.collectPaths(files
));
216 newProfiles
= new THashSet
<String
>(myExplicitProfiles
);
217 newProfiles
.addAll(profiles
);
220 resetManagedFilesPathsAndProfiles(newFiles
, newProfiles
);
223 public void removeManagedFiles(List
<VirtualFile
> files
) {
224 synchronized (myStateLock
) {
225 myManagedFilesPaths
.removeAll(MavenUtil
.collectPaths(files
));
229 public List
<VirtualFile
> getExistingManagedFiles() {
230 List
<VirtualFile
> result
= new ArrayList
<VirtualFile
>();
231 for (String path
: getManagedFilesPaths()) {
232 VirtualFile f
= LocalFileSystem
.getInstance().findFileByPath(path
);
233 if (f
!= null) result
.add(f
);
238 public List
<String
> getIgnoredFilesPaths() {
239 synchronized (myStateLock
) {
240 return new ArrayList
<String
>(myIgnoredFilesPaths
);
244 public void setIgnoredFilesPaths(final List
<String
> paths
) {
245 doChangeIgnoreStatus(new Runnable() {
247 myIgnoredFilesPaths
= new ArrayList
<String
>(paths
);
252 public boolean getIgnoredState(MavenProject project
) {
253 synchronized (myStateLock
) {
254 return myIgnoredFilesPaths
.contains(project
.getPath());
258 public void setIgnoredState(List
<MavenProject
> projects
, boolean ignored
) {
259 setIgnoredState(projects
, ignored
, null);
262 public void setIgnoredState(List
<MavenProject
> projects
, boolean ignored
, Object message
) {
263 doSetIgnoredState(projects
, ignored
, message
);
266 private void doSetIgnoredState(List
<MavenProject
> projects
, final boolean ignored
, Object message
) {
267 final List
<String
> paths
= MavenUtil
.collectPaths(MavenUtil
.collectFiles(projects
));
268 doChangeIgnoreStatus(new Runnable() {
271 myIgnoredFilesPaths
.addAll(paths
);
274 myIgnoredFilesPaths
.removeAll(paths
);
280 public List
<String
> getIgnoredFilesPatterns() {
281 synchronized (myStateLock
) {
282 return new ArrayList
<String
>(myIgnoredFilesPatterns
);
286 public void setIgnoredFilesPatterns(final List
<String
> patterns
) {
287 doChangeIgnoreStatus(new Runnable() {
289 myIgnoredFilesPatternsCache
= null;
290 myIgnoredFilesPatterns
= new ArrayList
<String
>(patterns
);
295 private void doChangeIgnoreStatus(Runnable runnable
) {
296 doChangeIgnoreStatus(runnable
, null);
299 private void doChangeIgnoreStatus(Runnable runnable
, Object message
) {
300 List
<MavenProject
> ignoredBefore
;
301 List
<MavenProject
> ignoredAfter
;
303 synchronized (myStateLock
) {
304 ignoredBefore
= getIgnoredProjects();
306 ignoredAfter
= getIgnoredProjects();
309 List
<MavenProject
> ignored
= new ArrayList
<MavenProject
>(ignoredAfter
);
310 ignored
.removeAll(ignoredBefore
);
312 List
<MavenProject
> unignored
= new ArrayList
<MavenProject
>(ignoredBefore
);
313 unignored
.removeAll(ignoredAfter
);
315 if (ignored
.isEmpty() && unignored
.isEmpty()) return;
317 fireProjectsIgnoredStateChanged(ignored
, unignored
, message
);
320 private List
<MavenProject
> getIgnoredProjects() {
321 List
<MavenProject
> result
= new ArrayList
<MavenProject
>();
322 for (MavenProject each
: getProjects()) {
323 if (isIgnored(each
)) result
.add(each
);
328 public boolean isIgnored(MavenProject project
) {
329 String path
= project
.getPath();
330 synchronized (myStateLock
) {
331 return myIgnoredFilesPaths
.contains(path
) || matchesIgnoredFilesPatterns(path
);
335 private boolean matchesIgnoredFilesPatterns(String path
) {
336 synchronized (myStateLock
) {
337 if (myIgnoredFilesPatternsCache
== null) {
338 myIgnoredFilesPatternsCache
= Pattern
.compile(Strings
.translateMasks(myIgnoredFilesPatterns
));
340 return myIgnoredFilesPatternsCache
.matcher(path
).matches();
344 public Collection
<String
> getExplicitProfiles() {
345 synchronized (myStateLock
) {
346 return new THashSet
<String
>(myExplicitProfiles
);
350 public void setExplicitProfiles(Collection
<String
> explicitProfiles
) {
351 synchronized (myStateLock
) {
352 myExplicitProfiles
= new THashSet
<String
>(explicitProfiles
);
354 fireProfilesChanged();
357 private void updateExplicitProfiles() {
358 Collection
<String
> available
= getAvailableProfiles();
360 synchronized (myStateLock
) {
361 Collection
<String
> removedProfiles
= new THashSet
<String
>(myExplicitProfiles
);
362 removedProfiles
.removeAll(available
);
363 myTemporarilyRemovedExplicitProfiles
.addAll(removedProfiles
);
365 Collection
<String
> restoredProfiles
= new THashSet
<String
>(myTemporarilyRemovedExplicitProfiles
);
366 restoredProfiles
.retainAll(available
);
367 myTemporarilyRemovedExplicitProfiles
.removeAll(restoredProfiles
);
369 myExplicitProfiles
.removeAll(removedProfiles
);
370 myExplicitProfiles
.addAll(restoredProfiles
);
374 public Collection
<String
> getAvailableProfiles() {
375 return getAvailableAndActiveProfiles(true, false).first
;
378 private Pair
<Collection
<String
>, Collection
<String
>> getAvailableAndActiveProfiles(boolean includeAvailable
, boolean includeActive
) {
379 Collection
<String
> available
= includeAvailable ?
new THashSet
<String
>() : null;
380 Collection
<String
> active
= includeActive ?
new THashSet
<String
>() : null;
381 for (MavenProject each
: getProjects()) {
382 if (available
!= null) available
.addAll(each
.getProfilesIds());
383 if (active
!= null) active
.addAll(each
.getActiveProfilesIds());
385 return Pair
.create(available
, active
);
388 public Collection
<Pair
<String
, MavenProfileState
>> getProfilesWithStates() {
389 Collection
<Pair
<String
, MavenProfileState
>> result
= new ArrayListSet
<Pair
<String
, MavenProfileState
>>();
391 Pair
<Collection
<String
>, Collection
<String
>> profiles
= getAvailableAndActiveProfiles(true, true);
392 Collection
<String
> available
= profiles
.first
;
393 Collection
<String
> active
= profiles
.second
;
394 Collection
<String
> explicitProfiles
= getExplicitProfiles();
396 for (String each
: available
) {
397 MavenProfileState state
= MavenProfileState
.NONE
;
398 if (explicitProfiles
.contains(each
)) {
399 state
= MavenProfileState
.EXPLICIT
;
401 else if (active
.contains(each
)) state
= MavenProfileState
.IMPLICIT
;
402 result
.add(Pair
.create(each
, state
));
407 public void updateAll(boolean force
, MavenGeneralSettings generalSettings
, MavenProgressIndicator process
, Object message
) {
408 List
<VirtualFile
> managedFiles
= getExistingManagedFiles();
409 Collection
<String
> explicitProfiles
= getExplicitProfiles();
411 MavenProjectReader projectReader
= new MavenProjectReader();
412 update(managedFiles
, true, force
, explicitProfiles
, projectReader
, generalSettings
, process
, message
);
414 List
<VirtualFile
> obsoleteFiles
= getRootProjectsFiles();
415 obsoleteFiles
.removeAll(managedFiles
);
416 delete(projectReader
, obsoleteFiles
, explicitProfiles
, generalSettings
, process
, message
);
419 public void update(Collection
<VirtualFile
> files
,
421 MavenGeneralSettings generalSettings
,
422 MavenProgressIndicator process
,
424 update(files
, false, force
, getExplicitProfiles(), new MavenProjectReader(), generalSettings
, process
, message
);
427 private void update(Collection
<VirtualFile
> files
,
430 Collection
<String
> explicitProfiles
,
431 MavenProjectReader projectReader
,
432 MavenGeneralSettings generalSettings
,
433 MavenProgressIndicator process
,
435 if (files
.isEmpty()) return;
437 UpdateContext updateContext
= new UpdateContext();
438 Stack
<MavenProject
> updateStack
= new Stack
<MavenProject
>();
440 for (VirtualFile each
: files
) {
441 MavenProject mavenProject
= findProject(each
);
442 if (mavenProject
== null) {
443 doAdd(each
, recursive
, explicitProfiles
, updateContext
, updateStack
, projectReader
, generalSettings
, process
);
446 doUpdate(mavenProject
,
447 findAggregator(mavenProject
),
460 updateExplicitProfiles();
461 updateContext
.fireUpdatedIfNecessary(message
);
464 private void doAdd(final VirtualFile f
,
466 Collection
<String
> explicitProfiles
,
467 UpdateContext updateContext
,
468 Stack
<MavenProject
> updateStack
,
469 MavenProjectReader reader
,
470 MavenGeneralSettings generalSettings
,
471 MavenProgressIndicator process
) {
472 MavenProject newMavenProject
= new MavenProject(f
);
474 MavenProject intendedAggregator
= null;
475 for (MavenProject each
: getProjects()) {
476 if (each
.getExistingModuleFiles().contains(f
)) {
477 intendedAggregator
= each
;
482 doUpdate(newMavenProject
,
495 private void doUpdate(MavenProject mavenProject
,
496 MavenProject aggregator
,
500 Collection
<String
> explicitProfiles
,
501 UpdateContext updateContext
,
502 Stack
<MavenProject
> updateStack
,
503 MavenProjectReader reader
,
504 MavenGeneralSettings generalSettings
,
505 MavenProgressIndicator process
) {
506 if (updateStack
.contains(mavenProject
)) {
507 MavenLog
.LOG
.info("Recursion detected in " + mavenProject
.getFile());
510 updateStack
.push(mavenProject
);
512 process
.setText(ProjectBundle
.message("maven.reading.pom", mavenProject
.getPath()));
513 process
.setText2("");
515 List
<MavenProject
> prevModules
= getModules(mavenProject
);
516 Set
<MavenProject
> prevInheritors
= isNew
517 ?
new THashSet
<MavenProject
>()
518 : findInheritors(mavenProject
);
520 MavenProjectTimestamp timestamp
= calculateTimestamp(mavenProject
, explicitProfiles
, generalSettings
);
521 boolean isChanged
= force
|| !timestamp
.equals(myTimestamps
.get(mavenProject
));
523 MavenProjectChanges changes
= force ? MavenProjectChanges
.ALL
: MavenProjectChanges
.NONE
;
528 myMavenIdToProjectMapping
.remove(mavenProject
.getMavenId());
529 myMavenIdToFileMapping
.remove(mavenProject
.getMavenId());
535 MavenId oldParentId
= mavenProject
.getParentId();
536 changes
= changes
.mergedWith(mavenProject
.read(generalSettings
, explicitProfiles
, reader
, myProjectLocator
));
540 myVirtualFileToProjectMapping
.put(mavenProject
.getFile(), mavenProject
);
541 myMavenIdToProjectMapping
.put(mavenProject
.getMavenId(), mavenProject
);
542 myMavenIdToFileMapping
.put(mavenProject
.getMavenId(), mavenProject
.getFile());
548 if (!Comparing
.equal(oldParentId
, mavenProject
.getParentId())) {
549 // ensure timestamp reflects actual parent's timestamp
550 timestamp
= calculateTimestamp(mavenProject
, explicitProfiles
, generalSettings
);
552 myTimestamps
.put(mavenProject
, timestamp
);
555 boolean reconnected
= isNew
;
557 connect(aggregator
, mavenProject
);
560 reconnected
= reconnect(aggregator
, mavenProject
);
563 if (isChanged
|| reconnected
) {
564 updateContext
.update(mavenProject
, changes
);
567 List
<VirtualFile
> existingModuleFiles
= mavenProject
.getExistingModuleFiles();
568 List
<MavenProject
> modulesToRemove
= new ArrayList
<MavenProject
>();
569 List
<MavenProject
> modulesToBecomeRoots
= new ArrayList
<MavenProject
>();
571 for (MavenProject each
: prevModules
) {
572 VirtualFile moduleFile
= each
.getFile();
573 if (!existingModuleFiles
.contains(moduleFile
)) {
574 if (isManagedFile(moduleFile
)) {
575 modulesToBecomeRoots
.add(each
);
578 modulesToRemove
.add(each
);
582 for (MavenProject each
: modulesToRemove
) {
583 removeModule(mavenProject
, each
);
584 doDelete(mavenProject
, each
, updateContext
);
585 prevInheritors
.removeAll(updateContext
.deletedProjects
);
588 for (MavenProject each
: modulesToBecomeRoots
) {
589 if (reconnect(null, each
)) updateContext
.update(each
, MavenProjectChanges
.NONE
);
592 for (VirtualFile each
: existingModuleFiles
) {
593 MavenProject module
= findProject(each
);
594 boolean isNewModule
= module
== null;
596 module
= new MavenProject(each
);
599 MavenProject currentAggregator
= findAggregator(module
);
600 if (currentAggregator
!= null && currentAggregator
!= mavenProject
) {
601 MavenLog
.LOG
.info("Module " + each
+ " is already included into " + mavenProject
.getFile());
606 if (isChanged
|| isNewModule
|| recursive
) {
611 recursive ? force
: false, // do not force update modules if only this project was requested to be updated
620 if (reconnect(mavenProject
, module
)) {
621 updateContext
.update(module
, MavenProjectChanges
.NONE
);
626 Set
<MavenProject
> allInheritors
= findInheritors(mavenProject
);
627 allInheritors
.addAll(prevInheritors
);
628 for (MavenProject each
: allInheritors
) {
630 findAggregator(each
),
632 false, // no need to go recursively in case of inheritance, only when updating modules
645 private MavenProjectTimestamp
calculateTimestamp(final MavenProject mavenProject
,
646 final Collection
<String
> explicitProfiles
,
647 final MavenGeneralSettings generalSettings
) {
648 return ApplicationManager
.getApplication().runReadAction(new Computable
<MavenProjectTimestamp
>() {
649 public MavenProjectTimestamp
compute() {
650 long pomTimestamp
= getFileTimestamp(mavenProject
.getFile());
651 MavenProject parent
= findParent(mavenProject
);
652 long parentLastReadStamp
= parent
== null ?
-1 : parent
.getLastReadStamp();
653 VirtualFile profilesXmlFile
= mavenProject
.getProfilesXmlFile();
654 long profilesTimestamp
= getFileTimestamp(profilesXmlFile
);
656 long userSettingsTimestamp
= getFileTimestamp(generalSettings
.getEffectiveUserSettingsFile());
657 long globalSettingsTimestamp
= getFileTimestamp(generalSettings
.getEffectiveGlobalSettingsFile());
659 int profilesHashCode
= explicitProfiles
.hashCode();
661 return new MavenProjectTimestamp(pomTimestamp
,
664 userSettingsTimestamp
,
665 globalSettingsTimestamp
,
671 private long getFileTimestamp(VirtualFile file
) {
672 if (file
== null) return -1;
673 return file
.getTimeStamp();
676 public boolean isManagedFile(VirtualFile moduleFile
) {
677 return isManagedFile(moduleFile
.getPath());
680 public boolean isManagedFile(String path
) {
681 for (String each
: getManagedFilesPaths()) {
682 if (FileUtil
.pathsEqual(each
, path
)) return true;
687 public boolean isPotentialProject(String path
) {
688 if (isManagedFile(path
)) return true;
690 for (MavenProject each
: getProjects()) {
691 if (FileUtil
.pathsEqual(path
, each
.getPath())) return true;
692 if (each
.getModulePaths().contains(path
)) return true;
697 public void delete(List
<VirtualFile
> files
,
698 MavenGeneralSettings generalSettings
,
699 MavenProgressIndicator process
,
701 delete(new MavenProjectReader(), files
, getExplicitProfiles(), generalSettings
, process
, message
);
704 private void delete(MavenProjectReader projectReader
,
705 List
<VirtualFile
> files
,
706 Collection
<String
> explicitProfiles
,
707 MavenGeneralSettings generalSettings
,
708 MavenProgressIndicator process
,
710 if (files
.isEmpty()) return;
712 UpdateContext updateContext
= new UpdateContext();
713 Stack
<MavenProject
> updateStack
= new Stack
<MavenProject
>();
715 Set
<MavenProject
> inheritorsToUpdate
= new THashSet
<MavenProject
>();
716 for (VirtualFile each
: files
) {
717 MavenProject mavenProject
= findProject(each
);
718 if (mavenProject
== null) return;
720 inheritorsToUpdate
.addAll(findInheritors(mavenProject
));
721 doDelete(findAggregator(mavenProject
), mavenProject
, updateContext
);
723 inheritorsToUpdate
.removeAll(updateContext
.deletedProjects
);
725 for (MavenProject each
: inheritorsToUpdate
) {
726 doUpdate(each
, null, false, false, false, explicitProfiles
, updateContext
, updateStack
, projectReader
, generalSettings
, process
);
729 updateExplicitProfiles();
730 updateContext
.fireUpdatedIfNecessary(message
);
733 private void doDelete(MavenProject aggregator
, MavenProject project
, UpdateContext updateContext
) {
734 for (MavenProject each
: getModules(project
)) {
735 if (isManagedFile(each
.getPath())) {
736 if (reconnect(null, each
)) {
737 updateContext
.update(each
, MavenProjectChanges
.NONE
);
741 doDelete(project
, each
, updateContext
);
747 if (aggregator
!= null) {
748 removeModule(aggregator
, project
);
751 myRootProjects
.remove(project
);
753 myTimestamps
.remove(project
);
754 myVirtualFileToProjectMapping
.remove(project
.getFile());
755 myMavenIdToProjectMapping
.remove(project
.getMavenId());
756 myMavenIdToFileMapping
.remove(project
.getMavenId());
757 myAggregatorToModuleMapping
.remove(project
);
758 myModuleToAggregatorMapping
.remove(project
);
764 updateContext
.deleted(project
);
767 private void connect(MavenProject newAggregator
, MavenProject project
) {
770 if (newAggregator
!= null) {
771 addModule(newAggregator
, project
);
774 myRootProjects
.add(project
);
782 private boolean reconnect(MavenProject newAggregator
, MavenProject project
) {
783 MavenProject prevAggregator
= findAggregator(project
);
785 if (prevAggregator
== newAggregator
) return false;
789 if (prevAggregator
!= null) {
790 removeModule(prevAggregator
, project
);
793 myRootProjects
.remove(project
);
796 if (newAggregator
!= null) {
797 addModule(newAggregator
, project
);
800 myRootProjects
.add(project
);
810 public boolean hasProjects() {
813 return !myRootProjects
.isEmpty();
820 public List
<MavenProject
> getRootProjects() {
823 return new ArrayList
<MavenProject
>(myRootProjects
);
830 public List
<VirtualFile
> getRootProjectsFiles() {
831 return MavenUtil
.collectFiles(getRootProjects());
834 public List
<MavenProject
> getProjects() {
837 return new ArrayList
<MavenProject
>(myVirtualFileToProjectMapping
.values());
844 public List
<MavenProject
> getNonIgnoredProjects() {
847 List
<MavenProject
> result
= new ArrayList
<MavenProject
>();
848 for (MavenProject each
: myVirtualFileToProjectMapping
.values()) {
849 if (!isIgnored(each
)) result
.add(each
);
858 public List
<VirtualFile
> getProjectsFiles() {
861 return new ArrayList
<VirtualFile
>(myVirtualFileToProjectMapping
.keySet());
868 public MavenProject
findProject(VirtualFile f
) {
871 return myVirtualFileToProjectMapping
.get(f
);
878 public MavenProject
findProject(MavenId id
) {
881 return myMavenIdToProjectMapping
.get(id
);
888 public MavenProject
findProject(MavenArtifact artifact
) {
889 return findProject(artifact
.getMavenId());
892 public MavenProject
findProject(Artifact artifact
) {
893 return findProject(new MavenId(artifact
));
896 private Map
<MavenId
, VirtualFile
> getProjectIdToFileMapping() {
899 return new THashMap
<MavenId
, VirtualFile
>(myMavenIdToFileMapping
);
906 public MavenProject
findAggregator(MavenProject project
) {
909 return myModuleToAggregatorMapping
.get(project
);
916 public List
<MavenProject
> getModules(MavenProject aggregator
) {
919 List
<MavenProject
> modules
= myAggregatorToModuleMapping
.get(aggregator
);
920 return modules
== null
921 ? Collections
.<MavenProject
>emptyList()
922 : new ArrayList
<MavenProject
>(modules
);
929 private void addModule(MavenProject aggregator
, MavenProject module
) {
932 List
<MavenProject
> modules
= myAggregatorToModuleMapping
.get(aggregator
);
933 if (modules
== null) {
934 modules
= new ArrayList
<MavenProject
>();
935 myAggregatorToModuleMapping
.put(aggregator
, modules
);
939 myModuleToAggregatorMapping
.put(module
, aggregator
);
946 private void removeModule(MavenProject aggregator
, MavenProject module
) {
949 List
<MavenProject
> modules
= myAggregatorToModuleMapping
.get(aggregator
);
950 if (modules
== null) return;
951 modules
.remove(module
);
952 myModuleToAggregatorMapping
.remove(module
);
959 private MavenProject
findParent(MavenProject project
) {
960 return findProject(project
.getParentId());
963 public Set
<MavenProject
> findInheritors(MavenProject project
) {
964 Set
<MavenProject
> result
= new THashSet
<MavenProject
>();
965 MavenId id
= project
.getMavenId();
967 for (MavenProject each
: getProjects()) {
968 if (each
== project
) continue;
969 if (id
.equals(each
.getParentId())) result
.add(each
);
974 public List
<MavenProject
> getDependentProjects(MavenProject project
) {
975 MavenId projectId
= project
.getMavenId();
976 List
<MavenProject
> result
= new ArrayList
<MavenProject
>();
977 for (MavenProject eachProject
: getProjects()) {
978 if (eachProject
== project
) continue;
979 for (MavenArtifact eachDependency
: eachProject
.getDependencies()) {
980 if (eachDependency
.getMavenId().equals(projectId
)) {
981 result
.add(eachProject
);
989 public void resolve(MavenProject mavenProject
,
990 MavenGeneralSettings generalSettings
,
991 MavenEmbeddersManager embeddersManager
,
992 MavenConsole console
,
993 MavenProgressIndicator process
,
994 Object message
) throws MavenProcessCanceledException
{
995 MavenEmbedderWrapper embedder
= embeddersManager
.getEmbedder(MavenEmbeddersManager
.EmbedderKind
.FOR_DEPENDENCIES_RESOLVE
);
996 embedder
.customizeForResolve(getProjectIdToFileMapping(), console
, process
);
999 process
.checkCanceled();
1000 process
.setText(ProjectBundle
.message("maven.resolving.pom", mavenProject
.getDisplayName()));
1001 process
.setText2("");
1002 Pair
<MavenProjectChanges
, org
.apache
.maven
.project
.MavenProject
> resolveResult
= mavenProject
.resolve(generalSettings
,
1004 new MavenProjectReader(),
1007 fireProjectResolved(Pair
.create(mavenProject
, resolveResult
.first
), resolveResult
.second
, message
);
1010 embeddersManager
.release(embedder
);
1014 public void resolvePlugins(MavenProject mavenProject
,
1015 org
.apache
.maven
.project
.MavenProject nativeMavenProject
,
1016 MavenEmbeddersManager embeddersManager
,
1017 MavenConsole console
,
1018 MavenProgressIndicator process
) throws MavenProcessCanceledException
{
1019 MavenEmbedderWrapper embedder
= embeddersManager
.getEmbedder(MavenEmbeddersManager
.EmbedderKind
.FOR_PLUGINS_RESOLVE
);
1020 embedder
.customizeForResolve(console
, process
);
1021 embedder
.clearCachesFor(mavenProject
);
1024 for (MavenPlugin each
: mavenProject
.getDeclaredPlugins()) {
1025 process
.checkCanceled();
1026 process
.setText(ProjectBundle
.message("maven.downloading.pom.plugins", mavenProject
.getDisplayName()));
1027 embedder
.resolvePlugin(each
, nativeMavenProject
, false);
1029 firePluginsResolved(mavenProject
);
1032 embeddersManager
.release(embedder
);
1036 public void resolveFolders(final MavenProject mavenProject
,
1037 final MavenGeneralSettings generalSettings
,
1038 final MavenImportingSettings importingSettings
,
1039 final MavenEmbeddersManager embeddersManager
,
1040 final MavenConsole console
,
1041 final MavenProgressIndicator process
,
1042 final Object message
) throws MavenProcessCanceledException
{
1043 executeWithEmbedder(mavenProject
,
1045 MavenEmbeddersManager
.EmbedderKind
.FOR_FOLDERS_RESOLVE
,
1048 new EmbedderTask() {
1049 public void run(MavenEmbedderWrapper embedder
) throws MavenProcessCanceledException
{
1050 process
.checkCanceled();
1051 process
.setText(ProjectBundle
.message("maven.updating.folders.pom", mavenProject
.getDisplayName()));
1052 process
.setText2("");
1054 Pair
<Boolean
, MavenProjectChanges
> resolveResult
= mavenProject
.resolveFolders(embedder
,
1057 new MavenProjectReader(),
1059 if (resolveResult
.first
) {
1060 fireFoldersResolved(Pair
.create(mavenProject
, resolveResult
.second
), message
);
1066 public void downloadArtifacts(MavenProject mavenProject
,
1067 boolean downloadSources
,
1068 boolean downloadDocs
,
1069 MavenEmbeddersManager embeddersManager
,
1070 MavenConsole console
,
1071 MavenProgressIndicator process
) throws MavenProcessCanceledException
{
1072 MavenEmbedderWrapper embedder
= embeddersManager
.getEmbedder(MavenEmbeddersManager
.EmbedderKind
.FOR_DOWNLOAD
);
1073 embedder
.customizeForResolve(console
, process
);
1076 MavenArtifactDownloader
.download(this, Collections
.singletonList(mavenProject
), downloadSources
, downloadDocs
, embedder
, process
);
1077 fireArtifactsDownloaded(mavenProject
);
1080 embeddersManager
.release(embedder
);
1084 public MavenArtifact
downloadArtifact(MavenProject mavenProject
,
1086 MavenEmbeddersManager embeddersManager
,
1087 MavenConsole console
,
1088 MavenProgressIndicator process
) throws MavenProcessCanceledException
{
1089 MavenEmbedderWrapper embedder
= embeddersManager
.getEmbedder(MavenEmbeddersManager
.EmbedderKind
.FOR_DOWNLOAD
);
1090 embedder
.customizeForResolve(console
, process
);
1093 Artifact artifact
= embedder
.resolve(id
, MavenConstants
.TYPE_JAR
, null, mavenProject
.getRemoteRepositories());
1094 artifact
.setScope(Artifact
.SCOPE_COMPILE
);
1095 return new MavenArtifact(artifact
, mavenProject
.getLocalRepository());
1098 embeddersManager
.release(embedder
);
1102 public void executeWithEmbedder(MavenProject mavenProject
,
1103 MavenEmbeddersManager embeddersManager
,
1104 MavenEmbeddersManager
.EmbedderKind embedderKind
,
1105 MavenConsole console
,
1106 MavenProgressIndicator process
,
1107 EmbedderTask task
) throws MavenProcessCanceledException
{
1108 MavenEmbedderWrapper embedder
= embeddersManager
.getEmbedder(embedderKind
);
1109 embedder
.customizeForStrictResolve(getProjectIdToFileMapping(), console
, process
);
1110 embedder
.clearCachesFor(mavenProject
);
1115 embeddersManager
.release(embedder
);
1119 public <Result
> Result
visit(Visitor
<Result
> visitor
) {
1120 for (MavenProject each
: getRootProjects()) {
1121 if (visitor
.isDone()) break;
1122 doVisit(each
, visitor
);
1124 return visitor
.getResult();
1127 private <Result
> void doVisit(MavenProject project
, Visitor
<Result
> visitor
) {
1128 if (!visitor
.isDone() && visitor
.shouldVisit(project
)) {
1129 visitor
.visit(project
);
1130 for (MavenProject each
: getModules(project
)) {
1131 if (visitor
.isDone()) break;
1132 doVisit(each
, visitor
);
1134 visitor
.leave(project
);
1138 private void writeLock() {
1139 myStructureWriteLock
.lock();
1142 private void writeUnlock() {
1143 myStructureWriteLock
.unlock();
1146 private void readLock() {
1147 myStructureReadLock
.lock();
1150 private void readUnlock() {
1151 myStructureReadLock
.unlock();
1154 public void addListener(Listener l
) {
1158 private void fireProfilesChanged() {
1159 for (Listener each
: myListeners
) {
1160 each
.profilesChanged();
1164 private void fireProjectsIgnoredStateChanged(List
<MavenProject
> ignored
, List
<MavenProject
> unignored
, Object fromImport
) {
1165 for (Listener each
: myListeners
) {
1166 each
.projectsIgnoredStateChanged(ignored
, unignored
, fromImport
);
1170 private void fireProjectsUpdated(List
<Pair
<MavenProject
, MavenProjectChanges
>> updated
, List
<MavenProject
> deleted
, Object message
) {
1171 for (Listener each
: myListeners
) {
1172 each
.projectsUpdated(updated
, deleted
, message
);
1176 private void fireProjectResolved(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
,
1177 org
.apache
.maven
.project
.MavenProject nativeMavenProject
,
1179 for (Listener each
: myListeners
) {
1180 each
.projectResolved(projectWithChanges
, nativeMavenProject
, message
);
1184 private void firePluginsResolved(MavenProject project
) {
1185 for (Listener each
: myListeners
) {
1186 each
.pluginsResolved(project
);
1190 private void fireFoldersResolved(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
, Object message
) {
1191 for (Listener each
: myListeners
) {
1192 each
.foldersResolved(projectWithChanges
, message
);
1196 private void fireArtifactsDownloaded(MavenProject project
) {
1197 for (Listener each
: myListeners
) {
1198 each
.artifactsDownloaded(project
);
1202 private class UpdateContext
{
1203 public final Map
<MavenProject
, MavenProjectChanges
> updatedProjectsWithChanges
= new LinkedHashMap
<MavenProject
, MavenProjectChanges
>();
1204 public final Set
<MavenProject
> deletedProjects
= new LinkedHashSet
<MavenProject
>();
1206 public void update(MavenProject project
, MavenProjectChanges changes
) {
1207 deletedProjects
.remove(project
);
1208 updatedProjectsWithChanges
.put(project
, changes
.mergedWith(updatedProjectsWithChanges
.get(project
)));
1211 public void deleted(MavenProject project
) {
1212 updatedProjectsWithChanges
.remove(project
);
1213 deletedProjects
.add(project
);
1216 public void deleted(Collection
<MavenProject
> projects
) {
1217 for (MavenProject each
: projects
) {
1222 public void fireUpdatedIfNecessary(Object message
) {
1223 if (updatedProjectsWithChanges
.isEmpty() && deletedProjects
.isEmpty()) return;
1224 fireProjectsUpdated(updatedProjectsWithChanges
.isEmpty()
1225 ? Collections
.EMPTY_LIST
1226 : MavenUtil
.mapToList(updatedProjectsWithChanges
),
1227 deletedProjects
.isEmpty()
1228 ? Collections
.EMPTY_LIST
1229 : new ArrayList
<MavenProject
>(deletedProjects
),
1234 public interface EmbedderTask
{
1235 void run(MavenEmbedderWrapper embedder
) throws MavenProcessCanceledException
;
1238 public static abstract class Visitor
<Result
> {
1239 private Result result
;
1241 public boolean shouldVisit(MavenProject project
) {
1245 public abstract void visit(MavenProject project
);
1247 public void leave(MavenProject node
) {
1250 public void setResult(Result result
) {
1251 this.result
= result
;
1254 public Result
getResult() {
1258 public boolean isDone() {
1259 return result
!= null;
1263 public static abstract class SimpleVisitor
extends Visitor
<Object
> {
1266 private static class MavenProjectTimestamp
{
1267 private final long myPomTimestamp
;
1268 private final long myParentLastReadStamp
;
1269 private final long myProfilesTimestamp
;
1270 private final long myUserSettingsTimestamp
;
1271 private final long myGlobalSettingsTimestamp
;
1272 private final long myExplicitProfilesHashCode
;
1274 private MavenProjectTimestamp(long pomTimestamp
,
1275 long parentLastReadStamp
,
1276 long profilesTimestamp
,
1277 long userSettingsTimestamp
,
1278 long globalSettingsTimestamp
,
1279 long explicitProfilesHashCode
) {
1280 myPomTimestamp
= pomTimestamp
;
1281 myParentLastReadStamp
= parentLastReadStamp
;
1282 myProfilesTimestamp
= profilesTimestamp
;
1283 myUserSettingsTimestamp
= userSettingsTimestamp
;
1284 myGlobalSettingsTimestamp
= globalSettingsTimestamp
;
1285 myExplicitProfilesHashCode
= explicitProfilesHashCode
;
1288 public static MavenProjectTimestamp
read(DataInputStream in
) throws IOException
{
1289 return new MavenProjectTimestamp(in
.readLong(),
1297 public void write(DataOutputStream out
) throws IOException
{
1298 out
.writeLong(myPomTimestamp
);
1299 out
.writeLong(myParentLastReadStamp
);
1300 out
.writeLong(myProfilesTimestamp
);
1301 out
.writeLong(myUserSettingsTimestamp
);
1302 out
.writeLong(myGlobalSettingsTimestamp
);
1303 out
.writeLong(myExplicitProfilesHashCode
);
1307 public String
toString() {
1308 return "(" + myPomTimestamp
1309 + ":" + myParentLastReadStamp
1310 + ":" + myProfilesTimestamp
1311 + ":" + myUserSettingsTimestamp
1312 + ":" + myGlobalSettingsTimestamp
1313 + ":" + myExplicitProfilesHashCode
+ ")";
1317 public boolean equals(Object o
) {
1318 if (this == o
) return true;
1319 if (o
== null || getClass() != o
.getClass()) return false;
1321 MavenProjectTimestamp timestamp
= (MavenProjectTimestamp
)o
;
1323 if (myPomTimestamp
!= timestamp
.myPomTimestamp
) return false;
1324 if (myParentLastReadStamp
!= timestamp
.myParentLastReadStamp
) return false;
1325 if (myProfilesTimestamp
!= timestamp
.myProfilesTimestamp
) return false;
1326 if (myUserSettingsTimestamp
!= timestamp
.myUserSettingsTimestamp
) return false;
1327 if (myGlobalSettingsTimestamp
!= timestamp
.myGlobalSettingsTimestamp
) return false;
1328 if (myExplicitProfilesHashCode
!= timestamp
.myExplicitProfilesHashCode
) return false;
1334 public int hashCode() {
1336 result
= 31 * result
+ (int)(myPomTimestamp ^
(myPomTimestamp
>>> 32));
1337 result
= 31 * result
+ (int)(myParentLastReadStamp ^
(myParentLastReadStamp
>>> 32));
1338 result
= 31 * result
+ (int)(myProfilesTimestamp ^
(myProfilesTimestamp
>>> 32));
1339 result
= 31 * result
+ (int)(myUserSettingsTimestamp ^
(myUserSettingsTimestamp
>>> 32));
1340 result
= 31 * result
+ (int)(myGlobalSettingsTimestamp ^
(myGlobalSettingsTimestamp
>>> 32));
1341 result
= 31 * result
+ (int)(myExplicitProfilesHashCode ^
(myExplicitProfilesHashCode
>>> 32));
1346 public interface Listener
extends EventListener
{
1347 void profilesChanged();
1349 void projectsIgnoredStateChanged(List
<MavenProject
> ignored
, List
<MavenProject
> unignored
, Object message
);
1351 void projectsUpdated(List
<Pair
<MavenProject
, MavenProjectChanges
>> updated
, List
<MavenProject
> deleted
, Object message
);
1353 void projectResolved(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
,
1354 org
.apache
.maven
.project
.MavenProject nativeMavenProject
,
1357 void pluginsResolved(MavenProject project
);
1359 void foldersResolved(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
, Object message
);
1361 void artifactsDownloaded(MavenProject project
);
1364 public static class ListenerAdapter
implements Listener
{
1365 public void profilesChanged() {
1368 public void projectsIgnoredStateChanged(List
<MavenProject
> ignored
, List
<MavenProject
> unignored
, Object message
) {
1371 public void projectsUpdated(List
<Pair
<MavenProject
, MavenProjectChanges
>> updated
, List
<MavenProject
> deleted
, Object message
) {
1374 public void projectResolved(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
,
1375 org
.apache
.maven
.project
.MavenProject nativeMavenProject
,
1379 public void pluginsResolved(MavenProject project
) {
1382 public void foldersResolved(Pair
<MavenProject
, MavenProjectChanges
> projectWithChanges
, Object message
) {
1385 public void artifactsDownloaded(MavenProject project
) {