KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > cvsclient > PseudoCvsServer


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.lib.cvsclient;
21
22 import java.io.*;
23 import java.net.ServerSocket JavaDoc;
24 import java.net.Socket JavaDoc;
25
26 /**
27  * Unit testing CVS server implementation that provides
28  * constant replies coming from prepared files and
29  * simulates network and server overload failures.
30  *
31  * <p>Typical server usage in unit test sequence:
32  * <pre>
33  * InputStream in = getClass().getResourceAsStream("...");
34  * PseudoCvsServer cvss = new PseudoCvsServer(in);
35  * new Thread(cvss).start();
36  * String cvsRoot = cvss.getCvsRoot();
37  * &lt;client operations>
38  * cvss.stop(); // check test failure
39  * &lt;tested client asserts>
40  * </pre>
41  *
42  * <p>Fake input and output streams can be on Unix systems
43  * catched using <tt>nc</tt> program. To catch command line
44  * <tt>cvs</tt>:
45  * <ul>
46  * <li>outgoing requests stream use <pre>nc -l -p $3000 | tee $requests.log</pre> and
47  * <pre>cvs -d :pserver:$ano@127.0.0.1:$3000/$cvs -z0 $whateEverCommand</pre>
48  * <li>incoming responses stream use <pre>nc $cvs.netbeans.org $2401 | tee $reponses.log</pre>
49  * </ul>
50  *
51  * @author Petr Kuzel
52  */

