Skip to content

Commit 000260f

Browse files
committed
Do checks inside the job and compute the classpath entries
Currently some checks are performed outside the update job, for example the model is fetched and the javanature. These values can change between submit the data to the job and it actually pick it up. This now moves these check into the job itself and uses a concurrent queue to prevent the need for synchronized. Also results are collected inside a Map so if new update request are received in the meanwhile we discard the previous computed values. Beside that, entries are now eagerly computed as they are required anyways when we set the classpath and we can catch problems that occur here instead of just swallow them. Also the job now react to cancel request much better than before.
1 parent 53dcd41 commit 000260f

4 files changed

Lines changed: 78 additions & 67 deletions

File tree

ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/ClasspathComputer.java

Lines changed: 66 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import java.util.List;
2424
import java.util.Map;
2525
import java.util.Map.Entry;
26+
import java.util.Queue;
27+
import java.util.concurrent.ConcurrentLinkedQueue;
2628
import java.util.regex.Pattern;
2729
import java.util.stream.Collectors;
2830
import java.util.stream.Stream;
@@ -35,6 +37,7 @@
3537
import org.eclipse.core.runtime.IPath;
3638
import org.eclipse.core.runtime.IProgressMonitor;
3739
import org.eclipse.core.runtime.IStatus;
40+
import org.eclipse.core.runtime.MultiStatus;
3841
import org.eclipse.core.runtime.Status;
3942
import org.eclipse.core.runtime.jobs.Job;
4043
import org.eclipse.jdt.core.IClasspathAttribute;
@@ -502,30 +505,17 @@ public static void requestClasspathUpdate(Collection<IProject> updateProjects) {
502505
if (updateProjects == null || updateProjects.isEmpty()) {
503506
return;
504507
}
505-
boolean added = false;
506-
for (IProject project : updateProjects) {
507-
if (project.exists() && project.isOpen()) {
508-
IPluginModelBase model = PluginModelManager.getInstance().findModel(project);
509-
if (model != null && PluginProject.isJavaProject(project)) {
510-
fUpdateJob.add(JavaCore.create(project), new RequiredPluginsClasspathContainer(model, project));
511-
added = true;
512-
}
513-
}
514-
}
515-
if (added) {
516-
fUpdateJob.schedule();
517-
}
508+
fUpdateJob.addAll(updateProjects);
518509
}
519510

