Issue #146852: accept Project in a constructor for SourcesHelper to permit registerExternalRoots to run synch. Can help simplify tests, and makes control flow easier to understand and debug. Also taking advantage of synchronous control flow to optimize class loading in the Eclipse importer. XXX to do: 1. Write tests to verify new constructor, and that LookupProvider's can call Project.getLookup for j2seproject. 2. Verify that j2seproject.classpath.SourcePathImplAddonsTest is "supposed" to fail. 3. Verify that the problem reported in #142938 is fixed. 4. Check to see if the new constructor should be used in: ant.freeform/src/org/netbeans/modules/ant/freeform/FreeformSources.java apisupport.project/src/org/netbeans/modules/apisupport/project/NbModuleProject.java bpel.project/src/org/netbeans/modules/bpel/project/BpelproProject.java cnd.makeproject/src/org/netbeans/modules/cnd/makeproject/MakeSources.java compapp.projects.base/src/org/netbeans/modules/compapp/projects/base/IcanproProject.java compapp.projects.jbi/src/org/netbeans/modules/compapp/projects/jbi/JbiProject.java etl.project/src/org/netbeans/modules/etl/project/EtlproProject.java iep.project/src/org/netbeans/modules/iep/project/IepProject.java j2ee.clientproject/src/org/netbeans/modules/j2ee/clientproject/AppClientProject.java j2ee.clientproject/src/org/netbeans/modules/j2ee/clientproject/AppClientSources.java j2ee.earproject/src/org/netbeans/modules/j2ee/earproject/EarProject.java j2ee.earproject/src/org/netbeans/modules/j2ee/earproject/EarSources.java j2ee.ejbjarproject/src/org/netbeans/modules/j2ee/ejbjarproject/EjbJarProject.java j2ee.ejbjarproject/src/org/netbeans/modules/j2ee/ejbjarproject/EjbJarSources.java java.api.common/test/unit/src/org/netbeans/modules/java/api/common/queries/GeneratedSourceRootTest.java mobility.project/src/org/netbeans/modules/mobility/project/J2MEProject.java php.project/src/org/netbeans/modules/php/project/PhpSources.java project.ant/test/unit/src/org/netbeans/spi/project/support/ant/SourcesHelperTest.java python.project/src/org/netbeans/modules/python/project/PythonSources.java ruby.merbproject/src/org/netbeans/modules/ruby/merbproject/MerbSources.java ruby.project/src/org/netbeans/modules/ruby/rubyproject/RubySources.java ruby.railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsSources.java sql.project/src/org/netbeans/modules/sql/project/IcanproProject.java sql.project/src/org/netbeans/modules/sql/project/SQLproProject.java web.project/src/org/netbeans/modules/web/project/WebSources.java xslt.project/src/org/netbeans/modules/xslt/project/XsltproProject.java diff --git a/java.j2seproject/nbproject/project.xml b/java.j2seproject/nbproject/project.xml --- a/java.j2seproject/nbproject/project.xml +++ b/java.j2seproject/nbproject/project.xml @@ -180,7 +180,7 @@ 1 - 1.28 + 1.31 diff --git a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java --- a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java +++ b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java @@ -156,7 +156,7 @@ private final PropertyEvaluator eval; private final ReferenceHelper refHelper; private final GeneratedFilesHelper genFilesHelper; - private final Lookup lookup; + private Lookup lookup; private final UpdateHelper updateHelper; private MainClassUpdater mainClassUpdater; private SourceRoots sourceRoots; @@ -313,7 +313,7 @@ UILookupMergerSupport.createProjectOpenHookMerger(new ProjectOpenedHookImpl()), QuerySupport.createUnitTestForSourceQuery(getSourceRoots(), getTestSourceRoots()), QuerySupport.createSourceLevelQuery(evaluator()), - new J2SESources (this.helper, evaluator(), getSourceRoots(), getTestSourceRoots()), + new J2SESources(this, helper, evaluator(), getSourceRoots(), getTestSourceRoots()), QuerySupport.createSharabilityQuery(helper, evaluator(), getSourceRoots(), getTestSourceRoots()), new CoSAwareFileBuiltQueryImpl(QuerySupport.createFileBuiltQuery(helper, evaluator(), getSourceRoots(), getTestSourceRoots()), this), new RecommendedTemplatesImpl (this.updateHelper), @@ -335,6 +335,7 @@ LookupMergerSupport.createJFBLookupMerger(), QuerySupport.createBinaryForSourceQueryImplementation(this.sourceRoots, this.testRoots, this.helper, this.eval) //Does not use APH to get/put properties/cfgdata ); + lookup = base; // in case LookupProvider's call Project.getLookup return LookupProviderSupport.createCompositeLookup(base, "Projects/org-netbeans-modules-java-j2seproject/Lookup"); //NOI18N } diff --git a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SESources.java b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SESources.java --- a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SESources.java +++ b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SESources.java @@ -53,6 +53,7 @@ import org.netbeans.api.project.ProjectManager; import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.java.project.JavaProjectConstants; +import org.netbeans.api.project.Project; import org.netbeans.modules.java.api.common.SourceRoots; import org.netbeans.modules.java.api.common.project.ProjectProperties; import org.netbeans.spi.project.support.GenericSources; @@ -72,20 +73,18 @@ private static final String BUILD_DIR_PROP = "${" + J2SEProjectProperties.BUILD_DIR + "}"; //NOI18N private static final String DIST_DIR_PROP = "${" + J2SEProjectProperties.DIST_DIR + "}"; //NOI18N + private final Project project; private final AntProjectHelper helper; private final PropertyEvaluator evaluator; private final SourceRoots sourceRoots; private final SourceRoots testRoots; private SourcesHelper sourcesHelper; private Sources delegate; - /** - * Flag to forbid multiple invocation of {@link SourcesHelper#registerExternalRoots} - **/ - private boolean externalRootsRegistered; private final ChangeSupport changeSupport = new ChangeSupport(this); - J2SESources(AntProjectHelper helper, PropertyEvaluator evaluator, + J2SESources(Project project, AntProjectHelper helper, PropertyEvaluator evaluator, SourceRoots sourceRoots, SourceRoots testRoots) { + this.project = project; this.helper = helper; this.evaluator = evaluator; this.sourceRoots = sourceRoots; @@ -152,20 +151,12 @@ } private Sources initSources() { - this.sourcesHelper = new SourcesHelper(helper, evaluator); //Safe to pass APH + this.sourcesHelper = new SourcesHelper(project, helper, evaluator); //Safe to pass APH register(sourceRoots); register(testRoots); this.sourcesHelper.addNonSourceRoot(BUILD_DIR_PROP); this.sourcesHelper.addNonSourceRoot(DIST_DIR_PROP); - externalRootsRegistered = false; - ProjectManager.mutex().postWriteRequest(new Runnable() { - public void run() { - if (!externalRootsRegistered) { - sourcesHelper.registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT, false); - externalRootsRegistered = true; - } - } - }); + sourcesHelper.registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT, false); return this.sourcesHelper.createSources(); } diff --git a/project.ant/apichanges.xml b/project.ant/apichanges.xml --- a/project.ant/apichanges.xml +++ b/project.ant/apichanges.xml @@ -104,6 +104,22 @@ + + + + Added SourcesHelper constructor accepting Project + + + + + +

