From b7bf0d8780274a6c99e1cf9076393665c07cfdc0 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sat, 16 Jan 2021 20:19:37 +0000 Subject: [PATCH 01/10] Upgrade guava --- .mvn/extensions.xml | 2 +- pom.xml | 9 +++++---- .../plugins/workflow/flow/FlowExecutionList.java | 5 +++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index a2d496cc..43d62816 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -2,6 +2,6 @@ io.jenkins.tools.incrementals git-changelist-maven-extension - 1.0-beta-4 + 1.2 diff --git a/pom.xml b/pom.xml index 8931f113..1d135ecb 100644 --- a/pom.xml +++ b/pom.xml @@ -44,9 +44,9 @@ - scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git - scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git - https://github.com/jenkinsci/${project.artifactId}-plugin + scm:git:git://github.com/${gitHubRepo}.git + scm:git:git@github.com:${gitHubRepo}.git + https://github.com/${gitHubRepo} ${scmTag} @@ -64,10 +64,11 @@ 2.41 -SNAPSHOT - 2.176.4 + 2.273-rc30689.09147672b85b 8 false true + jenkinsci/${project.artifactId}-plugin diff --git a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java index e33661d1..fb1a6298 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java @@ -5,6 +5,7 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; import com.google.inject.Inject; import hudson.Extension; import hudson.ExtensionList; @@ -194,7 +195,7 @@ public void onFailure(Throwable t) { LOGGER.log(WARNING, "Failed to load " + e, t); } } - }); + }, MoreExecutors.newDirectExecutorService()); } } } @@ -230,7 +231,7 @@ public void onSuccess(List result) { public void onFailure(Throwable t) { LOGGER.log(Level.WARNING, null, t); } - }); + }, MoreExecutors.newDirectExecutorService()); } return Futures.allAsList(all); From ec8ea590edcc4d8cf879059dfa41d498a9351438 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sat, 16 Jan 2021 21:08:09 +0000 Subject: [PATCH 02/10] Add trilead dep for ArtifactManagerTest --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 1d135ecb..1a8ead95 100644 --- a/pom.xml +++ b/pom.xml @@ -105,6 +105,11 @@ workflow-basic-steps test + + org.jenkins-ci.plugins + trilead-api + test + org.jenkins-ci.plugins.workflow From 564ca438a6ec127232766a3d8633848bb6a0a521 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sun, 17 Jan 2021 10:32:13 +0000 Subject: [PATCH 03/10] Update workflow-support --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 1a8ead95..14e04fc4 100644 --- a/pom.xml +++ b/pom.xml @@ -116,6 +116,7 @@ workflow-support tests test + 3.8-SNAPSHOT org.jenkins-ci.plugins From 284918f931753f53d789270809834243b394ed97 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sat, 6 Feb 2021 16:19:28 +0000 Subject: [PATCH 04/10] Spotbugs fixes --- pom.xml | 13 ++++++++++++ .../workflow/flow/FlowExecutionList.java | 20 +++++++++++-------- .../workflow/graphanalysis/ForkScanner.java | 2 +- .../graphanalysis/NodeStepNamePredicate.java | 2 +- .../graphanalysis/NodeStepTypePredicate.java | 2 +- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index 6e62dab2..5f10a464 100644 --- a/pom.xml +++ b/pom.xml @@ -140,4 +140,17 @@ test + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + true + + + + diff --git a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java index fb1a6298..f70c77de 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java @@ -181,9 +181,11 @@ public void onLoaded() { Futures.addCallback(e.getCurrentExecutions(false), new FutureCallback>() { @Override public void onSuccess(List result) { - LOGGER.log(FINE, "Will resume {0}", result); - for (StepExecution se : result) { - se.onResume(); + if (result != null) { + LOGGER.log(FINE, "Will resume {0}", result); + for (StepExecution se : result) { + se.onResume(); + } } } @@ -218,11 +220,13 @@ public ListenableFuture apply(final Function f) { Futures.addCallback(execs,new FutureCallback>() { @Override public void onSuccess(List result) { - for (StepExecution e : result) { - try { - f.apply(e); - } catch (RuntimeException x) { - LOGGER.log(Level.WARNING, null, x); + if (result != null) { + for (StepExecution e : result) { + try { + f.apply(e); + } catch (RuntimeException x) { + LOGGER.log(Level.WARNING, null, x); + } } } } diff --git a/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/ForkScanner.java b/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/ForkScanner.java index b161deb1..322fd8d4 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/ForkScanner.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/ForkScanner.java @@ -26,6 +26,7 @@ import com.google.common.base.Predicate; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import org.checkerframework.checker.nullness.qual.Nullable; import org.jenkinsci.plugins.workflow.actions.ThreadNameAction; import org.jenkinsci.plugins.workflow.actions.TimingAction; import org.jenkinsci.plugins.workflow.graph.BlockEndNode; @@ -36,7 +37,6 @@ import javax.annotation.CheckForNull; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; import java.util.ArrayDeque; import java.util.ArrayList; diff --git a/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepNamePredicate.java b/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepNamePredicate.java index 9890a8e1..b4ae91bd 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepNamePredicate.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepNamePredicate.java @@ -24,6 +24,7 @@ package org.jenkinsci.plugins.workflow.graphanalysis; import com.google.common.base.Predicate; +import org.checkerframework.checker.nullness.qual.Nullable; import org.jenkinsci.plugins.workflow.graph.FlowEndNode; import org.jenkinsci.plugins.workflow.graph.FlowNode; import org.jenkinsci.plugins.workflow.graph.FlowStartNode; @@ -31,7 +32,6 @@ import org.jenkinsci.plugins.workflow.steps.StepDescriptor; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; diff --git a/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepTypePredicate.java b/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepTypePredicate.java index c7ae8d7b..472504e5 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepTypePredicate.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepTypePredicate.java @@ -24,6 +24,7 @@ package org.jenkinsci.plugins.workflow.graphanalysis; import com.google.common.base.Predicate; +import org.checkerframework.checker.nullness.qual.Nullable; import org.jenkinsci.plugins.workflow.graph.FlowEndNode; import org.jenkinsci.plugins.workflow.graph.FlowNode; import org.jenkinsci.plugins.workflow.graph.FlowStartNode; @@ -31,7 +32,6 @@ import org.jenkinsci.plugins.workflow.steps.StepDescriptor; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; From 31acbeec2e2edded63436f0581eed6ee8d11600b Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sat, 6 Feb 2021 16:26:40 +0000 Subject: [PATCH 05/10] Downgrade workflow-support for noW --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f10a464..5e548f94 100644 --- a/pom.xml +++ b/pom.xml @@ -116,7 +116,6 @@ workflow-support tests test - 3.8-SNAPSHOT org.jenkins-ci.plugins From 8d974b8c4ed505d354f292da8dacc4e9a28bbf23 Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Sat, 6 Feb 2021 16:36:25 +0000 Subject: [PATCH 06/10] Tweak settings --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5e548f94..2e351f07 100644 --- a/pom.xml +++ b/pom.xml @@ -147,7 +147,8 @@ maven-surefire-plugin - true + + InjectedTest From c363cc8b4c9adef22fa9a238f2b272dc88f16733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mu=C3=B1iz?= Date: Thu, 4 Mar 2021 17:29:03 +0100 Subject: [PATCH 07/10] Fallback to old guava API if needed and avoid core bump --- pom.xml | 21 +-------- .../workflow/flow/FlowExecutionList.java | 47 +++++++++++++------ .../workflow/graphanalysis/ForkScanner.java | 2 +- .../graphanalysis/NodeStepNamePredicate.java | 2 +- .../graphanalysis/NodeStepTypePredicate.java | 2 +- 5 files changed, 37 insertions(+), 37 deletions(-) diff --git a/pom.xml b/pom.xml index 2e351f07..e6e28a3e 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 2.42 -SNAPSHOT - 2.273-rc30689.09147672b85b + 2.176.4 8 false true @@ -105,11 +105,6 @@ workflow-basic-steps test - - org.jenkins-ci.plugins - trilead-api - test - org.jenkins-ci.plugins.workflow @@ -139,18 +134,4 @@ test - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - - InjectedTest - - - - diff --git a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java index f70c77de..cb80b72b 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java @@ -21,10 +21,13 @@ import java.io.File; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -181,11 +184,9 @@ public void onLoaded() { Futures.addCallback(e.getCurrentExecutions(false), new FutureCallback>() { @Override public void onSuccess(List result) { - if (result != null) { - LOGGER.log(FINE, "Will resume {0}", result); - for (StepExecution se : result) { - se.onResume(); - } + LOGGER.log(FINE, "Will resume {0}", result); + for (StepExecution se : result) { + se.onResume(); } } @@ -197,7 +198,7 @@ public void onFailure(Throwable t) { LOGGER.log(WARNING, "Failed to load " + e, t); } } - }, MoreExecutors.newDirectExecutorService()); + }, newExecutorService()); } } } @@ -220,13 +221,11 @@ public ListenableFuture apply(final Function f) { Futures.addCallback(execs,new FutureCallback>() { @Override public void onSuccess(List result) { - if (result != null) { - for (StepExecution e : result) { - try { - f.apply(e); - } catch (RuntimeException x) { - LOGGER.log(Level.WARNING, null, x); - } + for (StepExecution e : result) { + try { + f.apply(e); + } catch (RuntimeException x) { + LOGGER.log(Level.WARNING, null, x); } } } @@ -235,7 +234,7 @@ public void onSuccess(List result) { public void onFailure(Throwable t) { LOGGER.log(Level.WARNING, null, t); } - }, MoreExecutors.newDirectExecutorService()); + }, newExecutorService()); } return Futures.allAsList(all); @@ -259,4 +258,24 @@ public void onFailure(Throwable t) { executor.awaitTermination(1, TimeUnit.MINUTES); } + /** + * Returns an {@link ExecutorService} to be used as a parameter in other methods. + * It calls {@code MoreExecutors#newDirectExecutorService} or falls back to {@code MoreExecutors#sameThreadExecutor} + * for compatibility with older (< 18.0) versions of guava. + */ + private static ExecutorService newExecutorService() { + try { + try { + Method method = MoreExecutors.class.getMethod("newDirectExecutorService"); + return (ExecutorService) method.invoke(null); + } catch (NoSuchMethodException e) { + // guava older than 18, fallback to `sameThreadExecutor` + Method method = MoreExecutors.class.getMethod("sameThreadExecutor"); + return (ExecutorService) method.invoke(null); + } + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e ) { + throw new RuntimeException(e); + } + } + } diff --git a/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/ForkScanner.java b/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/ForkScanner.java index 322fd8d4..b161deb1 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/ForkScanner.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/ForkScanner.java @@ -26,7 +26,6 @@ import com.google.common.base.Predicate; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import org.checkerframework.checker.nullness.qual.Nullable; import org.jenkinsci.plugins.workflow.actions.ThreadNameAction; import org.jenkinsci.plugins.workflow.actions.TimingAction; import org.jenkinsci.plugins.workflow.graph.BlockEndNode; @@ -37,6 +36,7 @@ import javax.annotation.CheckForNull; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; import java.util.ArrayDeque; import java.util.ArrayList; diff --git a/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepNamePredicate.java b/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepNamePredicate.java index b4ae91bd..9890a8e1 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepNamePredicate.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepNamePredicate.java @@ -24,7 +24,6 @@ package org.jenkinsci.plugins.workflow.graphanalysis; import com.google.common.base.Predicate; -import org.checkerframework.checker.nullness.qual.Nullable; import org.jenkinsci.plugins.workflow.graph.FlowEndNode; import org.jenkinsci.plugins.workflow.graph.FlowNode; import org.jenkinsci.plugins.workflow.graph.FlowStartNode; @@ -32,6 +31,7 @@ import org.jenkinsci.plugins.workflow.steps.StepDescriptor; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; diff --git a/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepTypePredicate.java b/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepTypePredicate.java index 472504e5..c7ae8d7b 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepTypePredicate.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/NodeStepTypePredicate.java @@ -24,7 +24,6 @@ package org.jenkinsci.plugins.workflow.graphanalysis; import com.google.common.base.Predicate; -import org.checkerframework.checker.nullness.qual.Nullable; import org.jenkinsci.plugins.workflow.graph.FlowEndNode; import org.jenkinsci.plugins.workflow.graph.FlowNode; import org.jenkinsci.plugins.workflow.graph.FlowStartNode; @@ -32,6 +31,7 @@ import org.jenkinsci.plugins.workflow.steps.StepDescriptor; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; From d6bfed6bb5f9e60614d1119b9ae217a8e19da20d Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Mon, 8 Mar 2021 08:03:00 +0000 Subject: [PATCH 08/10] Re-upgrade core and invert fallback code --- pom.xml | 6 +++--- .../plugins/workflow/flow/FlowExecutionList.java | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index e6e28a3e..861ceb33 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 2.42 -SNAPSHOT - 2.176.4 + 2.222.4 8 false true @@ -74,8 +74,8 @@ io.jenkins.tools.bom - bom-2.176.x - 16 + bom-2.222.x + 25 import pom diff --git a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java index cb80b72b..2fd29383 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java @@ -260,17 +260,18 @@ public void onFailure(Throwable t) { /** * Returns an {@link ExecutorService} to be used as a parameter in other methods. - * It calls {@code MoreExecutors#newDirectExecutorService} or falls back to {@code MoreExecutors#sameThreadExecutor} - * for compatibility with older (< 18.0) versions of guava. + * It calls {@code MoreExecutors#sameThreadExecutor} or falls back to {@code MoreExecutors#newDirectExecutorService} + * for compatibility with newer (> 18.0) versions of guava. */ private static ExecutorService newExecutorService() { try { try { - Method method = MoreExecutors.class.getMethod("newDirectExecutorService"); + // guava older than 18 + Method method = MoreExecutors.class.getMethod("sameThreadExecutor"); return (ExecutorService) method.invoke(null); } catch (NoSuchMethodException e) { - // guava older than 18, fallback to `sameThreadExecutor` - Method method = MoreExecutors.class.getMethod("sameThreadExecutor"); + // TODO invert this to prefer the newer guava method once guava is upgraded in Jenkins core + Method method = MoreExecutors.class.getMethod("newDirectExecutorService"); return (ExecutorService) method.invoke(null); } } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e ) { From d0626eb4da04048f067645fa0b78a640ca0caca3 Mon Sep 17 00:00:00 2001 From: Tim Jacomb <21194782+timja@users.noreply.github.com> Date: Mon, 8 Mar 2021 13:53:45 +0000 Subject: [PATCH 09/10] Update src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java --- .../org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java index 2fd29383..9f36c94e 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java @@ -270,7 +270,7 @@ private static ExecutorService newExecutorService() { Method method = MoreExecutors.class.getMethod("sameThreadExecutor"); return (ExecutorService) method.invoke(null); } catch (NoSuchMethodException e) { - // TODO invert this to prefer the newer guava method once guava is upgraded in Jenkins core + // TODO invert this to prefer the newer guava method once guava is upgraded in Jenkins core, (or update jenkins.version) Method method = MoreExecutors.class.getMethod("newDirectExecutorService"); return (ExecutorService) method.invoke(null); } From c8e40e3439dbdd7ae389ce775d5b74fac2bc787b Mon Sep 17 00:00:00 2001 From: Tim Jacomb Date: Mon, 15 Mar 2021 08:58:30 +0000 Subject: [PATCH 10/10] Vendor guava classes from 30.1 --- .../plugins/workflow/flow/DirectExecutor.java | 40 +++++++++ .../workflow/flow/FlowExecutionList.java | 30 +------ .../plugins/workflow/flow/MoreExecutors.java | 88 +++++++++++++++++++ 3 files changed, 130 insertions(+), 28 deletions(-) create mode 100644 src/main/java/org/jenkinsci/plugins/workflow/flow/DirectExecutor.java create mode 100644 src/main/java/org/jenkinsci/plugins/workflow/flow/MoreExecutors.java diff --git a/src/main/java/org/jenkinsci/plugins/workflow/flow/DirectExecutor.java b/src/main/java/org/jenkinsci/plugins/workflow/flow/DirectExecutor.java new file mode 100644 index 00000000..fdf1532a --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/workflow/flow/DirectExecutor.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.jenkinsci.plugins.workflow.flow; + +import com.google.common.annotations.GwtCompatible; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import java.util.concurrent.Executor; + +/** + * An {@link Executor} that runs each task in the thread that invokes {@link Executor#execute + * execute}. + */ +@GwtCompatible +@Restricted(NoExternalUse.class) +enum DirectExecutor implements Executor { + INSTANCE; + + @Override + public void execute(Runnable command) { + command.run(); + } + + @Override + public String toString() { + return "MoreExecutors.directExecutor()"; + } +} \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java index 2fd29383..0e20f266 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/flow/FlowExecutionList.java @@ -5,7 +5,6 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.MoreExecutors; import com.google.inject.Inject; import hudson.Extension; import hudson.ExtensionList; @@ -21,13 +20,10 @@ import java.io.File; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -198,7 +194,7 @@ public void onFailure(Throwable t) { LOGGER.log(WARNING, "Failed to load " + e, t); } } - }, newExecutorService()); + }, MoreExecutors.directExecutor()); } } } @@ -234,7 +230,7 @@ public void onSuccess(List result) { public void onFailure(Throwable t) { LOGGER.log(Level.WARNING, null, t); } - }, newExecutorService()); + }, MoreExecutors.directExecutor()); } return Futures.allAsList(all); @@ -257,26 +253,4 @@ public void onFailure(Throwable t) { executor.shutdown(); executor.awaitTermination(1, TimeUnit.MINUTES); } - - /** - * Returns an {@link ExecutorService} to be used as a parameter in other methods. - * It calls {@code MoreExecutors#sameThreadExecutor} or falls back to {@code MoreExecutors#newDirectExecutorService} - * for compatibility with newer (> 18.0) versions of guava. - */ - private static ExecutorService newExecutorService() { - try { - try { - // guava older than 18 - Method method = MoreExecutors.class.getMethod("sameThreadExecutor"); - return (ExecutorService) method.invoke(null); - } catch (NoSuchMethodException e) { - // TODO invert this to prefer the newer guava method once guava is upgraded in Jenkins core - Method method = MoreExecutors.class.getMethod("newDirectExecutorService"); - return (ExecutorService) method.invoke(null); - } - } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e ) { - throw new RuntimeException(e); - } - } - } diff --git a/src/main/java/org/jenkinsci/plugins/workflow/flow/MoreExecutors.java b/src/main/java/org/jenkinsci/plugins/workflow/flow/MoreExecutors.java new file mode 100644 index 00000000..86e05657 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/workflow/flow/MoreExecutors.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.jenkinsci.plugins.workflow.flow; + +import com.google.common.annotations.GwtCompatible; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy; + +/** + * Factory and utility methods for {@link java.util.concurrent.Executor}, {@link ExecutorService}, + * and {@link java.util.concurrent.ThreadFactory}. + * + * @author Eric Fellheimer + * @author Kyle Littlefield + * @author Justin Mahoney + * @since 3.0 + */ +@GwtCompatible(emulated = true) +@Restricted(NoExternalUse.class) +public final class MoreExecutors { + private MoreExecutors() {} + + /** + * Returns an {@link Executor} that runs each task in the thread that invokes {@link + * Executor#execute execute}, as in {@code ThreadPoolExecutor.CallerRunsPolicy}. + * + *

