diff --git a/ant.freeform/src/org/netbeans/modules/ant/freeform/FreeformSources.java b/ant.freeform/src/org/netbeans/modules/ant/freeform/FreeformSources.java --- a/ant.freeform/src/org/netbeans/modules/ant/freeform/FreeformSources.java +++ b/ant.freeform/src/org/netbeans/modules/ant/freeform/FreeformSources.java @@ -68,6 +68,7 @@ public FreeformSources(FreeformProject project) { this.project = project; project.helper().addAntProjectListener(this); + initSources(); // have to register external build roots eagerly } private Sources delegate; @@ -120,6 +121,11 @@ } } } + ProjectManager.mutex().postWriteRequest(new Runnable() { + public void run() { + h.registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT); + } + }); return h.createSources(); } @@ -142,7 +148,7 @@ protected void projectOpened() { getSourceGroups(TYPE_GENERIC); - h.registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT); + h.registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_CONFIRMED); } protected void projectClosed() {} diff --git a/project.ant/src/org/netbeans/spi/project/support/ant/SourcesHelper.java b/project.ant/src/org/netbeans/spi/project/support/ant/SourcesHelper.java --- a/project.ant/src/org/netbeans/spi/project/support/ant/SourcesHelper.java +++ b/project.ant/src/org/netbeans/spi/project/support/ant/SourcesHelper.java @@ -298,7 +298,7 @@ private final List nonSourceRoots = new ArrayList(); private final List ownedFiles = new ArrayList(); private final List typedSourceRoots = new ArrayList(); - private int registeredRootAlgorithm; + private int registeredRootAlgorithm = -1; private boolean minimalSubfolders; /** * If not null, external roots that we registered the last time. @@ -567,13 +567,14 @@ * otherwise the whole source root is registered. * @throws IllegalArgumentException if the algorithm is unrecognized * @throws IllegalStateException if this method is called more than once on a - * given SourcesHelper object + * given SourcesHelper object with the same algorithm * @since 1.26 */ public void registerExternalRoots (int algorithm, boolean minimalSubfolders) throws IllegalArgumentException, IllegalStateException { - if (lastRegisteredRoots != null) { - throw new IllegalStateException("registerExternalRoots was already called before"); // NOI18N + if (lastRegisteredRoots != null && algorithm == registeredRootAlgorithm) { + throw new IllegalStateException("registerExternalRoots was already called before using " + algorithm); // NOI18N } + lastRegisteredRoots = null; registeredRootAlgorithm = algorithm; this.minimalSubfolders = minimalSubfolders; remarkExternalRoots(); diff --git a/projectapi/src/org/netbeans/api/project/FileOwnerQuery.java b/projectapi/src/org/netbeans/api/project/FileOwnerQuery.java --- a/projectapi/src/org/netbeans/api/project/FileOwnerQuery.java +++ b/projectapi/src/org/netbeans/api/project/FileOwnerQuery.java @@ -168,6 +168,12 @@ * The external marking may be persisted across VM sessions, despite the name. */ public static final int EXTERNAL_ALGORITHM_TRANSIENT = 0; + + /** + * Takes precedence over {@link #EXTERNAL_ALGORITHM_TRANSIENT} in case of conflict. + * @since XXX + */ + public static final int EXTERNAL_ALGORITHM_CONFIRMED = 1; /** * Mark an external folder or file as being owned by a particular project. @@ -199,7 +205,10 @@ switch (algorithm) { case EXTERNAL_ALGORITHM_TRANSIENT: // XXX check args - SimpleFileOwnerQueryImplementation.markExternalOwnerTransient(root, owner); + SimpleFileOwnerQueryImplementation.markExternalOwnerTransient(root, owner, false); + break; + case EXTERNAL_ALGORITHM_CONFIRMED: + SimpleFileOwnerQueryImplementation.markExternalOwnerTransient(root, owner, true); break; default: throw new IllegalArgumentException("No such algorithm: " + algorithm); // NOI18N @@ -236,7 +245,10 @@ switch (algorithm) { case EXTERNAL_ALGORITHM_TRANSIENT: // XXX check args - SimpleFileOwnerQueryImplementation.markExternalOwnerTransient(root, owner); + SimpleFileOwnerQueryImplementation.markExternalOwnerTransient(root, owner, false); + break; + case EXTERNAL_ALGORITHM_CONFIRMED: + SimpleFileOwnerQueryImplementation.markExternalOwnerTransient(root, owner, true); break; default: throw new IllegalArgumentException("No such algorithm: " + algorithm); // NOI18N diff --git a/projectapi/src/org/netbeans/modules/projectapi/SimpleFileOwnerQueryImplementation.java b/projectapi/src/org/netbeans/modules/projectapi/SimpleFileOwnerQueryImplementation.java --- a/projectapi/src/org/netbeans/modules/projectapi/SimpleFileOwnerQueryImplementation.java +++ b/projectapi/src/org/netbeans/modules/projectapi/SimpleFileOwnerQueryImplementation.java @@ -187,12 +187,20 @@ } return null; } + + private static class ConfirmableReference extends WeakReference { + final boolean confirmed; + ConfirmableReference(FileObject referent, boolean confirmed) { + super(referent); + this.confirmed = confirmed; + } + } /** * Map from external source roots to the owning project directories. */ - private static final Map> externalOwners = - Collections.synchronizedMap(new WeakHashMap>()); + private static final Map externalOwners = + Collections.synchronizedMap(new WeakHashMap()); private static final Map deserializedExternalOwners = Collections.synchronizedMap(new HashMap()); @@ -246,16 +254,22 @@ } /** @see FileOwnerQuery#markExternalOwner */ - public static void markExternalOwnerTransient(FileObject root, Project owner) { - markExternalOwnerTransient(fileObject2URI(root), owner); + public static void markExternalOwnerTransient(FileObject root, Project owner, boolean confirmed) { + markExternalOwnerTransient(fileObject2URI(root), owner, confirmed); } /** @see FileOwnerQuery#markExternalOwner */ - public static void markExternalOwnerTransient(URI root, Project owner) { + public static void markExternalOwnerTransient(URI root, Project owner, boolean confirmed) { externalRootsIncludeNonFolders |= !root.getPath().endsWith("/"); if (owner != null) { FileObject fo = owner.getProjectDirectory(); - externalOwners.put(root, new WeakReference(fo)); + if (!confirmed) { + ConfirmableReference old = externalOwners.get(root); + if (old != null && old.confirmed && old.get() != null) { + return; + } + } + externalOwners.put(root, new ConfirmableReference(fo, confirmed)); deserializedExternalOwners.remove(root); synchronized (project2External) { FileObject prjDir = owner.getProjectDirectory();