+ The new constructor enables simplified control flow. +

+
+ + +
diff --git a/project.ant/manifest.mf b/project.ant/manifest.mf --- a/project.ant/manifest.mf +++ b/project.ant/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.project.ant/1 -OpenIDE-Module-Specification-Version: 1.30 +OpenIDE-Module-Specification-Version: 1.31 OpenIDE-Module-Layer: org/netbeans/modules/project/ant/resources/mf-layer.xml OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/project/ant/Bundle.properties OpenIDE-Module-Install: org/netbeans/modules/project/ant/AntProjectModule.class 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 @@ -74,6 +74,7 @@ import org.openide.filesystems.FileStateInvalidException; import org.openide.filesystems.FileUtil; import org.openide.util.ChangeSupport; +import org.openide.util.Parameters; import org.openide.util.WeakListeners; // XXX should perhaps be legal to call add* methods at any time (should update things) @@ -98,7 +99,7 @@ if (val == null) { return null; } - return project.resolveFile(val); + return aph.resolveFile(val); } public Collection getIncludeRoots(boolean minimalSubfolders) { File loc = getActualLocation(); @@ -292,7 +293,8 @@ } } - private final AntProjectHelper project; + private final AntProjectHelper aph; + private final Project project; private final PropertyEvaluator evaluator; private final List principalSourceRoots = new ArrayList(); private final List nonSourceRoots = new ArrayList(); @@ -312,11 +314,29 @@ /** * Create the helper object, initially configured to recognize only sources * contained inside the project directory. - * @param project an Ant project helper + * @param aph an Ant project helper * @param evaluator a way to evaluate Ant properties used to define source locations + * @deprecated Rather use {@link #SourcesHelper(Project, AntProjectHelper, PropertyEvaluator)}. */ - public SourcesHelper(AntProjectHelper project, PropertyEvaluator evaluator) { + @Deprecated + public SourcesHelper(AntProjectHelper aph, PropertyEvaluator evaluator) { + this.project = null; + this.aph = aph; + this.evaluator = evaluator; + } + + /** + * Create the helper object, initially configured to recognize only sources + * contained inside the project directory. + * @param project the project object (need not yet be registered in {@link ProjectManager}) + * @param aph an Ant project helper + * @param evaluator a way to evaluate Ant properties used to define source locations + * @since org.netbeans.modules.project.ant/1 1.31 + */ + public SourcesHelper(Project project, AntProjectHelper aph, PropertyEvaluator evaluator) { + Parameters.notNull("project", project); this.project = project; + this.aph = aph; this.evaluator = evaluator; } @@ -470,7 +490,7 @@ } private Project getProject() { - return AntBasedProjectFactorySingleton.getProjectFor(project); + return project != null ? project : AntBasedProjectFactorySingleton.getProjectFor(aph); } /** @@ -504,11 +524,14 @@ * {@link FileOwnerQuery#EXTERNAL_ALGORITHM_TRANSIENT}. *

