KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > hudson > remoting > Pipe


1 package hudson.remoting;
2
3 import java.io.IOException JavaDoc;
4 import java.io.InputStream JavaDoc;
5 import java.io.ObjectInputStream JavaDoc;
6 import java.io.ObjectOutputStream JavaDoc;
7 import java.io.OutputStream JavaDoc;
8 import java.io.PipedInputStream JavaDoc;
9 import java.io.PipedOutputStream JavaDoc;
10 import java.io.Serializable JavaDoc;
11 import java.util.logging.Level JavaDoc;
12 import java.util.logging.Logger JavaDoc;
13
14 /**
15  * Pipe for the remote {@link Callable} and the local program to talk to each other.
16  *
17  * <p>
18  * There are two kinds of pipes. One is for having a local system write to a remote system,
19  * and the other is for having a remote system write to a local system. Use
20  * the different versions of the <tt>create</tt> method to create the appropriate kind
21  * of pipes.
22  *
23  * <p>
24  * Once created, {@link Pipe} can be sent to the remote system as a part of a serialization of
25  * {@link Callable} between {@link Channel}s.
26  * Once re-instantiated on the remote {@link Channel}, pipe automatically connects
27  * back to the local instance and perform necessary set up.
28  *
29  * <p>
30  * The local and remote system can then call {@link #getIn()} and {@link #getOut()} to
31  * read/write bytes.
32  *
33  * <p>
34  * Pipe can be only written by one system and read by the other system. It is an error to
35  * send one {@link Pipe} to two remote {@link Channel}s, or send one {@link Pipe} to
36  * the same {@link Channel} twice.
37  *
38  * <h2>Usage</h2>
39  * <pre>
40  * final Pipe p = Pipe.createLocalToRemote();
41  *
42  * channel.callAsync(new Callable() {
43  * public Object call() {
44  * InputStream in = p.getIn();
45  * ... read from in ...
46  * }
47  * });
48  *
49  * OutputStream out = p.getOut();
50  * ... write to out ...
51  * </pre>
52  *
53  * <h2>Implementation Note</h2>
54  * <p>
55  * For better performance, {@link Pipe} uses lower-level {@link Command} abstraction
56  * to send data, instead of typed proxy object. This allows the writer to send data
57  * without blocking until the arrival of the data is confirmed.
58  *
59  * @author Kohsuke Kawaguchi
60  */

61 public final class Pipe implements Serializable JavaDoc {
62     private InputStream JavaDoc in;
63     private OutputStream JavaDoc out;
64
65     private Pipe(InputStream JavaDoc in, OutputStream JavaDoc out) {
66         this.in = in;
67         this.out = out;
68     }
69
70     /**
71      * Gets the reading end of the pipe.
72      */

73     public InputStream JavaDoc getIn() {
74         return in;
75     }
76
77     /**
78      * Gets the writing end of the pipe.
79      */

80     public OutputStream JavaDoc getOut() {
81         return out;
82     }
83
84     /**
85      * Creates a {@link Pipe} that allows remote system to write and local system to read.
86      */

87     public static Pipe createRemoteToLocal() {
88         // OutputStream will be created on the target
89
return new Pipe(new PipedInputStream JavaDoc(),null);
90     }
91
92     /**
93      * Creates a {@link Pipe} that allows local system to write and remote system to read.
94      */

95     public static Pipe createLocalToRemote() {
96         return new Pipe(null,new ProxyOutputStream());
97     }
98
99     private void writeObject(ObjectOutputStream JavaDoc oos) throws IOException JavaDoc {
100         if(in!=null && out==null) {
101             // remote will write to local
102
PipedOutputStream JavaDoc pos = new PipedOutputStream JavaDoc((PipedInputStream JavaDoc)in);
103             int oid = Channel.current().export(pos);
104
105             oos.writeBoolean(true); // marker
106
oos.writeInt(oid);
107         } else {
108             // remote will read from local
109
int oid = Channel.current().export(out);
110
111             oos.writeBoolean(false);
112             oos.writeInt(oid);
113         }
114     }
115
116     private void readObject(ObjectInputStream JavaDoc ois) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
117         final Channel channel = Channel.current();
118         assert channel !=null;
119
120         if(ois.readBoolean()) {
121             // local will write to remote
122
in = null;
123             out = new ProxyOutputStream(channel, ois.readInt());
124         } else {
125             // local will read from remote.
126
// tell the remote system about this local read pipe
127

128             // this is the OutputStream that wants to send data to us
129
final int oidRos = ois.readInt();
130
131             // we want 'oidRos' to send data to this PipedOutputStream
132
PipedOutputStream JavaDoc pos = new PipedOutputStream JavaDoc();
133             final int oidPos = channel.export(pos);
134
135             // tell 'ros' to connect to our 'pos'.
136
channel.send(new ConnectCommand(oidRos, oidPos));
137
138             out = null;
139             in = new PipedInputStream JavaDoc(pos);
140         }
141     }
142
143     private static final long serialVersionUID = 1L;
144
145     private static final Logger JavaDoc logger = Logger.getLogger(Pipe.class.getName());
146
147     private static class ConnectCommand extends Command {
148         private final int oidRos;
149         private final int oidPos;
150
151         public ConnectCommand(int oidRos, int oidPos) {
152             this.oidRos = oidRos;
153             this.oidPos = oidPos;
154         }
155
156         protected void execute(Channel channel) {
157             try {
158                 ProxyOutputStream ros = (ProxyOutputStream) channel.getExportedObject(oidRos);
159                 channel.unexport(oidRos);
160                 ros.connect(channel, oidPos);
161             } catch (IOException JavaDoc e) {
162                 logger.log(Level.SEVERE,"Failed to connect to pipe",e);
163             }
164         }
165     }
166 }
167
Popular Tags