53 public final class PseudoCvsServer implements Runnable JavaDoc {
54
55     private final int SIMULATE_SLOWNESS = 1;
56     private final int SIMULATE_OVERLOAD = 2;
57     private final int SIMULATE_DROP = 4;
58
59     private final InputStream fakeDataStream;
60     private OutputStream requestsStream;
61     private final ServerSocket JavaDoc serverSocket;
62
63     private Socket JavaDoc clientSocket;
64     private OutputStream socketOut;
65     private InputStream socketIn;
66
67     private int outputCounter = -1;
68     private int inputCounter = -1;
69     private int simulationMode;
70
71     private Exception JavaDoc throwable;
72     private boolean stopped;
73     private boolean running;
74     private boolean ignoreProbe;
75
76     /**
77      * Creates new server that replies with given data.
78      * @param in input stream that is consumend and <b>closed</b>
79      * once server runnable terminates.
80      *
81      * @throws IOException if cannot create server socket
82      */

83     public PseudoCvsServer(InputStream in) throws IOException {
84         try {
85             this.fakeDataStream = in;
86             serverSocket = new ServerSocket JavaDoc();
87             serverSocket.bind(null, 2);
88         } catch (IOException ex) {
89             in.close();
90             throw ex;
91         }
92     }
93
94     /**
95      * returns port that accepts client requests.
96      */

97     public int getPort() {
98         return serverSocket.getLocalPort();
99     }
100
101     /**
102      * Utility method returning typical CVSRoot sutable for
103      * local CVSClient testing.
104      *
105      * @return <code>":pserver:anoncvs@127.0.0.1:" + getPort() + "/cvs"</code>
106      */

107     public synchronized String JavaDoc getCvsRoot() {
108         try {
109             while (running == false) {
110                 this.wait();
111             }
112         } catch (InterruptedException JavaDoc e) {
113         }
114         return ":pserver:anoncvs@127.0.0.1:" + getPort() + "/cvs";
115     }
116
117     /**
118      * Enters hard network failure simulation mode, silentry
119      * dropping down connection after specified number of in/outgoing bytes.
120      *
121      * @param write specifies number of bytes send before
122      * closing socket output stream. -1 for unlimited.
123      * @param read specifies number of bytes received before
124      * closing socket input stream. -1 for unlimited.
125      */

126     public void simulateNetworkFailure(int write, int read) {
127         simulationMode |= SIMULATE_DROP;
128         outputCounter = write;
129         inputCounter = read;
130     }
131
132     /**
133      * Enters server overload simulation mode.
134      * Server properly closes streams sending TCP signals to client.
135      *
136      * @param write specifies number of bytes send before
137      * shuting down socket output stream. -1 for unlimited.
138      * @param read specifies number of bytes received before
139      * shuting down socket input stream. -1 for unlimited.
140      */

141     public void simulateServerOverload(int write, int read) {
142         simulationMode |= SIMULATE_OVERLOAD;
143         outputCounter = write;
144         inputCounter = read;
145     }
146
147
148     public void simulateSlowNetwork(int write, int read) {
149         simulationMode |= SIMULATE_SLOWNESS;
150         outputCounter = write;
151         inputCounter = read;
152     }
153
154     /**
155      * Enters ignore very first connect mode (connection probe).
156      * It means that actual data are send out to second requestor.
157      */

158     public void ignoreProbe() {
159         ignoreProbe = true;
160     }
161
162     /**
163      * Logs server input intu specified stream.
164      *
165      * @param out log stream. The stream is closed on server termination.
166      */

167     public void logRequests(OutputStream out) {
168         requestsStream = out;
169     }
170
171     /**
172      * Entry point, starts listening at port and sends out
173      * predefined replies. HAndles only first request.
174      */

175     public void run() {
176
177         try {
178             synchronized (this) {
179                 running = true;
180                 notifyAll();
181             }
182
183             while (true) {
184                 try {
185                     clientSocket = serverSocket.accept();
186                     if (ignoreProbe == false) {
187                         break;
188                     }
189                     ignoreProbe = false;
190                 } catch (IOException e) {
191                     throwable = e;
192                     return;
193                 }
194             }
195
196             try {
197                 socketOut = clientSocket.getOutputStream();
198                 socketIn = clientSocket.getInputStream();
199                 if (consumeInput()) {
200                     return;
201                 }
202                 int nextByte = fakeDataStream.read();
203                 while (nextByte != -1) {
204                     if (outputCounter-- == 0) {
205                         if ((simulationMode & SIMULATE_DROP) != 0) {
206                             socketOut.flush();
207                             socketOut.close();
208                         }
209                         if ((simulationMode & SIMULATE_OVERLOAD) != 0) {
210                             clientSocket.shutdownOutput();
211                         }
212                         if ((simulationMode & SIMULATE_SLOWNESS) != 0) {
213                             try {
214                                 Thread.sleep(5000);
215                             } catch (InterruptedException JavaDoc e) {
216                                 throwable = e;
217                             }
218                         }
219                         if ((simulationMode & (SIMULATE_OVERLOAD | SIMULATE_DROP)) != 0) {
220                             consumeInputUntilStopped();
221                             return;
222                         }
223                     }
224                     socketOut.write(nextByte);
225                     if (consumeInput()) {
226                         return;
227                     }
228                     nextByte = fakeDataStream.read();
229                 }
230                 socketOut.flush();
231 // socketOut.close(); // need to propagate to client ASAP, otherwise all reads and available wait forever
232
// on the other hand it causes premature BrokenPipe signal because it
233
// immediately clears receiver's input buffers
234

235                 // do not close input streams prematurely
236
consumeInputUntilStopped();
237             } catch (IOException e) {
238                 throwable = e;
239                 return;
240             }
241         } finally {
242             try {
243                 fakeDataStream.close();
244             } catch (IOException alreadyClosed) {
245             }
246             try {
247                 if (socketIn != null) socketIn.close();
248             } catch (IOException alreadyClosed) {
249             }
250             try {
251                 if (socketOut != null) socketOut.close();
252             } catch (IOException alreadyClosed) {
253             }
254             try {
255                 if (requestsStream != null) {
256                     requestsStream.flush();
257                     requestsStream.close();
258                 }
259             } catch (IOException alreadyClosed) {
260             }
261         }
262     }
263
264     /**
265      * Stops server and optionaly rethrows internal server exception if any.
266      */

267     public synchronized void stop() throws Exception JavaDoc {
268         stopped = true;
269         notifyAll();
270         if (throwable != null) {
271             throw throwable;
272         }
273     }
274
275     /** For diagnostics purpoes only. */
276     public String JavaDoc toString() {
277         StringWriter sw = new StringWriter();
278         PrintWriter ps = new PrintWriter(sw);
279         ps.write("PseudoCvsServer on " + serverSocket + "\n");
280         if (throwable != null) {
281             throwable.fillInStackTrace();
282             throwable.printStackTrace(ps);
283         }
284         ps.flush();
285         ps.close();
286         return sw.getBuffer().toString();
287     }
288
289     /**
290      * Reads client input stream possibly simulating errors.
291      */

292     private boolean consumeInput() throws IOException {
293         int available = socketIn.available();
294         for (int i = 0; i<available; i++) {
295             if (inputCounter-- == 0) {
296                 if ((simulationMode & SIMULATE_DROP) != 0) {
297                     socketIn.close();
298                     if (requestsStream != null) {
299                         requestsStream.write("[PseudoCvsServer abort]".getBytes("utf8"));
300                     }
301                 }
302                 if ((simulationMode & SIMULATE_OVERLOAD) != 0) {
303                     clientSocket.shutdownInput();
304                     if (requestsStream != null) {
305                         requestsStream.write("[PseudoCvsServer abort]".getBytes("utf8"));
306                     }
307                 }
308                 return true;
309             }
310             int octet = socketIn.read();
311             if (requestsStream != null) {
312                 requestsStream.write(octet);
313                 requestsStream.flush();
314             }
315         }
316         return false;
317     }
318
319     private synchronized void consumeInputUntilStopped() throws IOException {
320         while (stopped == false) {
321             try {
322                 wait(100);
323                 consumeInput();
324             } catch (InterruptedException JavaDoc e) {
325                 throwable = e;
326             }
327         }
328     }
329 }
330
Popular Tags