Skip to content

Commit 3884639

Browse files
committed
Unify access to RequiredPluginsClasspathContainer and classpath updates
Currently there a many slightly different access to the RequiredPluginsClasspathContainer when performing an update for the classpath, this makes it quite hard to control what happens when. Also then different jobs are fired to update the classpath and this also creates a lot of boilerplate code. This now do the following: - make RequiredPluginsClasspathContainer package protected to limit its visibility and scope - let all code use ClasspathComputer for its access and to request an update to the container.
1 parent 42ba205 commit 3884639

10 files changed

Lines changed: 157 additions & 267 deletions

File tree

ds/org.eclipse.pde.ds.annotations/src/org/eclipse/pde/ds/internal/annotations/DSAnnotationPreferenceListener.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,15 @@
2323
import org.eclipse.core.runtime.CoreException;
2424
import org.eclipse.core.runtime.IProgressMonitor;
2525
import org.eclipse.core.runtime.IStatus;
26+
import org.eclipse.core.runtime.OperationCanceledException;
2627
import org.eclipse.core.runtime.Status;
2728
import org.eclipse.core.runtime.SubMonitor;
29+
import org.eclipse.core.runtime.jobs.Job;
2830
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
2931
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
3032
import org.eclipse.core.runtime.preferences.InstanceScope;
31-
import org.eclipse.jdt.core.JavaCore;
33+
import org.eclipse.pde.internal.core.ClasspathComputer;
34+
import org.eclipse.pde.internal.core.PluginModelManager;
3235
import org.eclipse.swt.widgets.Display;
3336
import org.eclipse.ui.PlatformUI;
3437

@@ -48,6 +51,7 @@ public void preferenceChange(final PreferenceChangeEvent event) {
4851
}
4952

