diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 773405acf2..95c523099e 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -28,7 +28,6 @@ package hudson; import hudson.Launcher.LocalLauncher; import hudson.Launcher.RemoteLauncher; import hudson.model.AbstractDescribableImpl; -import hudson.model.Descriptor; import jenkins.model.Jenkins; import hudson.model.TaskListener; import hudson.model.AbstractProject; @@ -831,8 +830,8 @@ public final class FilePath implements Serializable { // run this on a remote system try { DelegatingCallable wrapper = new FileCallableWrapper(callable, cl); - ExtensionList factories = Jenkins.getInstance().getExtensionList(AroundInvokeFactory.class); - for (AroundInvokeFactory factory : factories) { + ExtensionList factories = Jenkins.getInstance().getExtensionList(FileCallableWrapperFactory.class); + for (FileCallableWrapperFactory factory : factories) { wrapper = factory.wrap(wrapper); } @@ -851,12 +850,46 @@ public final class FilePath implements Serializable { } } - public static abstract class AroundInvokeFactory extends AbstractDescribableImpl implements ExtensionPoint { + /** + * This extension point allows to contribute a wrapper around a fileCallable so that a plugin can "intercept" a + * call. Code in wrapper will be executed on remote. + */ + public static abstract class FileCallableWrapperFactory extends AbstractDescribableImpl implements ExtensionPoint { public abstract DelegatingCallable wrap(DelegatingCallable callable); } + /** + * Abstract {@link DelegatingCallable} that exposes an Before/After pattern for + * {@link hudson.FilePath.FileCallableWrapperFactory} that want to implement AOP-style interceptors + */ + public abstract class AbstractInterceptorCallableWrapper implements DelegatingCallable { + + protected DelegatingCallable callable; + + public AbstractInterceptorCallableWrapper(DelegatingCallable callable) { + this.callable = callable; + } + + public ClassLoader getClassLoader() { + return callable.getClassLoader(); + } + + public T call() throws IOException { + before(); + try { + return callable.call(); + } finally { + after(); + } + } + + protected void before() {} + protected void after() {} + } + + /** * Executes some program on the machine that this {@link FilePath} exists, * so that one can perform local file operations. @@ -2211,7 +2244,6 @@ public final class FilePath implements Serializable { public T call() throws IOException { try { - Channel.current(). return callable.invoke(new File(remote), Channel.current()); } catch (InterruptedException e) { throw new TunneledInterruptedException(e);