KickJava   Java API By Example, From Geeks To Geeks.

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

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

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

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