This executor is appropriate for tasks that are lightweight and not deeply chained. + * Inappropriate {@code directExecutor} usage can cause problems, and these problems can be + * difficult to reproduce because they depend on timing. For example: + * + *

    + *
  • A call like {@code future.transform(function, directExecutor())} may execute the function + * immediately in the thread that is calling {@code transform}. (This specific case happens + * if the future is already completed.) If {@code transform} call was made from a UI thread + * or other latency-sensitive thread, a heavyweight function can harm responsiveness. + *
  • If the task will be executed later, consider which thread will trigger the execution -- + * since that thread will execute the task inline. If the thread is a shared system thread + * like an RPC network thread, a heavyweight task can stall progress of the whole system or + * even deadlock it. + *
  • If many tasks will be triggered by the same event, one heavyweight task may delay other + * tasks -- even tasks that are not themselves {@code directExecutor} tasks. + *
  • If many such tasks are chained together (such as with {@code + * future.transform(...).transform(...).transform(...)....}), they may overflow the stack. + * (In simple cases, callers can avoid this by registering all tasks with the same {@code + * MoreExecutors#newSequentialExecutor} wrapper around {@code directExecutor()}. More + * complex cases may require using thread pools or making deeper changes.) + *
+ * + * Additionally, beware of executing tasks with {@code directExecutor} while holding a lock. Since + * the task you submit to the executor (or any other arbitrary work the executor does) may do slow + * work or acquire other locks, you risk deadlocks. + * + *

This instance is equivalent to: + * + *

{@code
+   * final class DirectExecutor implements Executor {
+   *   public void execute(Runnable r) {
+   *     r.run();
+   *   }
+   * }
+   * }
+ * + *

This should be preferred to {@code #newDirectExecutorService()} because implementing the + * {@link ExecutorService} subinterface necessitates significant performance overhead. + * + * + * @since 18.0 + */ + public static Executor directExecutor() { + return DirectExecutor.INSTANCE; + } +} \ No newline at end of file