520511
/**
521512
* Job to update class path containers asynchronously. Avoids blocking the
522-
* UI thread while saving the manifest editor. The job is given a workspace
523-
* lock so other jobs can't run on a stale classpath.
513+
* UI thread. The job is given a workspace lock so other jobs can't run on a
514+
* stale classpath.
524515
*/
525516
private static final class UpdateClasspathsJob extends Job {
526517

527-
private final List<IJavaProject> fProjects = new ArrayList<>();
528-
private final List<IClasspathContainer> fContainers = new ArrayList<>();
518+
private final Queue<IProject> workQueue = new ConcurrentLinkedQueue<>();
529519

530520
/**
531521
* Constructs a new job.
@@ -539,43 +529,77 @@ public UpdateClasspathsJob() {
539529

540530
@Override
541531
public boolean belongsTo(Object family) {
542-
return family == PluginModelManager.class;
532+
return family == PluginModelManager.class || family == ClasspathComputer.class;
543533
}
544534

545535
@Override
546536
protected IStatus run(IProgressMonitor monitor) {
547-
try {
548-
boolean more = false;
549-
do {
550-
IJavaProject[] projects = null;
551-
IClasspathContainer[] containers = null;
552-
synchronized (fProjects) {
553-
projects = fProjects.toArray(new IJavaProject[fProjects.size()]);
554-
containers = fContainers.toArray(new IClasspathContainer[fContainers.size()]);
555-
fProjects.clear();
556-
fContainers.clear();
537+
PluginModelManager modelManager = PluginModelManager.getInstance();
538+
Map<IJavaProject, IClasspathContainer> updateProjects = new LinkedHashMap<>();
539+
Map<IProject, IStatus> errorsPerProject = new LinkedHashMap<>();
540+
IProject project;
541+
while (!monitor.isCanceled() && (project = workQueue.poll()) != null) {
542+
if (project.exists() && project.isOpen()) {
543+
IPluginModelBase model = modelManager.findModel(project);
544+
if (model != null && PluginProject.isJavaProject(project)) {
545+
IJavaProject javaProject = JavaCore.create(project);
546+
RequiredPluginsClasspathContainer classpathContainer = new RequiredPluginsClasspathContainer(
547+
model, project);
548+
try {
549+
// eager compute the entries as they will be
550+
// needed soon, if any error occurs here we do
551+
// not update the entry, all errors will be
552+
// reported at the end of the update!
553+
classpathContainer.computeEntries();
554+
updateProjects.put(javaProject, classpathContainer);
555+
errorsPerProject.remove(project);
556+
} catch (CoreException e) {
557+
errorsPerProject.put(project, e.getStatus());
558+
}
557559
}
558-
JavaCore.setClasspathContainer(PDECore.REQUIRED_PLUGINS_CONTAINER_PATH, projects, containers,
559-
monitor);
560-
synchronized (fProjects) {
561-
more = !fProjects.isEmpty();
560+
}
561+
}
562+
if (monitor.isCanceled()) {
563+
return Status.CANCEL_STATUS;
564+
}
565+
if (!updateProjects.isEmpty()) {
566+
try {
567+
int i = 0;
568+
int n = updateProjects.size();
569+
IJavaProject[] javaProjects = new IJavaProject[n];
570+
IClasspathContainer[] container = new IClasspathContainer[n];
571+
for (Entry<IJavaProject, IClasspathContainer> entry : updateProjects.entrySet()) {
572+
javaProjects[i] = entry.getKey();
573+
container[i] = entry.getValue();
574+
i++;
562575
}
563-
} while (more);
564-
565-
} catch (JavaModelException e) {
566-
return e.getStatus();
576+
JavaCore.setClasspathContainer(PDECore.REQUIRED_PLUGINS_CONTAINER_PATH, javaProjects, container,
577+
monitor);
578+
} catch (JavaModelException e) {
579+
return e.getStatus();
580+
}
581+
}
582+
IStatus[] errors = errorsPerProject.values().toArray(IStatus[]::new);
583+
if (errors.length == 0) {
584+
return Status.OK_STATUS;
567585
}
568-
return Status.OK_STATUS;
586+
if (errors.length == 1) {
587+
return errors[0];
588+
}
589+
MultiStatus overallStatus = new MultiStatus(ClasspathComputer.class, 0,
590+
PDECoreMessages.ClasspathComputer_failed);
591+
for (IStatus status : errors) {
592+
overallStatus.add(status);
593+
}
594+
return overallStatus;
569595
}
570596

571597
/**
572598
* Queues more projects/containers.
573599
*/
574-
void add(IJavaProject project, IClasspathContainer container) {
575-
synchronized (fProjects) {
576-
fProjects.add(project);
577-
fContainers.add(container);
578-
}
600+
void addAll(Collection<IProject> tocheck) {
601+
workQueue.addAll(tocheck);
602+
schedule();
579603
}
580604

581605
}

ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDECoreMessages.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ public class PDECoreMessages extends NLS {
281281

282282
public static String BuildErrorReporter_SourceCompatibility;
283283

284+
public static String ClasspathComputer_failed;
285+
284286
public static String ClasspathHelper_BadFileLocation;
285287

286288
public static String ConvertSchemaToHTML_CannotFindIncludedSchema;

ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsClasspathContainer.java

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import org.eclipse.core.resources.IFile;
3737
import org.eclipse.core.resources.IProject;
3838
import org.eclipse.core.resources.IResource;
39-
import org.eclipse.core.resources.IWorkspaceRoot;
4039
import org.eclipse.core.runtime.CoreException;
4140
import org.eclipse.core.runtime.IConfigurationElement;
4241
import org.eclipse.core.runtime.IExtensionRegistry;
@@ -131,6 +130,14 @@ public String getDescription() {
131130

132131
@Override
133132
public IClasspathEntry[] getClasspathEntries() {
133+
try {
134+
return computeEntries();
135+
} catch (CoreException e) {
136+
return new IClasspathEntry[0];
137+
}
138+
}
139+
140+
IClasspathEntry[] computeEntries() throws CoreException {
134141
if (fEntries == null) {
135142
if (fModel == null) {
136143
fEntries = computePluginEntriesByProject();
@@ -215,9 +222,8 @@ protected void debugProblems(Project bnd) {
215222
}
216223
}
217224

218-
private List<IClasspathEntry> computePluginEntriesByModel() {
225+
private List<IClasspathEntry> computePluginEntriesByModel() throws CoreException {
219226
List<IClasspathEntry> entries = new ArrayList<>();
220-
try {
221227
BundleDescription desc = fModel.getBundleDescription();
222228
if (desc == null) {
223229
return List.of();
@@ -278,8 +284,6 @@ private List<IClasspathEntry> computePluginEntriesByModel() {
278284
addJunit5RuntimeDependencies(added, entries);
279285
addImplicitDependencies(desc, added, entries);
280286

281-
} catch (CoreException e) {
282-
}
283287
return entries;
284288
}
285289

@@ -728,24 +732,4 @@ private void addExtraLibrary(IPath path, IPluginModelBase model, List<IClasspath
728732
}
729733
}
730734

731-
/**
732-
* Tries to compute a full set of bundle dependencies, including not
733-
* exported bundle dependencies and bundles contributing packages possibly
734-
* imported by any of bundles in the dependency graph.
735-
*
736-
* @return never null, but possibly empty project list which all projects in
737-
* the workspace this container depends on, directly or indirectly.
738-
*/
739-
public List<IProject> getAllProjectDependencies() {
740-
IWorkspaceRoot root = PDECore.getWorkspace().getRoot();
741-
try {
742-
addImportedPackages = true;
743-
return computePluginEntriesByModel().stream()
744-
.filter(cpe -> cpe.getEntryKind() == IClasspathEntry.CPE_PROJECT)
745-
.map(cpe -> cpe.getPath().lastSegment()).map(root::getProject) //
746-
.filter(IProject::exists).toList();
747-
} finally {
748-
addImportedPackages = false;
749-
}
750-
}
751735
}

ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/pderesources.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ FeatureExportOperation_runningPackagerScript=Running packager script
222222
FeatureExportOperation_workspaceBuildErrorsFoundDuringExport=Export completed successfully, but build problems were detected in the following required projects: {0}
223223
FeatureModelManager_initializingFeatureTargetPlatform=Initializing feature from target platform
224224
BaseExportTask_pdeExport=PDE Export
225+
ClasspathComputer_failed=Classpath Update failed
225226
ClasspathHelper_BadFileLocation=Could not determine absolute location of file: {0}
226227
ConvertSchemaToHTML_CannotFindIncludedSchema=Cannot find included schema ''{0}'' required by parent schema ''{1}''
227228
ConvertSchemaToHTML_InvalidAdditionalSearchPath=Invalid path found in additional search paths: {0}

0 commit comments

Comments
 (0)