Skip to content

Commit 0e88d89

Browse files
authored
Suspend only ConvertJobs instead of all non-system jobs (#2112)
* Suspend only ConvertJobs * Identify ConvertJob in a more robust way
1 parent 38cd14d commit 0e88d89

5 files changed

Lines changed: 99 additions & 57 deletions

File tree

plugins/com.google.cloud.tools.eclipse.appengine.facets.test/META-INF/MANIFEST.MF

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Require-Bundle: org.eclipse.wst.common.project.facet.core,
1212
Import-Package: com.google.cloud.tools.eclipse.test.util,
1313
com.google.cloud.tools.eclipse.test.util.project,
1414
org.eclipse.wst.common.project.facet.core,
15+
org.eclipse.wst.jsdt.web.core.javascript,
1516
org.junit;version="4.12.0",
1617
org.junit.runner;version="4.12.0",
1718
org.mockito;provider=google;version="1.10.19",

plugins/com.google.cloud.tools.eclipse.appengine.facets.test/src/com/google/cloud/tools/eclipse/appengine/facets/NonSystemJobSuspenderTest.java renamed to plugins/com.google.cloud.tools.eclipse.appengine.facets.test/src/com/google/cloud/tools/eclipse/appengine/facets/ConvertJobSuspenderTest.java

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,41 +17,72 @@
1717
package com.google.cloud.tools.eclipse.appengine.facets;
1818

1919
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertNotNull;
2021
import static org.junit.Assert.assertTrue;
22+
import static org.junit.Assert.fail;
2123

24+
import com.google.common.base.Predicates;
2225
import org.eclipse.core.runtime.IProgressMonitor;
2326
import org.eclipse.core.runtime.IStatus;
2427
import org.eclipse.core.runtime.Status;
2528
import org.eclipse.core.runtime.jobs.Job;
29+
import org.eclipse.wst.jsdt.web.core.javascript.JsNameManglerUtil;
2630
import org.junit.After;
31+
import org.junit.Before;
2732
import org.junit.Test;
33+
import org.osgi.framework.Bundle;
34+
import org.osgi.framework.FrameworkUtil;
2835

29-
public class NonSystemJobSuspenderTest {
36+
public class ConvertJobSuspenderTest {
3037

3138
private Job job1 = new NoOpSpinJob("Test job 1");
3239
private Job job2 = new NoOpSpinJob("Test job 2");
3340

41+
@Before
42+
public void setUp() {
43+
// Assume all test jobs are "ConvertJob"s.
44+
ConvertJobSuspender.isConvertJob = Predicates.alwaysTrue();
45+
}
46+
3447
@After
3548
public void tearDown() {
36-
NonSystemJobSuspender.resumeInternal();
49+
ConvertJobSuspender.resumeInternal();
3750
job1.cancel();
3851
job2.cancel();
3952
}
4053

41-
@Test(expected = IllegalStateException.class)
54+
@Test
55+
public void testConvertJobClassName() {
56+
String convertJobClass =
57+
ConvertJobSuspender.CONVERT_JOB_CLASS_NAME.replace(".", "/") + ".class";
58+
Bundle jsdtWebCoreBundle = FrameworkUtil.getBundle(JsNameManglerUtil.class);
59+
assertNotNull(jsdtWebCoreBundle.getResource(convertJobClass));
60+
}
61+
62+
@Test
4263
public void testCannotSuspendConcurrently() {
43-
NonSystemJobSuspender.suspendFutureJobs();
44-
NonSystemJobSuspender.suspendFutureJobs();
64+
ConvertJobSuspender.suspendFutureConvertJobs();
65+
try {
66+
ConvertJobSuspender.suspendFutureConvertJobs();
67+
fail();
68+
} catch (IllegalStateException ex) {
69+
assertEquals("Already suspended.", ex.getMessage());
70+
}
4571
}
4672

47-
@Test(expected = IllegalStateException.class)
73+
@Test
4874
public void testCannotResumeIfNotSuspended() {
49-
NonSystemJobSuspender.resume();
75+
try {
76+
ConvertJobSuspender.resume();
77+
fail();
78+
} catch (IllegalStateException ex) {
79+
assertEquals("Not suspended.", ex.getMessage());
80+
}
5081
}
5182

5283
@Test
53-
public void testSuspendFutureJobs() {
54-
NonSystemJobSuspender.suspendFutureJobs();
84+
public void testSuspendFutureConvertJobs() {
85+
ConvertJobSuspender.suspendFutureConvertJobs();
5586
job1.schedule();
5687
job2.schedule(10000 /* ms */);
5788
assertEquals(Job.NONE, job1.getState());
@@ -62,16 +93,16 @@ public void testSuspendFutureJobs() {
6293
public void testScheduledJobsAreNotSuspended() {
6394
job1.schedule();
6495
job2.schedule(10000 /* ms */);
65-
NonSystemJobSuspender.suspendFutureJobs();
96+
ConvertJobSuspender.suspendFutureConvertJobs();
6697
assertTrue(Job.WAITING == job1.getState() || Job.RUNNING == job1.getState());
6798
assertEquals(Job.SLEEPING, job2.getState());
6899
}
69100

70101
@Test
71-
public void testSystemJobsAreNotSuspended() {
72-
NonSystemJobSuspender.suspendFutureJobs();
73-
job1.setSystem(true);
74-
job2.setSystem(true);
102+
public void testNonConvertJobsAreNotSuspended() {
103+
ConvertJobSuspender.suspendFutureConvertJobs();
104+
// Assume all test jobs are not "ConvertJob"s.
105+
ConvertJobSuspender.isConvertJob = Predicates.alwaysFalse();
75106
job1.schedule();
76107
job2.schedule(10000 /* ms */);
77108
assertTrue(Job.WAITING == job1.getState() || Job.RUNNING == job1.getState());
@@ -80,13 +111,13 @@ public void testSystemJobsAreNotSuspended() {
80111

81112
@Test
82113
public void testResume() {
83-
NonSystemJobSuspender.suspendFutureJobs();
114+
ConvertJobSuspender.suspendFutureConvertJobs();
84115
job1.schedule();
85116
job2.schedule(10000 /* ms */);
86117
assertEquals(Job.NONE, job1.getState());
87118
assertEquals(Job.NONE, job2.getState());
88119

89-
NonSystemJobSuspender.resume();
120+
ConvertJobSuspender.resume();
90121
assertTrue(Job.WAITING == job1.getState() || Job.RUNNING == job1.getState());
91122
assertEquals(Job.SLEEPING, job2.getState());
92123
}

plugins/com.google.cloud.tools.eclipse.appengine.facets/src/com/google/cloud/tools/eclipse/appengine/facets/NonSystemJobScheduleListener.java renamed to plugins/com.google.cloud.tools.eclipse.appengine.facets/src/com/google/cloud/tools/eclipse/appengine/facets/ConvertJobScheduleListener.java

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,16 @@
1717
package com.google.cloud.tools.eclipse.appengine.facets;
1818

1919
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
20-
import org.eclipse.core.runtime.jobs.IJobChangeListener;
20+
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
2121

2222
/**
23-
* For private use in {@link NonSystemJobSuspender} only. Listens for every job being scheduled
24-
* and cancels it if the suspender is active.
23+
* For private use in {@link ConvertJobSuspender} only. Listens for every job being scheduled
24+
* and cancels it if it is {@link org.eclipse.wst.jsdt.web.core.internal.project.ConvertJob} while
25+
* the suspender is active.
2526
*/
26-
class NonSystemJobScheduleListener implements IJobChangeListener {
27+
class ConvertJobScheduleListener extends JobChangeAdapter {
2728
@Override
2829
public void scheduled(IJobChangeEvent event) {
29-
NonSystemJobSuspender.suspendJob(event.getJob(), event.getDelay());
30+
ConvertJobSuspender.suspendJob(event.getJob(), event.getDelay());
3031
}
31-
32-
@Override
33-
public void aboutToRun(IJobChangeEvent event) {}
34-
35-
@Override
36-
public void awake(IJobChangeEvent event) {}
37-
38-
@Override
39-
public void done(IJobChangeEvent event) {}
40-
41-
@Override
42-
public void running(IJobChangeEvent event) {}
43-
44-
@Override
45-
public void sleeping(IJobChangeEvent event) {}
4632
}

plugins/com.google.cloud.tools.eclipse.appengine.facets/src/com/google/cloud/tools/eclipse/appengine/facets/NonSystemJobSuspender.java renamed to plugins/com.google.cloud.tools.eclipse.appengine.facets/src/com/google/cloud/tools/eclipse/appengine/facets/ConvertJobSuspender.java

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,34 @@
1818

1919
import com.google.common.annotations.VisibleForTesting;
2020
import com.google.common.base.Preconditions;
21+
import com.google.common.base.Predicate;
2122
import java.util.ArrayList;
2223
import java.util.List;
2324
import java.util.concurrent.atomic.AtomicBoolean;
25+
import java.util.logging.Level;
26+
import java.util.logging.Logger;
2427
import org.eclipse.core.runtime.jobs.Job;
2528

2629
/**
27-
* Prevents scheduling all future non-system jobs once {@link #suspendFutureJobs} is called, until
28-
* {@link #resume} is called. Jobs already scheduled are not affected and will run to completion.
30+
* Prevents scheduling all future {@link org.eclipse.wst.jsdt.web.core.internal.project.ConvertJob}s
31+
* once {@link #suspendConvertJobs} is called, until {@link #resume} is called. Jobs already
32+
* scheduled are not affected and will run to completion.
2933
*
3034
* The class is for https://github.com/GoogleCloudPlatform/google-cloud-eclipse/issues/1155. The
3135
* purpose of the class is to prevent the second ConvertJob from running. The second ConvertJob is
3236
* triggered by the first ConvertJob when the latter job installs the JSDT facet.
3337
*
3438
* Not recommended to use for other situations, although the workings of the class are general.
3539
*/
36-
class NonSystemJobSuspender {
40+
// TODO(chanseok): not needed after we drop support for Mars and Neon, as Oxygen has fixed the
41+
// issue. Remove this and related code when that happens.
42+
class ConvertJobSuspender {
43+
44+
private static final Logger logger = Logger.getLogger(ConvertJobSuspender.class.getName());
45+
46+
@VisibleForTesting
47+
static final String CONVERT_JOB_CLASS_NAME =
48+
"org.eclipse.wst.jsdt.web.core.internal.project.ConvertJob";
3749

3850
private static class SuspendedJob {
3951
private Job job;
@@ -45,15 +57,23 @@ private SuspendedJob(Job job, long scheduleDelay) {
4557
}
4658
}
4759

60+
@VisibleForTesting
61+
static Predicate<Job> isConvertJob = new Predicate<Job>() {
62+
@Override
63+
public boolean apply(Job job) {
64+
return CONVERT_JOB_CLASS_NAME.equals(job.getClass().getName());
65+
}
66+
};
67+
4868
private static final AtomicBoolean suspended = new AtomicBoolean(false);
4969

5070
private static final List<SuspendedJob> suspendedJobs = new ArrayList<>();
5171

52-
private static final NonSystemJobScheduleListener jobScheduleListener =
53-
new NonSystemJobScheduleListener();
72+
private static final ConvertJobScheduleListener jobScheduleListener =
73+
new ConvertJobScheduleListener();
5474

5575
/** Once called, it is imperative to call {@link #resume()} later. */
56-
public static void suspendFutureJobs() {
76+
public static void suspendFutureConvertJobs() {
5777
synchronized (suspendedJobs) {
5878
Preconditions.checkState(!suspended.getAndSet(true), "Already suspended.");
5979
Job.getJobManager().addJobChangeListener(jobScheduleListener);
@@ -83,7 +103,7 @@ static void resumeInternal() {
83103
}
84104

85105
static void suspendJob(Job job, long scheduleDelay) {
86-
if (job.isSystem()) {
106+
if (!isConvertJob.apply(job)) {
87107
return;
88108
}
89109
synchronized (suspendedJobs) {
@@ -104,8 +124,10 @@ static void suspendJob(Job job, long scheduleDelay) {
104124
job.schedule(scheduleDelay);
105125
}
106126
}
127+
} else {
128+
logger.log(Level.SEVERE, "job already running: " + job);
107129
}
108130
}
109131

110-
private NonSystemJobSuspender() {}
132+
private ConvertJobSuspender() {}
111133
}

plugins/com.google.cloud.tools.eclipse.appengine.facets/src/com/google/cloud/tools/eclipse/appengine/facets/StandardFacetInstallDelegate.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ private void installAppEngineRuntimes(IProject project) throws CoreException {
6464
// https://github.com/GoogleCloudPlatform/google-cloud-eclipse/issues/1155
6565
// The first ConvertJob has already been scheduled (which installs JSDT facet), and
6666
// this is to suspend the second ConvertJob temporarily.
67-
NonSystemJobSuspender.suspendFutureJobs();
67+
ConvertJobSuspender.suspendFutureConvertJobs();
6868
}
6969

7070
private static class AppEngineRuntimeInstallJob extends Job {
@@ -86,18 +86,14 @@ public boolean belongsTo(Object family) {
8686
return J2EEElementChangedListener.PROJECT_COMPONENT_UPDATE_JOB_FAMILY.equals(family);
8787
}
8888

89-
private void waitUntilJsdtIsFixedFacet() {
89+
private void waitUntilJsdtIsFixedFacet(IProgressMonitor monitor) throws InterruptedException {
9090
try {
9191
IProjectFacet jsdtFacet = ProjectFacetsManager.getProjectFacet(JSDT_FACET_ID);
92-
for (int times = 0;
93-
times < MAX_JSDT_CHECK_RETRIES && !facetedProject.isFixedProjectFacet(jsdtFacet);
94-
times++) {
95-
try {
96-
// To prevent going into the SLEEPING state, don't use "Job.schedule(100)".
97-
Thread.sleep(100 /* ms */);
98-
} catch (InterruptedException ex) {
99-
// Keep waiting.
92+
for (int times = 0; !monitor.isCanceled() && times < MAX_JSDT_CHECK_RETRIES; times++) {
93+
if (facetedProject.isFixedProjectFacet(jsdtFacet)) {
94+
return;
10095
}
96+
Thread.sleep(100 /* ms */);
10197
}
10298
} catch (IllegalArgumentException ex) {
10399
// JSDT facet itself doesn't exist. (Should not really happen.) Ignore and fall through.
@@ -109,14 +105,20 @@ protected IStatus run(IProgressMonitor monitor) {
109105
try {
110106
// https://github.com/GoogleCloudPlatform/google-cloud-eclipse/issues/1155
111107
// Wait until the first ConvertJob installs the JSDT facet.
112-
waitUntilJsdtIsFixedFacet();
108+
waitUntilJsdtIsFixedFacet(monitor);
109+
if (monitor.isCanceled()) {
110+
return Status.CANCEL_STATUS;
111+
}
113112
AppEngineStandardFacet.installAllAppEngineRuntimes(facetedProject, monitor);
114113
return Status.OK_STATUS;
114+
115115
} catch (CoreException ex) {
116116
return ex.getStatus();
117+
} catch (InterruptedException ex) {
118+
return Status.CANCEL_STATUS;
117119
} finally {
118-
// Now resume all the suspended jobs (including the second ConvertJob).
119-
NonSystemJobSuspender.resume();
120+
// Now resume the second ConvertJob.
121+
ConvertJobSuspender.resume();
120122
}
121123
}
122124
}

0 commit comments

Comments
 (0)