5053
WorkspaceJob job = new WorkspaceJob(Messages.DSAnnotationPreferenceListener_jobName) {
54+
@SuppressWarnings({ "restriction" })
5155
@Override
5256
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
5357
IProject[] projects = ws.getRoot().getProjects();
@@ -61,13 +65,14 @@ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
6165

6266
SubMonitor progress = SubMonitor.convert(monitor, Messages.DSAnnotationPreferenceListener_taskName,
6367
managedProjects.size() * 2);
64-
for (IProject project : managedProjects) {
65-
if (requiresClasspathUpdate) {
66-
ProjectClasspathPreferenceChangeListener.updateClasspathContainer(JavaCore.create(project), progress.newChild(1));
67-
} else {
68-
progress.worked(1);
68+
if (requiresClasspathUpdate) {
69+
ClasspathComputer.requestClasspathUpdate(managedProjects);
70+
try {
71+
Job.getJobManager().join(PluginModelManager.class, monitor);
72+
} catch (OperationCanceledException | InterruptedException e) {
6973
}
70-
74+
}
75+
for (IProject project : managedProjects) {
7176
if (autoBuilding) {
7277
project.build(IncrementalProjectBuilder.FULL_BUILD, progress.newChild(1));
7378
} else {

ds/org.eclipse.pde.ds.annotations/src/org/eclipse/pde/ds/internal/annotations/DSLibPluginModelListener.java

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,17 @@
1414
package org.eclipse.pde.ds.internal.annotations;
1515

1616
import java.util.ArrayList;
17-
import java.util.Collection;
1817
import java.util.HashMap;
1918
import java.util.HashSet;
2019
import java.util.Map;
2120

22-
import org.eclipse.core.resources.WorkspaceJob;
23-
import org.eclipse.core.runtime.IProgressMonitor;
24-
import org.eclipse.core.runtime.IStatus;
25-
import org.eclipse.core.runtime.Status;
26-
import org.eclipse.core.runtime.SubMonitor;
27-
import org.eclipse.core.runtime.jobs.ISchedulingRule;
28-
import org.eclipse.core.runtime.jobs.MultiRule;
21+
import org.eclipse.core.resources.IProject;
2922
import org.eclipse.jdt.core.IJavaProject;
3023
import org.eclipse.pde.core.plugin.ModelEntry;
24+
import org.eclipse.pde.internal.core.ClasspathComputer;
3125
import org.eclipse.pde.internal.core.IPluginModelListener;
3226
import org.eclipse.pde.internal.core.PluginModelDelta;
3327
import org.eclipse.pde.internal.core.PluginModelManager;
34-
import org.eclipse.swt.widgets.Display;
35-
import org.eclipse.ui.PlatformUI;
3628

3729
@SuppressWarnings("restriction")
3830
public class DSLibPluginModelListener implements IPluginModelListener {
@@ -114,50 +106,20 @@ && containsModel(delta.getRemovedEntries(), modelId))) {
114106
}
115107
}
116108

117-
ArrayList<IJavaProject> toUpdate = new ArrayList<>(projects.size());
109+
ArrayList<IProject> toUpdate = new ArrayList<>(projects.size());
118110
if (!modelIds.isEmpty()) {
119111
for (Map.Entry<IJavaProject, String> entry : projects.entrySet()) {
120112
IJavaProject project = entry.getKey();
121113
String modelId = entry.getValue();
122114
if (modelIds.contains(modelId)) {
123-
toUpdate.add(project);
115+
toUpdate.add(project.getProject());
124116
}
125117
}
126118
}
127-
128-
if (!toUpdate.isEmpty()) {
129-
requestClasspathUpdate(toUpdate);
130-
}
119+
ClasspathComputer.requestClasspathUpdate(toUpdate);
131120
}
132121
}
133122

134-
private void requestClasspathUpdate(final Collection<IJavaProject> changedProjects) {
135-
WorkspaceJob job = new WorkspaceJob(Messages.ProjectClasspathPreferenceChangeListener_jobName) {
136-
@Override
137-
public IStatus runInWorkspace(IProgressMonitor monitor) {
138-
SubMonitor progress = SubMonitor.convert(monitor, Messages.DSAnnotationPreferenceListener_taskName,
139-
changedProjects.size());
140-
for (IJavaProject project : changedProjects) {
141-
ProjectClasspathPreferenceChangeListener.updateClasspathContainer(project, progress.newChild(1));
142-
}
143-
144-
return Status.OK_STATUS;
145-
}
146-
};
147-
148-
job.setSystem(true);
149-
150-
ISchedulingRule[] rules = changedProjects.stream().map(IJavaProject::getProject)
151-
.toArray(size -> new ISchedulingRule[size]);
152-
job.setRule(new MultiRule(rules));
153-
154-
Display display = Display.getCurrent();
155-
if (display != null) {
156-
PlatformUI.getWorkbench().getProgressService().showInDialog(display.getActiveShell(), job);
157-
}
158-
159-
job.schedule();
160-
}
161123

162124
public static void dispose() {
163125
DSLibPluginModelListener instance = getInstance(false);

ds/org.eclipse.pde.ds.annotations/src/org/eclipse/pde/ds/internal/annotations/ProjectClasspathPreferenceChangeListener.java

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,10 @@
1717
import org.eclipse.core.resources.IResourceChangeListener;
1818
import org.eclipse.core.resources.ProjectScope;
1919
import org.eclipse.core.resources.ResourcesPlugin;
20-
import org.eclipse.core.runtime.CoreException;
21-
import org.eclipse.core.runtime.IProgressMonitor;
22-
import org.eclipse.core.runtime.OperationCanceledException;
2320
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
2421
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
25-
import org.eclipse.jdt.core.ClasspathContainerInitializer;
2622
import org.eclipse.jdt.core.IJavaProject;
27-
import org.eclipse.jdt.core.JavaCore;
28-
import org.eclipse.pde.core.plugin.IPluginModelBase;
29-
import org.eclipse.pde.core.plugin.PluginRegistry;
30-
import org.eclipse.pde.internal.core.ClasspathUtilCore;
31-
import org.eclipse.pde.internal.core.PDECore;
32-
import org.eclipse.pde.internal.core.RequiredPluginsClasspathContainer;
3323

34-
@SuppressWarnings("restriction")
3524
public class ProjectClasspathPreferenceChangeListener implements IPreferenceChangeListener, IResourceChangeListener {
3625

3726
private final IJavaProject project;
@@ -50,40 +39,6 @@ public void preferenceChange(PreferenceChangeEvent event) {
5039
}
5140

5241

53-
static void updateClasspathContainer(IJavaProject project, IProgressMonitor monitor) {
54-
if (monitor != null) {
55-
monitor.beginTask(project.getElementName(), 1);
56-
}
57-
58-
try {
59-
if (monitor != null && monitor.isCanceled()) {
60-
throw new OperationCanceledException();
61-
}
62-
63-
ClasspathContainerInitializer initializer = JavaCore.getClasspathContainerInitializer(PDECore.REQUIRED_PLUGINS_CONTAINER_PATH.segment(0));
64-
if (initializer != null && initializer.canUpdateClasspathContainer(PDECore.REQUIRED_PLUGINS_CONTAINER_PATH, project)) {
65-
IPluginModelBase model = PluginRegistry.findModel(project.getProject());
66-
if (model != null) {
67-
try {
68-
initializer.requestClasspathContainerUpdate(PDECore.REQUIRED_PLUGINS_CONTAINER_PATH, project,
69-
new RequiredPluginsClasspathContainer(model, ClasspathUtilCore.getBuild(model),
70-
project.getProject()));
71-
} catch (CoreException e) {
72-
Activator.log(e);
73-
}
74-
}
75-
}
76-
77-
if (monitor != null) {
78-
monitor.worked(1);
79-
}
80-
} finally {
81-
if (monitor != null) {
82-
monitor.done();
83-
}
84-
}
85-
}
86-
8742
@Override
8843
public void resourceChanged(IResourceChangeEvent event) {
8944
if ((event.getType() == IResourceChangeEvent.PRE_CLOSE || event.getType() == IResourceChangeEvent.PRE_DELETE)

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

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import java.util.ArrayList;
1717
import java.util.Arrays;
18+
import java.util.Collection;
1819
import java.util.Collections;
1920
import java.util.HashMap;
2021
import java.util.Iterator;
@@ -29,9 +30,15 @@
2930
import org.eclipse.core.resources.IFile;
3031
import org.eclipse.core.resources.IProject;
3132
import org.eclipse.core.resources.IResource;
33+
import org.eclipse.core.resources.ResourcesPlugin;
3234
import org.eclipse.core.runtime.CoreException;
3335
import org.eclipse.core.runtime.IPath;
36+
import org.eclipse.core.runtime.IProgressMonitor;
37+
import org.eclipse.core.runtime.IStatus;
38+
import org.eclipse.core.runtime.Status;
39+
import org.eclipse.core.runtime.jobs.Job;
3440
import org.eclipse.jdt.core.IClasspathAttribute;
41+
import org.eclipse.jdt.core.IClasspathContainer;
3542
import org.eclipse.jdt.core.IClasspathEntry;
3643
import org.eclipse.jdt.core.IJavaModelStatus;
3744
import org.eclipse.jdt.core.IJavaProject;
@@ -49,6 +56,7 @@
4956
import org.eclipse.pde.core.plugin.IPluginLibrary;
5057
import org.eclipse.pde.core.plugin.IPluginModelBase;
5158
import org.eclipse.pde.internal.core.build.WorkspaceBuildModel;
59+
import org.eclipse.pde.internal.core.natures.PluginProject;
5260
import org.eclipse.pde.internal.core.project.PDEProject;
5361
import org.eclipse.pde.internal.core.util.CoreUtility;
5462
import org.eclipse.team.core.RepositoryProvider;
@@ -65,6 +73,11 @@ private record ClasspathConfiguration(IPluginModelBase model, IJavaProject javaP
6573
private static final int SEVERITY_WARNING = 2;
6674
private static final int SEVERITY_IGNORE = 1;
6775

76+
/**
77+
* Job used to update class path containers.
78+
*/
79+
private static final UpdateClasspathsJob fUpdateJob = new UpdateClasspathsJob();
80+
6881
public static void setClasspath(IProject project, IPluginModelBase model) throws CoreException {
6982
IClasspathEntry[] entries = getClasspath(project, model, null, false, true);
7083
JavaCore.create(project).setRawClasspath(entries, null);
@@ -473,4 +486,98 @@ public static IClasspathEntry createContainerEntry() {
473486
return JavaCore.newContainerEntry(PDECore.REQUIRED_PLUGINS_CONTAINER_PATH);
474487
}
475488

489+
public static IClasspathEntry[] computeClasspathEntries(IPluginModelBase model, IProject project) {
490+
IClasspathContainer container = new RequiredPluginsClasspathContainer(model, project);
491+
return container.getClasspathEntries();
492+
}
493+
494+
public static void requestClasspathUpdate(IProject project) {
495+
if (project == null) {
496+
return;
497+
}
498+
requestClasspathUpdate(List.of(project));
499+
}
500+
501+
public static void requestClasspathUpdate(Collection<IProject> updateProjects) {
502+
if (updateProjects == null || updateProjects.isEmpty()) {
503+
return;
504+
}
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+
}
518+
}
519+
520+
/**
521+
* 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.
524+
*/
525+
private static final class UpdateClasspathsJob extends Job {
526+
527+
private final List<IJavaProject> fProjects = new ArrayList<>();
528+
private final List<IClasspathContainer> fContainers = new ArrayList<>();
529+
530+
/**
531+
* Constructs a new job.
532+
*/
533+
public UpdateClasspathsJob() {
534+
super(PDECoreMessages.PluginModelManager_1);
535+
// The job is given a workspace lock so other jobs can't run on a
536+
// stale classpath (bug 354993)
537+
setRule(ResourcesPlugin.getWorkspace().getRoot());
538+
}
539+
540+
@Override
541+
public boolean belongsTo(Object family) {
542+
return family == PluginModelManager.class;
543+
}
544+
545+
@Override
546+
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();
557+
}
558+
JavaCore.setClasspathContainer(PDECore.REQUIRED_PLUGINS_CONTAINER_PATH, projects, containers,
559+
monitor);
560+
synchronized (fProjects) {
561+
more = !fProjects.isEmpty();
562+
}
563+
} while (more);
564+
565+
} catch (JavaModelException e) {
566+
return e.getStatus();
567+
}
568+
return Status.OK_STATUS;
569+
}
570+
571+
/**
572+
* Queues more projects/containers.
573+
*/
574+
void add(IJavaProject project, IClasspathContainer container) {
575+
synchronized (fProjects) {
576+
fProjects.add(project);
577+
fContainers.add(container);
578+
}
579+
}
580+
581+
}
582+
476583
}

0 commit comments

Comments
 (0)