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

hudson.remoting.Pipe Maven / Gradle / Ivy

Go to download

Contains the bootstrap code to bridge separate JVMs into a single semi-shared space. Reusable outside Hudson.

There is a newer version: 3.0.3
Show newest version
/*******************************************************************************
 *
 * Copyright (c) 2004-2009 Oracle Corporation.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors: 
*
*    Kohsuke Kawaguchi
 *     
 *
 *******************************************************************************/ 

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