*

- * You may not call this method inside the project's constructor, as - * it requires the actual project to exist and be registered in {@link ProjectManager}. - * Typically you would use {@link org.openide.util.Mutex#postWriteRequest} to run it + * If you used the old constructor form + * {@link #SourcesHelper(AntProjectHelper, PropertyEvaluator)} + * then you may not call this method inside the project's constructor, as + * it requires the actual project to exist and be registered in {@link ProjectManager}; + * in this case you could still use {@link org.openide.util.Mutex#postWriteRequest} to run it * later, if you were creating the helper in your constructor, since the project construction * normally occurs in read access. + * Better to use {@link #SourcesHelper(Project, AntProjectHelper, PropertyEvaluator)}. *

* @param algorithm an external root registration algorithm as per * {@link FileOwnerQuery#markExternalOwner} @@ -584,7 +607,7 @@ allRoots.addAll(nonSourceRoots); allRoots.addAll(ownedFiles); Project p = getProject(); - FileObject pdir = project.getProjectDirectory(); + FileObject pdir = aph.getProjectDirectory(); // First time: register roots and add to lastRegisteredRoots. // Subsequent times: add to newRootsToRegister and maybe add them later. if (lastRegisteredRoots == null) { diff --git a/projectapi/src/org/netbeans/modules/projectapi/AuxiliaryConfigBasedPreferencesProvider.java b/projectapi/src/org/netbeans/modules/projectapi/AuxiliaryConfigBasedPreferencesProvider.java --- a/projectapi/src/org/netbeans/modules/projectapi/AuxiliaryConfigBasedPreferencesProvider.java +++ b/projectapi/src/org/netbeans/modules/projectapi/AuxiliaryConfigBasedPreferencesProvider.java @@ -95,6 +95,7 @@ } AuxiliaryConfiguration ac = ProjectUtils.getAuxiliaryConfiguration(p); + assert p.getLookup() != null : p; AuxiliaryProperties ap = p.getLookup().lookup(AuxiliaryProperties.class); target.put(p, new WeakReference(prov = new AuxiliaryConfigBasedPreferencesProvider(p, ac, ap, shared))); diff --git a/projectimport.eclipse.core/src/org/netbeans/modules/projectimport/eclipse/core/ProjectOpenHookImpl.java b/projectimport.eclipse.core/src/org/netbeans/modules/projectimport/eclipse/core/ProjectOpenHookImpl.java --- a/projectimport.eclipse.core/src/org/netbeans/modules/projectimport/eclipse/core/ProjectOpenHookImpl.java +++ b/projectimport.eclipse.core/src/org/netbeans/modules/projectimport/eclipse/core/ProjectOpenHookImpl.java @@ -40,31 +40,17 @@ package org.netbeans.modules.projectimport.eclipse.core; import java.util.concurrent.ExecutionException; -import java.util.logging.Logger; -import org.netbeans.api.project.Project; import org.netbeans.api.project.ui.OpenProjects; import org.netbeans.spi.project.ui.ProjectOpenedHook; import org.openide.util.Exceptions; import org.openide.util.RequestProcessor; -/** - * - */ public class ProjectOpenHookImpl extends ProjectOpenedHook{ private static final RequestProcessor PROJ_OPEN_HOOK_RESYNCHRONIZER = new RequestProcessor("Eclipse.Resynchronizer"); // NOI18N private static RequestProcessor.Task currentTask; - private UpgradableProject upgradable; - private Project project; - - private static final Logger LOG = - Logger.getLogger(ProjectOpenHookImpl.class.getName()); - - public ProjectOpenHookImpl(Project project, UpgradableProject upgradable) { - this.upgradable = upgradable; - this.project = project; - } + public ProjectOpenHookImpl() {} @Override protected synchronized void projectOpened() { diff --git a/projectimport.eclipse.core/src/org/netbeans/modules/projectimport/eclipse/core/spi/UpgradableProjectLookupProvider.java b/projectimport.eclipse.core/src/org/netbeans/modules/projectimport/eclipse/core/spi/UpgradableProjectLookupProvider.java --- a/projectimport.eclipse.core/src/org/netbeans/modules/projectimport/eclipse/core/spi/UpgradableProjectLookupProvider.java +++ b/projectimport.eclipse.core/src/org/netbeans/modules/projectimport/eclipse/core/spi/UpgradableProjectLookupProvider.java @@ -40,22 +40,33 @@ package org.netbeans.modules.projectimport.eclipse.core.spi; import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; import org.netbeans.modules.projectimport.eclipse.core.ProjectOpenHookImpl; import org.netbeans.modules.projectimport.eclipse.core.UpgradableProject; import org.netbeans.spi.project.LookupProvider; import org.openide.util.Lookup; import org.openide.util.lookup.Lookups; -// registered separately in j2se and web modules, but could use @LookupProvider.Registration +// registered separately in j2se and web modules, otherwise could use @LookupProvider.Registration final public class UpgradableProjectLookupProvider implements LookupProvider { public Lookup createAdditionalLookup(Lookup baseContext) { Project p = baseContext.lookup(Project.class); assert p != null; - UpgradableProject up = new UpgradableProject(p); + if (ProjectUtils.getPreferences(p, UpgradableProjectLookupProvider.class, true). + get("project", null) == null) { // NOI18N + // Shortcut, the normal case: + return Lookup.EMPTY; + } else { + // Keep as separate method to try to delay class initialization: + return upgradeLookup(p); + } + } + + private static Lookup upgradeLookup(Project p) { return Lookups.fixed( - up, - new ProjectOpenHookImpl(p, up)); + new UpgradableProject(p), + new ProjectOpenHookImpl()); } } diff --git a/projectimport.eclipse.core/test/unit/src/org/netbeans/modules/projectimport/eclipse/core/spi/ProjectFactorySupportTest.java b/projectimport.eclipse.core/test/unit/src/org/netbeans/modules/projectimport/eclipse/core/spi/ProjectFactorySupportTest.java --- a/projectimport.eclipse.core/test/unit/src/org/netbeans/modules/projectimport/eclipse/core/spi/ProjectFactorySupportTest.java +++ b/projectimport.eclipse.core/test/unit/src/org/netbeans/modules/projectimport/eclipse/core/spi/ProjectFactorySupportTest.java @@ -46,7 +46,6 @@ import java.util.Collections; import java.util.List; import org.netbeans.api.java.platform.JavaPlatform; -import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectManager; import org.netbeans.api.project.ProjectUtils; @@ -225,14 +224,6 @@ model.getEclipseTestSourceRootsAsFileArray(), null, null, null); J2SEProject p = (J2SEProject)ProjectManager.getDefault().findProject(helper.getProjectDirectory()); List importProblems = new ArrayList(); - - // - // NB-Core-Build #1293: "No project found to correspond to .../spcp/eclipse/src" from ProjectClassPathModifier.findExtensible - // - // Looks like J2SEProject registers its external source roots asynchronously and sometimes - // it is too late and above problem happens. Mark external source roots explicitly here: - FileOwnerQuery.markExternalOwner(model.getEclipseSourceRootsAsFileArray()[0].toURI(), p, FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT); - ProjectFactorySupport.updateProjectClassPath(helper, p.getReferenceHelper(), model, importProblems); EditableProperties ep = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); assertEquals( @@ -262,14 +253,6 @@ model.getEclipseTestSourceRootsAsFileArray(), null, null, null); J2SEProject p = (J2SEProject)ProjectManager.getDefault().findProject(helper.getProjectDirectory()); List importProblems = new ArrayList(); - - // - // NB-Core-Build #1293: "No project found to correspond to .../spcp/eclipse/src" from ProjectClassPathModifier.findExtensible - // - // Looks like J2SEProject registers its external source roots asynchronously and sometimes - // it is too late and above problem happens. Mark external source roots explicitly here: - FileOwnerQuery.markExternalOwner(model.getEclipseSourceRootsAsFileArray()[0].toURI(), p, FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT); - ProjectFactorySupport.updateProjectClassPath(helper, p.getReferenceHelper(), model, importProblems); EditableProperties ep = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); assertEquals( @@ -355,14 +338,6 @@ model.getEclipseTestSourceRootsAsFileArray(), null, null, null); J2SEProject p = (J2SEProject)ProjectManager.getDefault().findProject(helper.getProjectDirectory()); List importProblems = new ArrayList(); - - // - // NB-Core-Build #1293: "No project found to correspond to .../spcp/eclipse/src" from ProjectClassPathModifier.findExtensible - // - // Looks like J2SEProject registers its external source roots asynchronously and sometimes - // it is too late and above problem happens. Mark external source roots explicitly here: - FileOwnerQuery.markExternalOwner(model.getEclipseSourceRootsAsFileArray()[0].toURI(), p, FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT); - ProjectFactorySupport.updateProjectClassPath(helper, p.getReferenceHelper(), model, importProblems); EditableProperties ep = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); // required project "JavaLibrary1" is not available and therefore should not be @@ -411,14 +386,6 @@ mdl_d.getEclipseTestSourceRootsAsFileArray(), null, null, null); List problems = new ArrayList(); J2SEProject j2seprj_d = (J2SEProject) ProjectManager.getDefault().findProject(aph_d.getProjectDirectory()); - - // - // NB-Core-Build #1293: "No project found to correspond to .../spcp/eclipse/src" from ProjectClassPathModifier.findExtensible - // - // Looks like J2SEProject registers its external source roots asynchronously and sometimes - // it is too late and above problem happens. Mark external source roots explicitly here: - FileOwnerQuery.markExternalOwner(mdl_d.getEclipseSourceRootsAsFileArray()[0].toURI(), j2seprj_d, FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT); - ProjectFactorySupport.updateProjectClassPath(aph_d, j2seprj_d.getReferenceHelper(), mdl_d, problems); assertEquals(Collections.emptyList(), problems); assertEquals("${reference.c.jar}:${reference.b.jar}", aph_d.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH).get("javac.classpath")); diff --git a/web.project/src/org/netbeans/modules/web/project/WebProject.java b/web.project/src/org/netbeans/modules/web/project/WebProject.java --- a/web.project/src/org/netbeans/modules/web/project/WebProject.java +++ b/web.project/src/org/netbeans/modules/web/project/WebProject.java @@ -185,7 +185,7 @@ private final PropertyEvaluator eval; private final ReferenceHelper refHelper; private final GeneratedFilesHelper genFilesHelper; - private final Lookup lookup; + private Lookup lookup; private final ProjectWebModule webModule; private final CopyOnSaveSupport css; private final ArtifactCopyOnSaveSupport artifactSupport; @@ -529,6 +529,7 @@ LookupMergerSupport.createJFBLookupMerger(), QuerySupport.createBinaryForSourceQueryImplementation(sourceRoots, testRoots, helper, eval), }); + lookup = base; return LookupProviderSupport.createCompositeLookup(base, "Projects/org-netbeans-modules-web-project/Lookup"); //NOI18N }