All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.remoting.Pipe Maven / Gradle / Ivy

/*
 * The MIT License
 * 
 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
 * 
 * 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;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Pipe for the remote {@link Callable} and the local program to talk to each other.
 *
 * 

* There are two kinds of pipes. One is for having a local system write to a remote system, * and the other is for having a remote system write to a local system. Use * the different versions of the create method to create the appropriate kind * of pipes. * *

* Once created, {@link Pipe} can be sent to the remote system as a part of a serialization of * {@link Callable} between {@link Channel}s. * Once re-instantiated on the remote {@link Channel}, pipe automatically connects * back to the local instance and perform necessary set up. * *

* The local and remote system can then call {@link #getIn()} and {@link #getOut()} to * read/write bytes. * *

* Pipe can be only written by one system and read by the other system. It is an error to * send one {@link Pipe} to two remote {@link Channel}s, or send one {@link Pipe} to * the same {@link Channel} twice. * *

Usage

*
 * final Pipe p = Pipe.createLocalToRemote();
 *
 * channel.callAsync(new Callable() {
 *   public Object call() {
 *     InputStream in = p.getIn();
 *     ... read from in ...
 *   }
 * });
 *
 * OutputStream out = p.getOut();
 * ... write to out ...
 * 
* *

Implementation Note

*

* For better performance, {@link Pipe} uses lower-level {@link Command} abstraction * to send data, instead of typed proxy object. This allows the writer to send data * without blocking until the arrival of the data is confirmed. * * @author Kohsuke Kawaguchi */ public final class Pipe implements Serializable { private InputStream in; private OutputStream out; private Pipe(InputStream in, OutputStream out) { this.in = in; this.out = out; } /** * Gets the reading end of the pipe. */ public InputStream getIn() { return in; } /** * Gets the writing end of the pipe. */ public OutputStream getOut() { return out; } /** * Creates a {@link Pipe} that allows remote system to write and local system to read. */ public static Pipe createRemoteToLocal() { // OutputStream will be created on the target return new Pipe(new FastPipedInputStream(),null); } /** * Creates a {@link Pipe} that allows local system to write and remote system to read. */ public static Pipe createLocalToRemote() { return new Pipe(null,new ProxyOutputStream()); } private void writeObject(ObjectOutputStream oos) throws IOException { if(in!=null && out==null) { // remote will write to local FastPipedOutputStream pos = new FastPipedOutputStream((FastPipedInputStream)in); int oid = Channel.current().export(pos,false); // this export is unexported in ProxyOutputStream.finalize() oos.writeBoolean(true); // marker oos.writeInt(oid); } else { // remote will read from local int oid = Channel.current().export(out); oos.writeBoolean(false); oos.writeInt(oid); } } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { final Channel channel = Channel.current(); assert channel !=null; if(ois.readBoolean()) { // local will write to remote in = null; out = new ProxyOutputStream(channel, ois.readInt()); } else { // local will read from remote. // tell the remote system about this local read pipe // this is the OutputStream that wants to send data to us final int oidRos = ois.readInt(); // we want 'oidRos' to send data to this PipedOutputStream FastPipedOutputStream pos = new FastPipedOutputStream(); FastPipedInputStream pis = new FastPipedInputStream(pos); final int oidPos = channel.export(pos); // tell 'ros' to connect to our 'pos'. channel.send(new ConnectCommand(oidRos, oidPos)); out = null; in = pis; } } private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(Pipe.class.getName()); private static class ConnectCommand extends Command { private final int oidRos; private final int oidPos; public ConnectCommand(int oidRos, int oidPos) { this.oidRos = oidRos; this.oidPos = oidPos; } protected void execute(final Channel channel) { channel.pipeWriter.submit(new Runnable() { public void run() { try { final ProxyOutputStream ros = (ProxyOutputStream) channel.getExportedObject(oidRos); channel.unexport(oidRos); ros.connect(channel, oidPos); } catch (IOException e) { logger.log(Level.SEVERE,"Failed to connect to pipe",e); } } }); } static final long serialVersionUID = -9128735897846418140L; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy