diff --git a/cli/pom.xml b/cli/pom.xml index 17fa61e21082187ed2be2473cce94eac11b9225c..3ee8bca64f41a899fedfbe3fe01ec42973b7c47a 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -10,6 +10,30 @@ cli Hudson CLI + + + + maven-assembly-plugin + + + + attached + + package + + jar-with-dependencies + + + hudson.cli.CLI + + + + + + + + + ${project.groupId} diff --git a/cli/src/main/java/hudson/cli/CLI.java b/cli/src/main/java/hudson/cli/CLI.java index 6f0cb710b82ea8e42784851b3c388ba5e224fc67..daa7937a1f484e68fad1b8394ad0b1497525647d 100644 --- a/cli/src/main/java/hudson/cli/CLI.java +++ b/cli/src/main/java/hudson/cli/CLI.java @@ -1,19 +1,42 @@ +/* + * The MIT License + * + * Copyright (c) 2004-2009, Sun Microsystems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package hudson.cli; -import hudson.remoting.Callable; import hudson.remoting.Channel; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.lang.reflect.Method; /** + * CLI entry point to Hudson. + * * @author Kohsuke Kawaguchi */ public class CLI { public static void main(final String[] args) throws Exception { - URL target = new URL("http://localhost:8080/duplexChannel"); + URL target = new URL("http://localhost:8080/cli"); FullDuplexHttpStream con = new FullDuplexHttpStream(target); ExecutorService pool = Executors.newCachedThreadPool(); Channel channel = new Channel("Chunked connection to "+target, @@ -22,12 +45,8 @@ public class CLI { // execute the command int r=-1; try { - r = channel.call(new Callable() { - public Integer call() throws Exception { - Method m = Class.forName("hudson.model.Hudson").getMethod("cli", String[].class); - return (Integer)m.invoke(null,new Object[]{args}); - } - }); + CliEntryPoint cli = (CliEntryPoint)channel.getRemoteProperty(CliEntryPoint.class.getName()); + r = cli.main(args); } finally { channel.close(); pool.shutdown(); diff --git a/cli/src/main/java/hudson/cli/CliEntryPoint.java b/cli/src/main/java/hudson/cli/CliEntryPoint.java new file mode 100644 index 0000000000000000000000000000000000000000..61f7d4b031905c8f61bd8ce7d42da5ae1ad40987 --- /dev/null +++ b/cli/src/main/java/hudson/cli/CliEntryPoint.java @@ -0,0 +1,36 @@ +/* + * The MIT License + * + * Copyright (c) 2004-2009, Sun Microsystems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package hudson.cli; + +/** + * Remotable interface for CLI entry point on the server side. + * + * @author Kohsuke Kawaguchi + */ +public interface CliEntryPoint { + /** + * Just like the static main method. + */ + int main(String[] args); +} diff --git a/core/pom.xml b/core/pom.xml index 44a74ada7e9ed4c57ae8c6297dc4ea798e664440..4741c327cc393ac5e7f815ec755e341e3b91afed 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -297,10 +297,15 @@ THE SOFTWARE. - org.jvnet.hudson.main + ${project.groupId} remoting ${project.version} + + ${project.groupId} + cli + ${project.version} + org.jvnet.hudson jtidy diff --git a/core/src/main/java/hudson/model/FullDuplexHttpChannel.java b/core/src/main/java/hudson/model/FullDuplexHttpChannel.java index 2dd17eab730789ceac520c6868ce5b0002e02598..b77cb9406746b6ec1bcf4ff4ee11696128077111 100644 --- a/core/src/main/java/hudson/model/FullDuplexHttpChannel.java +++ b/core/src/main/java/hudson/model/FullDuplexHttpChannel.java @@ -1,3 +1,26 @@ +/* + * The MIT License + * + * Copyright (c) 2004-2009, Sun Microsystems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package hudson.model; import hudson.remoting.Channel; @@ -19,7 +42,7 @@ import java.util.logging.Logger; * * @author Kohsuke Kawaguchi */ -final class FullDuplexHttpChannel { +abstract class FullDuplexHttpChannel { private Channel channel; private final PipedOutputStream pipe = new PipedOutputStream(); @@ -62,10 +85,13 @@ final class FullDuplexHttpChannel { } }; ping.start(); + main(channel); channel.join(); ping.interrupt(); } + protected abstract void main(Channel channel) throws IOException, InterruptedException; + /** * This is where we receive inputs from the client. */ diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java index 7623c089a65e9235e53086725d95c10267a231dd..f3b3f9a21166ccacec4fe5fc9abe96882ae8bb80 100644 --- a/core/src/main/java/hudson/model/Hudson.java +++ b/core/src/main/java/hudson/model/Hudson.java @@ -44,6 +44,7 @@ import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.DescriptorExtensionList; import hudson.ExtensionListView; +import hudson.cli.CliEntryPoint; import hudson.logging.LogRecorderManager; import hudson.lifecycle.Lifecycle; import hudson.model.Descriptor.FormException; @@ -147,6 +148,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.InputStream; +import java.io.Serializable; import java.net.URL; import java.security.SecureRandom; import java.text.NumberFormat; @@ -2651,12 +2653,25 @@ public final class Hudson extends Node implements ItemGroup, Stapl rsp.getWriter().println("GCed"); } + /** + * {@link CliEntryPoint} implementation exposed to the remote CLI. + */ + private final class CliManager implements CliEntryPoint, Serializable { + public int main(String[] args) { + System.out.println(Arrays.asList(args)); + return 0; + } + private Object writeReplace() { + return Channel.current().export(CliEntryPoint.class,this); + } + } + private transient final Map duplexChannels = new HashMap(); /** - * Handles HTTP requests for duplex channels. + * Handles HTTP requests for duplex channels for CLI. */ - public void doDuplexChannel(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException { + public void doCli(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException { checkPermission(READ); requirePOST(); @@ -2664,7 +2679,11 @@ public final class Hudson extends Node implements ItemGroup, Stapl FullDuplexHttpChannel server; if(req.getHeader("Side").equals("download")) { - duplexChannels.put(uuid,server=new FullDuplexHttpChannel(uuid, !hasPermission(ADMINISTER))); + duplexChannels.put(uuid,server=new FullDuplexHttpChannel(uuid, !hasPermission(ADMINISTER)) { + protected void main(Channel channel) throws IOException, InterruptedException { + channel.setProperty(CliEntryPoint.class.getName(),new CliManager()); + } + }); try { server.download(req,rsp); } finally { @@ -2675,14 +2694,6 @@ public final class Hudson extends Node implements ItemGroup, Stapl } } - /** - * Called by the CLI over a {@link Channel} to execute an CLI command. - */ - public static int cli(String... args) { - System.out.println(Arrays.asList(args)); - return 0; - } - /** * Binds /userContent/... to $HUDSON_HOME/userContent. */ diff --git a/remoting/src/main/java/hudson/remoting/Channel.java b/remoting/src/main/java/hudson/remoting/Channel.java index 9ec029faf7d2ddb029cc6eb205b542afec0bee29..e881095b8599923401dfaa758ed6dcd86db42829 100644 --- a/remoting/src/main/java/hudson/remoting/Channel.java +++ b/remoting/src/main/java/hudson/remoting/Channel.java @@ -97,7 +97,7 @@ import java.net.URL; * * @author Kohsuke Kawaguchi */ -public class Channel implements VirtualChannel { +public class Channel implements VirtualChannel, IChannel { private final ObjectInputStream ois; private final ObjectOutputStream oos; private final String name; @@ -173,6 +173,16 @@ public class Channel implements VirtualChannel { */ public final AtomicInteger resourceLoadingCount = new AtomicInteger(); + /** + * Property bag that contains application-specific stuff. + */ + private final Hashtable properties = new Hashtable(); + + /** + * Proxy to the remote {@link Channel} object. + */ + private IChannel remoteChannel; + /** * Communication mode. * @since 1.161 @@ -276,6 +286,10 @@ public class Channel implements VirtualChannel { this.isRestricted = restricted; ObjectOutputStream oos = null; + if(export(this,false)!=1) + throw new AssertionError(); // export number 1 is reserved for the channel itself + remoteChannel = RemoteInvocationHandler.wrap(this,1,IChannel.class,false); + // write the magic preamble. // certain communication channel, such as forking JVM via ssh, // may produce some garbage at the beginning (for example a remote machine @@ -662,6 +676,27 @@ public class Channel implements VirtualChannel { // termination is done by CloseCommand when we received it. } + /** + * Gets the application specific property set by {@link #setProperty(Object, Object)}. + * These properties are also accessible from the remote channel via {@link #getRemoteProperty(Object)}. + * + *

+ * This mechanism can be used for one side to discover contextual objects created by the other JVM + * (as opposed to executing {@link Callable}, which cannot have any reference to the context + * of the remote {@link Channel}. + */ + public Object getProperty(Object key) { + return properties.get(key); + } + + public Object setProperty(Object key, Object value) { + return properties.put(key,value); + } + + public Object getRemoteProperty(Object key) { + return remoteChannel.getProperty(key); + } + public String toString() { return super.toString()+":"+name; } diff --git a/remoting/src/main/java/hudson/remoting/IChannel.java b/remoting/src/main/java/hudson/remoting/IChannel.java new file mode 100644 index 0000000000000000000000000000000000000000..cfe7073585f84b80f4c8fa38e6595560d7463021 --- /dev/null +++ b/remoting/src/main/java/hudson/remoting/IChannel.java @@ -0,0 +1,33 @@ +/* + * The MIT License + * + * Copyright (c) 2004-2009, Sun Microsystems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package hudson.remoting; + +/** + * Internally used to mark methods on {@link Channel} that are exported to remote. + * + * @author Kohsuke Kawaguchi + */ +interface IChannel { + Object getProperty(Object key); +}