### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core.tests.model Index: src/org/eclipse/jdt/core/tests/model/ClasspathInitializerTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathInitializerTests.java,v retrieving revision 1.54 diff -u -r1.54 ClasspathInitializerTests.java --- src/org/eclipse/jdt/core/tests/model/ClasspathInitializerTests.java 25 Sep 2007 15:33:37 -0000 1.54 +++ src/org/eclipse/jdt/core/tests/model/ClasspathInitializerTests.java 11 Oct 2007 10:47:13 -0000 @@ -781,7 +781,7 @@ ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P2", "/P1/lib.jar", "P3", "/P1/lib.jar"}) { public void initialize(IPath containerPath, IJavaProject project) throws CoreException { // simulate concurrency (another thread is initializing all containers in parallel and thus this flag is set to true) - JavaModelManager.getJavaModelManager().batchContainerInitializations = true; + JavaModelManager.getJavaModelManager().batchContainerInitializations = JavaModelManager.NEED_BATCH_INITIALIZATION; super.initialize(containerPath, project); } }); #P org.eclipse.jdt.core Index: model/org/eclipse/jdt/internal/core/JavaModelOperation.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java,v retrieving revision 1.68 diff -u -r1.68 JavaModelOperation.java --- model/org/eclipse/jdt/internal/core/JavaModelOperation.java 28 Aug 2007 10:03:39 -0000 1.68 +++ model/org/eclipse/jdt/internal/core/JavaModelOperation.java 11 Oct 2007 10:47:16 -0000 @@ -714,7 +714,7 @@ if (canModifyRoots()) { // computes the root infos before executing the operation // noop if aready initialized - JavaModelManager.getDeltaState().initializeRoots(); + JavaModelManager.getDeltaState().initializeRoots(false/*not initiAfterLoad*/); } executeOperation(); Index: model/org/eclipse/jdt/internal/core/JavaModelManager.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java,v retrieving revision 1.378 diff -u -r1.378 JavaModelManager.java --- model/org/eclipse/jdt/internal/core/JavaModelManager.java 21 Sep 2007 13:16:47 -0000 1.378 +++ model/org/eclipse/jdt/internal/core/JavaModelManager.java 11 Oct 2007 10:47:16 -0000 @@ -100,8 +100,14 @@ public HashMap containers = new HashMap(5); public HashMap previousSessionContainers = new HashMap(5); private ThreadLocal containerInitializationInProgress = new ThreadLocal(); - public boolean batchContainerInitializations = false; - public ThreadLocal batchContainerInitializationsProgress = new ThreadLocal(); + + public static final int NO_BATCH_INITIALIZATION = 0; + public static final int NEED_BATCH_INITIALIZATION = 1; + public static final int BATCH_INITIALIZATION_IN_PROGRESS = 2; + public static final int BATCH_INITIALIZATION_FINISHED = 3; + public int batchContainerInitializations = NO_BATCH_INITIALIZATION; + + public BatchInitializationMonitor batchContainerInitializationsProgress = new BatchInitializationMonitor(); public HashMap containerInitializersCache = new HashMap(5); /* @@ -1566,14 +1572,39 @@ } } + /* + * Returns true if forcing batch initialization was successful. + * Returns false if batch initialization is already running. + */ + public synchronized boolean forceBatchInitializations(boolean initAfterLoad) { + switch (this.batchContainerInitializations) { + case NO_BATCH_INITIALIZATION: + this.batchContainerInitializations = NEED_BATCH_INITIALIZATION; + return true; + case BATCH_INITIALIZATION_FINISHED: + if (initAfterLoad) + return false; // no need to initialize again + this.batchContainerInitializations = NEED_BATCH_INITIALIZATION; + return true; + } + return false; + } + private synchronized boolean batchContainerInitializations() { - if (this.batchContainerInitializations) { - this.batchContainerInitializations = false; + switch (this.batchContainerInitializations) { + case NEED_BATCH_INITIALIZATION: + this.batchContainerInitializations = BATCH_INITIALIZATION_IN_PROGRESS; + return true; + case BATCH_INITIALIZATION_IN_PROGRESS: return true; } return false; } + private synchronized void batchInitializationFinished() { + this.batchContainerInitializations = BATCH_INITIALIZATION_FINISHED; + } + public IClasspathContainer getClasspathContainer(final IPath containerPath, final IJavaProject project) throws JavaModelException { IClasspathContainer container = containerGet(project, containerPath); @@ -1582,7 +1613,11 @@ if (batchContainerInitializations()) { // avoid deep recursion while initializaing container on workspace restart // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=60437) - container = initializeAllContainers(project, containerPath); + try { + container = initializeAllContainers(project, containerPath); + } finally { + batchInitializationFinished(); + } } else { container = initializeContainer(project, containerPath); } @@ -2199,7 +2234,7 @@ } } }; - IProgressMonitor monitor = (IProgressMonitor) this.batchContainerInitializationsProgress.get(); + IProgressMonitor monitor = this.batchContainerInitializationsProgress; IWorkspace workspace = ResourcesPlugin.getWorkspace(); if (workspace.isTreeLocked()) runnable.run(monitor); @@ -2234,7 +2269,7 @@ IClasspathContainer initializeContainer(IJavaProject project, IPath containerPath) throws JavaModelException { - IProgressMonitor monitor = (IProgressMonitor) this.batchContainerInitializationsProgress.get(); + IProgressMonitor monitor = this.batchContainerInitializationsProgress; if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException(); Index: model/org/eclipse/jdt/internal/core/DeltaProcessor.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java,v retrieving revision 1.305 diff -u -r1.305 DeltaProcessor.java --- model/org/eclipse/jdt/internal/core/DeltaProcessor.java 27 Sep 2007 16:33:52 -0000 1.305 +++ model/org/eclipse/jdt/internal/core/DeltaProcessor.java 11 Oct 2007 10:47:15 -0000 @@ -339,7 +339,7 @@ JavaProject javaProject = (JavaProject)JavaCore.create(project); switch (delta.getKind()) { case IResourceDelta.ADDED : - this.manager.batchContainerInitializations = true; + this.manager.forceBatchInitializations(false/*not initAfterLoad*/); // remember project and its dependents addToRootsToRefreshWithDependents(javaProject); @@ -357,7 +357,7 @@ case IResourceDelta.CHANGED : if ((delta.getFlags() & IResourceDelta.OPEN) != 0) { - this.manager.batchContainerInitializations = true; + this.manager.forceBatchInitializations(false/*not initAfterLoad*/); // project opened or closed: remember project and its dependents addToRootsToRefreshWithDependents(javaProject); @@ -385,7 +385,7 @@ boolean wasJavaProject = this.state.findJavaProject(project.getName()) != null; boolean isJavaProject = JavaProject.hasJavaNature(project); if (wasJavaProject != isJavaProject) { - this.manager.batchContainerInitializations = true; + this.manager.forceBatchInitializations(false/*not initAfterLoad*/); // java nature added or removed: remember project and its dependents this.addToRootsToRefreshWithDependents(javaProject); @@ -428,7 +428,7 @@ break; case IResourceDelta.REMOVED : - this.manager.batchContainerInitializations = true; + this.manager.forceBatchInitializations(false/*not initAfterLoad*/); // remove classpath cache so that initializeRoots() will not consider the project has a classpath this.manager.removePerProjectInfo(javaProject); @@ -444,7 +444,7 @@ IFile file = (IFile) resource; /* classpath file change */ if (file.getName().equals(JavaProject.CLASSPATH_FILENAME)) { - this.manager.batchContainerInitializations = true; + this.manager.forceBatchInitializations(false/*not initAfterLoad*/); switch (delta.getKind()) { case IResourceDelta.CHANGED : int flags = delta.getFlags(); @@ -1705,7 +1705,7 @@ return null; } } - this.state.initializeRoots(); + this.state.initializeRoots(false/*not initiAfterLoad*/); this.currentElement = null; // get the workspace delta, and start processing there. Index: model/org/eclipse/jdt/internal/core/DeltaProcessingState.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java,v retrieving revision 1.43 diff -u -r1.43 DeltaProcessingState.java --- model/org/eclipse/jdt/internal/core/DeltaProcessingState.java 31 Aug 2007 07:36:52 -0000 1.43 +++ model/org/eclipse/jdt/internal/core/DeltaProcessingState.java 11 Oct 2007 10:47:15 -0000 @@ -178,7 +178,7 @@ } } - public void initializeRoots() { + public void initializeRoots(boolean initAfterLoad) { // recompute root infos only if necessary HashMap newRoots = null; @@ -196,7 +196,7 @@ // all classpaths in the workspace are going to be resolved // ensure that containers are initialized in one batch - JavaModelManager.getJavaModelManager().batchContainerInitializations = true; + JavaModelManager.getJavaModelManager().forceBatchInitializations(initAfterLoad); newRoots = new HashMap(); newOtherRoots = new HashMap(); Index: model/org/eclipse/jdt/core/JavaCore.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java,v retrieving revision 1.585 diff -u -r1.585 JavaCore.java --- model/org/eclipse/jdt/core/JavaCore.java 4 Oct 2007 13:01:36 -0000 1.585 +++ model/org/eclipse/jdt/core/JavaCore.java 11 Oct 2007 10:47:15 -0000 @@ -105,6 +105,7 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Plugin; import org.eclipse.core.runtime.QualifiedName; @@ -3330,52 +3331,78 @@ */ public static void initializeAfterLoad(IProgressMonitor monitor) throws CoreException { try { - if (monitor != null) monitor.beginTask(Messages.javamodel_initialization, 100); + if (monitor != null) { + monitor.beginTask(Messages.javamodel_initialization, 100); + monitor.subTask(Messages.javamodel_configuring_classpath_containers); + } // initialize all containers and variables JavaModelManager manager = JavaModelManager.getJavaModelManager(); + SubProgressMonitor subMonitor = null; try { if (monitor != null) { - monitor.subTask(Messages.javamodel_configuring_classpath_containers); - manager.batchContainerInitializationsProgress.set(new SubProgressMonitor(monitor, 50)); // 50% of the time is spent in initializing containers and variables + subMonitor = new SubProgressMonitor(monitor, 50); // 50% of the time is spent in initializing containers and variables + subMonitor.beginTask("", 100); //$NON-NLS-1$ + subMonitor.worked(5); // give feedback to the user that something is happening + manager.batchContainerInitializationsProgress.initializeAfterLoadMonitor.set(subMonitor); } - - // all classpaths in the workspace are going to be resolved, ensure that containers are initialized in one batch - manager.batchContainerInitializations = true; - - // avoid leaking source attachment properties (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=183413) - IJavaProject[] projects = manager.getJavaModel().getJavaProjects(); - for (int i = 0, length = projects.length; i < length; i++) { - IClasspathEntry[] classpath; - try { - classpath = ((JavaProject) projects[i]).getResolvedClasspath(); - } catch (JavaModelException e) { - // project no longer exist: ignore - continue; - } - if (classpath != null) { - for (int j = 0, length2 = classpath.length; j < length2; j++) { - IClasspathEntry entry = classpath[j]; - if (entry.getSourceAttachmentPath() != null) - Util.setSourceAttachmentProperty(entry.getPath(), null); - // else source might have been attached by IPackageFragmentRoot#attachSource(...), we keep it + if (manager.forceBatchInitializations(true/*initAfterLoad*/)) { // if no other thread has started the batch container initializations + manager.getClasspathContainer(Path.EMPTY, null); // force the batch initialization + } else { // else wait for the batch initialization to finish + while (manager.batchContainerInitializations == JavaModelManager.BATCH_INITIALIZATION_IN_PROGRESS) { + if (subMonitor != null) { + subMonitor.subTask(manager.batchContainerInitializationsProgress.subTaskName); + subMonitor.worked(manager.batchContainerInitializationsProgress.getWorked()); + } + synchronized(manager) { + try { + manager.wait(100); + } catch (InterruptedException e) { + // continue + } } } } - - // initialize delta state - manager.deltaState.rootsAreStale = true; // in case it was already initialized before we cleaned up the source attachment proprties - manager.deltaState.initializeRoots(); } finally { - manager.batchContainerInitializationsProgress.set(null); + if (subMonitor != null) + subMonitor.done(); + manager.batchContainerInitializationsProgress.initializeAfterLoadMonitor.set(null); } + + // avoid leaking source attachment properties (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=183413 ) + if (monitor != null) + monitor.subTask(Messages.javamodel_resetting_source_attachment_properties); + final IJavaProject[] projects = manager.getJavaModel().getJavaProjects(); + for (int i = 0, length = projects.length; i < length; i++) { + IClasspathEntry[] classpath; + try { + classpath = ((JavaProject) projects[i]).getResolvedClasspath(); + } catch (JavaModelException e) { + // project no longer exist: ignore + continue; + } + if (classpath != null) { + for (int j = 0, length2 = classpath.length; j < length2; j++) { + IClasspathEntry entry = classpath[j]; + if (entry.getSourceAttachmentPath() != null) + Util.setSourceAttachmentProperty(entry.getPath(), null); + // else source might have been attached by IPackageFragmentRoot#attachSource(...), we keep it + } + } + } + + // initialize delta state + if (monitor != null) + monitor.subTask(Messages.javamodel_initializing_delta_state); + manager.deltaState.rootsAreStale = true; // in case it was already initialized before we cleaned up the source attachment proprties + manager.deltaState.initializeRoots(true/*initAfteLoad*/); // dummy query for waiting until the indexes are ready + if (monitor != null) + monitor.subTask(Messages.javamodel_configuring_searchengine); SearchEngine engine = new SearchEngine(); IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); try { - if (monitor != null) - monitor.subTask(Messages.javamodel_configuring_searchengine); engine.searchAllTypeNames( null, SearchPattern.R_EXACT_MATCH, @@ -3426,22 +3453,14 @@ System.out.println("Build state version number has changed"); //$NON-NLS-1$ IWorkspaceRunnable runnable = new IWorkspaceRunnable() { public void run(IProgressMonitor progressMonitor2) throws CoreException { - IJavaProject[] projects = null; - try { - projects = model.getJavaProjects(); - } catch (JavaModelException e) { - // could not get Java projects: ignore - } - if (projects != null) { - for (int i = 0, length = projects.length; i < length; i++) { - IJavaProject project = projects[i]; - try { - if (JavaBuilder.DEBUG) - System.out.println("Touching " + project.getElementName()); //$NON-NLS-1$ - project.getProject().touch(progressMonitor2); - } catch (CoreException e) { - // could not touch this project: ignore - } + for (int i = 0, length = projects.length; i < length; i++) { + IJavaProject project = projects[i]; + try { + if (JavaBuilder.DEBUG) + System.out.println("Touching " + project.getElementName()); //$NON-NLS-1$ + project.getProject().touch(progressMonitor2); + } catch (CoreException e) { + // could not touch this project: ignore } } } Index: model/org/eclipse/jdt/internal/core/util/messages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties,v retrieving revision 1.65 diff -u -r1.65 messages.properties --- model/org/eclipse/jdt/internal/core/util/messages.properties 7 Mar 2007 16:09:14 -0000 1.65 +++ model/org/eclipse/jdt/internal/core/util/messages.properties 11 Oct 2007 10:47:16 -0000 @@ -179,12 +179,14 @@ ## java model initialization javamodel_initialization = Initializing Java tooling +javamodel_initializing_delta_state= Initializing delta state javamodel_configuring_searchengine=Configuring search engine javamodel_configuring_classpath_containers=Configuring classpath containers javamodel_getting_build_state_number=Getting build state version number javamodel_configuring=Configuring {0} javamodel_building_after_upgrade=Triggering build after upgrade javamodel_refreshing_external_jars=Refreshing external archives +javamodel_resetting_source_attachment_properties=Resetting source attachment properties ### access restrictions restrictedAccess_project = The type {0} is not accessible due to restriction on required project {1} Index: model/org/eclipse/jdt/internal/core/util/Messages.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java,v retrieving revision 1.16 diff -u -r1.16 Messages.java --- model/org/eclipse/jdt/internal/core/util/Messages.java 7 Mar 2007 16:09:14 -0000 1.16 +++ model/org/eclipse/jdt/internal/core/util/Messages.java 11 Oct 2007 10:47:16 -0000 @@ -37,12 +37,14 @@ public static String element_nullType; public static String element_illegalParent; public static String javamodel_initialization; + public static String javamodel_initializing_delta_state; public static String javamodel_building_after_upgrade; public static String javamodel_configuring; public static String javamodel_configuring_classpath_containers; public static String javamodel_configuring_searchengine; public static String javamodel_getting_build_state_number; public static String javamodel_refreshing_external_jars; + public static String javamodel_resetting_source_attachment_properties; public static String operation_needElements; public static String operation_needName; public static String operation_needPath; Index: model/org/eclipse/jdt/internal/core/BatchInitializationMonitor.java =================================================================== RCS file: model/org/eclipse/jdt/internal/core/BatchInitializationMonitor.java diff -N model/org/eclipse/jdt/internal/core/BatchInitializationMonitor.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ model/org/eclipse/jdt/internal/core/BatchInitializationMonitor.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,86 @@ +package org.eclipse.jdt.internal.core; +import org.eclipse.core.runtime.IProgressMonitor; + +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +public class BatchInitializationMonitor implements IProgressMonitor { + + public ThreadLocal initializeAfterLoadMonitor = new ThreadLocal(); + + public String subTaskName = ""; //$NON-NLS-1$ + public int worked = 0; + + private IProgressMonitor getMonitor() { + return (IProgressMonitor) this.initializeAfterLoadMonitor.get(); + } + + public void beginTask(String name, int totalWork) { + IProgressMonitor monitor = getMonitor(); + if (monitor != null) + monitor.beginTask(name, totalWork); + } + + public void done() { + IProgressMonitor monitor = getMonitor(); + if (monitor != null) + monitor.done(); + this.worked = 0; + this.subTaskName = ""; //$NON-NLS-1$ + } + + public void internalWorked(double work) { + IProgressMonitor monitor = getMonitor(); + if (monitor != null) + monitor.internalWorked(work); + } + + public boolean isCanceled() { + IProgressMonitor monitor = getMonitor(); + if (monitor != null) + return monitor.isCanceled(); + return false; + } + + public void setCanceled(boolean value) { + IProgressMonitor monitor = getMonitor(); + if (monitor != null) + monitor.setCanceled(value); + } + + public void setTaskName(String name) { + IProgressMonitor monitor = getMonitor(); + if (monitor != null) + monitor.setTaskName(name); + } + + public void subTask(String name) { + IProgressMonitor monitor = getMonitor(); + if (monitor != null) + monitor.subTask(name); + this.subTaskName = name; + } + + public void worked(int work) { + IProgressMonitor monitor = getMonitor(); + if (monitor != null) + monitor.worked(work); + synchronized(this) { + this.worked += work; + } + } + + public synchronized int getWorked() { + int result = this.worked; + this.worked = 0; + return result; + } +}