KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cactus > integration > ant > container > MockHttpServer


1 /*
2  * ========================================================================
3  *
4  * Copyright 2003 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * ========================================================================
19  */

20 package org.apache.cactus.integration.ant.container;
21
22 import java.io.BufferedReader JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.InputStream JavaDoc;
25 import java.io.InputStreamReader JavaDoc;
26 import java.io.OutputStream JavaDoc;
27 import java.io.StringReader JavaDoc;
28 import java.net.ConnectException JavaDoc;
29 import java.net.ServerSocket JavaDoc;
30 import java.net.Socket JavaDoc;
31 import java.util.Random JavaDoc;
32 import java.util.StringTokenizer JavaDoc;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37 import junit.framework.Assert;
38
39 /**
40  * A very simple HTTP server that binds to a port and responds to all requests
41  * with a predefined response.
42  *
43  * @version $Id: MockHttpServer.java,v 1.7 2004/02/29 16:32:16 vmassol Exp $
44  */

45 public final class MockHttpServer implements Runnable JavaDoc
46 {
47
48     // Instance Variables ------------------------------------------------------
49

50     /**
51      * The port to bind to.
52      */

53     private int port;
54
55     /**
56      * The content of the request to send back on any request.
57      */

58     private String JavaDoc response;
59
60     /**
61      * Flag indicating whether the server should be stopped.
62      */

63     private volatile boolean stopFlag = false;
64
65     /**
66      * The actual method requested.
67      */

68     private String JavaDoc actualMethod;
69
70     /**
71      * The HTTP method expected.
72      */

73     private String JavaDoc expectedMethod;
74
75     /**
76      * The actual request URI.
77      */

78     private String JavaDoc actualUri;
79
80     /**
81      * The request URI expected.
82      */

83     private String JavaDoc expectedUri;
84
85     /**
86      * The expected number of requests.
87      */

88     private int expectedRequestCount = -1;
89
90     /**
91      * The number of requests (excluding the internal SHUTDOWN request).
92      */

93     private int actualRequestCount = 0;
94
95     /**
96      * The log to write messages to.
97      */

98     private Log log = LogFactory.getLog(MockHttpServer.class);
99
100     // Constructors ------------------------------------------------------------
101

102     /**
103      * Constructor.
104      *
105      * @param thePort The port to bind to
106      */

107     public MockHttpServer(int thePort)
108     {
109         if (thePort <= 0)
110         {
111             throw new IllegalArgumentException JavaDoc("Invalid port number");
112         }
113         this.port = thePort;
114     }
115
116     // Runnable Implementation -------------------------------------------------
117

118     /**
119      * The main server thread. The server will wait for connections until it
120      * receives a special request containing the string 'SHUTDOWN'.
121      */

122     public void run()
123     {
124         if (this.response == null)
125         {
126             throw new IllegalStateException JavaDoc("Response content not set");
127         }
128
129         try
130         {
131             ServerSocket JavaDoc serverSocket = new ServerSocket JavaDoc(port);
132             while (!this.stopFlag)
133             {
134                 Socket JavaDoc socket = serverSocket.accept();
135                 try
136                 {
137                     if (!this.stopFlag)
138                     {
139                         processRequest(socket);
140                     }
141                 }
142                 catch (IOException JavaDoc ioe)
143                 {
144                     this.log.error("Couldn't process request", ioe);
145                 }
146                 finally
147                 {
148                     socket.close();
149                 }
150             }
151             serverSocket.close();
152         }
153         catch (IOException JavaDoc ioe)
154         {
155             this.log.error("Problem with server socket", ioe);
156         }
157     }
158
159     // Public Methods ----------------------------------------------------------
160

161     /**
162      * Advise the server to expect a specific HTTP method in requests.
163      *
164      * @param theMethod The HTTP method to expect
165      */

166     public void expectMethod(String JavaDoc theMethod)
167     {
168         this.expectedMethod = theMethod;
169     }
170
171     /**
172      * Advise the server to expect a specific number of requests.
173      *
174      * @param theRequestCount The number of requests to expect
175      */

176     public void expectRequestCount(int theRequestCount)
177     {
178         this.expectedRequestCount = theRequestCount;
179     }
180
181     /**
182      * Advise the server to expect a specific request URI in requests.
183      *
184      * @param theUri The request URI to expect
185      */

186     public void expectUri(String JavaDoc theUri)
187     {
188         this.expectedUri = theUri;
189     }
190
191     /**
192      * Returns the port number the server is listening on.
193      *
194      * @return The port
195      */

196     public int getPort()
197     {
198         return this.port;
199     }
200
201     /**
202      * Returns whether the server is stopped (or about to stop, to be precise).
203      *
204      * @return Whether the server is stopped
205      */

206     public boolean isStopped()
207     {
208         return this.stopFlag;
209     }
210
211     /**
212      * Sets the content of the request to send back on any request.
213      *
214      * @param theResponse The content of the HTTP response
215      */

216     public void setResponse(String JavaDoc theResponse)
217     {
218         this.response = theResponse;
219     }
220
221     /**
222      * Stops the server.
223      */

224     public void stop()
225     {
226         this.stopFlag = true;
227         try
228         {
229             Socket JavaDoc sock = new Socket JavaDoc("localhost", this.port);
230             sock.getOutputStream().write("SHUTDOWN\n".getBytes());
231         }
232         catch (IOException JavaDoc ioe)
233         {
234             this.log.error("Error while trying to stop", ioe);
235         }
236     }
237
238     /**
239      * Verifies whether the requests sent to the server matched those expected.
240      */

241     public void verify()
242     {
243         if (this.expectedRequestCount >= 0)
244         {
245             Assert.assertTrue("Expected " + this.expectedRequestCount
246                 + " requests, but got " + this.actualRequestCount,
247                 this.expectedRequestCount == this.actualRequestCount);
248         }
249         if (this.expectedMethod != null)
250         {
251             Assert.assertEquals(this.expectedMethod, this.actualMethod);
252         }
253         if (this.expectedUri != null)
254         {
255             Assert.assertEquals(this.expectedUri, this.actualUri);
256         }
257     }
258
259     // Public Static Methods ---------------------------------------------------
260

261     /**
262      * Returns a free port number on the specified host within the given range.
263      *
264      * @param theHost The name or IP addres of host on which to find a free port
265      * @param theLowest The port number from which to start searching
266      * @param theHighest The port number at which to stop searching
267      * @return A free port in the specified range, or -1 of none was found
268      * @throws IOException If an I/O error occurs
269      */

270     public static int findUnusedLocalPort(String JavaDoc theHost, int theLowest,
271         int theHighest)
272         throws IOException JavaDoc
273     {
274         final Random JavaDoc random = new Random JavaDoc(System.currentTimeMillis());
275         for (int i = 0; i < 10; i++)
276         {
277             int port = (int)
278                 (random.nextFloat() * (theHighest - theLowest)) + theLowest;
279             Socket JavaDoc s = null;
280             try
281             {
282                 s = new Socket JavaDoc(theHost, port);
283             }
284             catch (ConnectException JavaDoc e)
285             {
286                 return port;
287             }
288             finally
289             {
290                 if (s != null)
291                 {
292                     s.close();
293                 }
294             }
295         }
296         return -1;
297     }
298
299     // Private Methods ---------------------------------------------------------
300

301     /**
302      * Processes an incoming request.
303      *
304      * @param theSocket The socket to which the connection was established
305      * @throws IOException If an I/O error occurs
306      */

307     private void processRequest(Socket JavaDoc theSocket) throws IOException JavaDoc
308     {
309         BufferedReader JavaDoc in = null;
310         OutputStream JavaDoc out = null;
311         try
312         {
313             readRequest(theSocket.getInputStream());
314             writeResponse(theSocket.getOutputStream());
315         }
316         finally
317         {
318             if (in != null)
319             {
320                 in.close();
321             }
322             if (out != null)
323             {
324                 out.close();
325             }
326         }
327     }
328
329     /**
330      * Reads the request and stores the HTTP method and request URI.
331      *
332      * @param theIn The socket input stream
333      * @throws IOException If an I/O error occurs
334      */

335     private void readRequest(InputStream JavaDoc theIn) throws IOException JavaDoc
336     {
337         BufferedReader JavaDoc reader =
338             new BufferedReader JavaDoc(new InputStreamReader JavaDoc(theIn));
339
340         String JavaDoc statusLine = reader.readLine();
341         StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(statusLine);
342         this.actualRequestCount++;
343         this.actualMethod = tokenizer.nextToken();
344         this.actualUri = tokenizer.nextToken();
345     }
346
347     /**
348      * Writes the user-defined response to the socket output stream.
349      *
350      * @param theOut The socket output stream
351      * @throws IOException If an I/O error occurs
352      */

353     private void writeResponse(OutputStream JavaDoc theOut) throws IOException JavaDoc
354     {
355         // Construct the response message.
356
if (this.response != null)
357         {
358             BufferedReader JavaDoc reader = new BufferedReader JavaDoc(
359                 new StringReader JavaDoc(this.response));
360             String JavaDoc line = null;
361             while ((line = reader.readLine()) != null)
362             {
363                 theOut.write(line.getBytes());
364                 theOut.write("\r\n".getBytes());
365             }
366         }
367     }
368
369 }
370
Popular Tags