1 // ========================================================================
2 // Copyright 2004-2008 Mort Bay Consulting Pty. Ltd.
3 // ------------------------------------------------------------------------
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 // ========================================================================
14 package org.mortbay.jetty.testing;
15
16 import java.io.IOException;
17 import java.net.Inet4Address;
18 import java.net.InetAddress;
19 import java.net.URL;
20 import java.util.Enumeration;
21 import java.util.EventListener;
22
23 import org.mortbay.io.ByteArrayBuffer;
24 import org.mortbay.jetty.LocalConnector;
25 import org.mortbay.jetty.Server;
26 import org.mortbay.jetty.bio.SocketConnector;
27 import org.mortbay.jetty.nio.SelectChannelConnector;
28 import org.mortbay.jetty.servlet.Context;
29 import org.mortbay.jetty.servlet.FilterHolder;
30 import org.mortbay.jetty.servlet.ServletHolder;
31 import org.mortbay.util.Attributes;
32
33
34
35 /* ------------------------------------------------------------ */
36 /** Testing support for servlets and filters.
37 *
38 * Allows a programatic setup of a context with servlets and filters for
39 * testing. Raw HTTP requests may be sent to the context and responses received.
40 * To avoid handling raw HTTP see {@link org.mortbay.jetty.testing.HttpTester}.
41 * <pre>
42 * ServletTester tester=new ServletTester();
43 * tester.setContextPath("/context");
44 * tester.addServlet(TestServlet.class, "/servlet/*");
45 * tester.addServlet("org.mortbay.jetty.servlet.DefaultServlet", "/");
46 * tester.start();
47 * String response = tester.getResponses("GET /context/servlet/info HTTP/1.0\r\n\r\n");
48 * </pre>
49 *
50 * @see org.mortbay.jetty.testing.HttpTester
51 * @author gregw
52 *
53 */
54 public class ServletTester
55 {
56 Server _server = new Server();
57 LocalConnector _connector = new LocalConnector();
58 Context _context = new Context(Context.SESSIONS|Context.SECURITY);
59 int _maxIdleTime = -1;
60
61 public ServletTester()
62 {
63 try
64 {
65 _server.setSendServerVersion(false);
66 _server.addConnector(_connector);
67 _server.addHandler(_context);
68 }
69 catch (Error e)
70 {
71 throw e;
72 }
73 catch (RuntimeException e)
74 {
75 throw e;
76 }
77 catch (Exception e)
78 {
79 throw new RuntimeException(e);
80 }
81 }
82
83 /* ------------------------------------------------------------ */
84 public void start() throws Exception
85 {
86 _server.start();
87 }
88
89 /* ------------------------------------------------------------ */
90 public void stop() throws Exception
91 {
92 _server.stop();
93 }
94
95 /* ------------------------------------------------------------ */
96 public Context getContext()
97 {
98 return _context;
99 }
100
101 /* ------------------------------------------------------------ */
102 /** Get raw HTTP responses from raw HTTP requests.
103 * Multiple requests and responses may be handled, but only if
104 * persistent connections conditions apply.
105 * @param rawRequests String of raw HTTP requests
106 * @return String of raw HTTP responses
107 * @throws Exception
108 */
109 public String getResponses(String rawRequests) throws Exception
110 {
111 _connector.reopen();
112 String responses = _connector.getResponses(rawRequests);
113 return responses;
114 }
115
116 /* ------------------------------------------------------------ */
117 /** Get raw HTTP responses from raw HTTP requests.
118 * Multiple requests and responses may be handled, but only if
119 * persistent connections conditions apply.
120 * @param rawRequests String of raw HTTP requests
121 * @param connector The connector to handle the responses
122 * @return String of raw HTTP responses
123 * @throws Exception
124 */
125 public String getResponses(String rawRequests, LocalConnector connector) throws Exception
126 {
127 connector.reopen();
128 String responses = connector.getResponses(rawRequests);
129 return responses;
130 }
131
132 /* ------------------------------------------------------------ */
133 /** Get raw HTTP responses from raw HTTP requests.
134 * Multiple requests and responses may be handled, but only if
135 * persistent connections conditions apply.
136 * @param rawRequests String of raw HTTP requests
137 * @return String of raw HTTP responses
138 * @throws Exception
139 */
140 public ByteArrayBuffer getResponses(ByteArrayBuffer rawRequests) throws Exception
141 {
142 _connector.reopen();
143 ByteArrayBuffer responses = _connector.getResponses(rawRequests,false);
144 return responses;
145 }
146
147 /* ------------------------------------------------------------ */
148 /** Get raw HTTP responses from raw HTTP requests.
149 * Multiple requests and responses may be handled, but only if
150 * persistent connections conditions apply.
151 * @param rawRequests String of raw HTTP requests
152 * @param connector The connector to handle the responses
153 * @return String of raw HTTP responses
154 * @throws Exception
155 */
156 public ByteArrayBuffer getResponses(ByteArrayBuffer rawRequests, LocalConnector connector) throws Exception
157 {
158 connector.reopen();
159 ByteArrayBuffer responses = connector.getResponses(rawRequests,false);
160 return responses;
161 }
162
163 /* ------------------------------------------------------------ */
164 /** Create a Socket connector.
165 * This methods adds a socket connector to the server
166 * @param locahost if true, only listen on local host, else listen on all interfaces.
167 * @return A URL to access the server via the socket connector.
168 * @throws Exception
169 */
170 public String createSocketConnector(boolean localhost)
171 throws Exception
172 {
173 synchronized (this)
174 {
175 SelectChannelConnector connector = new SelectChannelConnector();
176 if (localhost)
177 connector.setHost("127.0.0.1");
178 _server.addConnector(connector);
179 if (_maxIdleTime != -1 )
180 connector.setMaxIdleTime(_maxIdleTime);
181 if (_server.isStarted())
182 connector.start();
183 else
184 connector.open();
185
186 return "http://"+(localhost?"127.0.0.1":
187 InetAddress.getLocalHost().getHostAddress()
188 )+":"+connector.getLocalPort();
189 }
190 }
191
192 /* ------------------------------------------------------------ */
193 /** Create a Socket connector.
194 * This methods adds a socket connector to the server
195 * @param locahost if true, only listen on local host, else listen on all interfaces.
196 * @return A URL to access the server via the socket connector.
197 * @throws Exception
198 */
199 public LocalConnector createLocalConnector()
200 throws Exception
201 {
202 synchronized (this)
203 {
204 LocalConnector connector = new LocalConnector();
205 _server.addConnector(connector);
206
207 if (_server.isStarted())
208 connector.start();
209
210 return connector;
211 }
212 }
213
214 /* ------------------------------------------------------------ */
215 /**
216 * @param listener
217 * @see org.mortbay.jetty.handler.ContextHandler#addEventListener(java.util.EventListener)
218 */
219 public void addEventListener(EventListener listener)
220 {
221 _context.addEventListener(listener);
222 }
223
224 /* ------------------------------------------------------------ */
225 /**
226 * @param filterClass
227 * @param pathSpec
228 * @param dispatches
229 * @return
230 * @see org.mortbay.jetty.servlet.Context#addFilter(java.lang.Class, java.lang.String, int)
231 */
232 public FilterHolder addFilter(Class filterClass, String pathSpec, int dispatches)
233 {
234 return _context.addFilter(filterClass,pathSpec,dispatches);
235 }
236
237 /* ------------------------------------------------------------ */
238 /**
239 * @param filterClass
240 * @param pathSpec
241 * @param dispatches
242 * @return
243 * @see org.mortbay.jetty.servlet.Context#addFilter(java.lang.String, java.lang.String, int)
244 */
245 public FilterHolder addFilter(String filterClass, String pathSpec, int dispatches)
246 {
247 return _context.addFilter(filterClass,pathSpec,dispatches);
248 }
249
250 /* ------------------------------------------------------------ */
251 /**
252 * @param servlet
253 * @param pathSpec
254 * @return
255 * @see org.mortbay.jetty.servlet.Context#addServlet(java.lang.Class, java.lang.String)
256 */
257 public ServletHolder addServlet(Class servlet, String pathSpec)
258 {
259 return _context.addServlet(servlet,pathSpec);
260 }
261
262 /* ------------------------------------------------------------ */
263 /**
264 * @param className
265 * @param pathSpec
266 * @return
267 * @see org.mortbay.jetty.servlet.Context#addServlet(java.lang.String, java.lang.String)
268 */
269 public ServletHolder addServlet(String className, String pathSpec)
270 {
271 return _context.addServlet(className,pathSpec);
272 }
273
274 /* ------------------------------------------------------------ */
275 /**
276 * @param name
277 * @return
278 * @see org.mortbay.jetty.handler.ContextHandler#getAttribute(java.lang.String)
279 */
280 public Object getAttribute(String name)
281 {
282 return _context.getAttribute(name);
283 }
284
285 /* ------------------------------------------------------------ */
286 /**
287 * @return
288 * @see org.mortbay.jetty.handler.ContextHandler#getAttributeNames()
289 */
290 public Enumeration getAttributeNames()
291 {
292 return _context.getAttributeNames();
293 }
294
295 /* ------------------------------------------------------------ */
296 /**
297 * @return
298 * @see org.mortbay.jetty.handler.ContextHandler#getAttributes()
299 */
300 public Attributes getAttributes()
301 {
302 return _context.getAttributes();
303 }
304
305 /* ------------------------------------------------------------ */
306 /**
307 * @return
308 * @see org.mortbay.jetty.handler.ContextHandler#getResourceBase()
309 */
310 public String getResourceBase()
311 {
312 return _context.getResourceBase();
313 }
314
315 /* ------------------------------------------------------------ */
316 /**
317 * @param name
318 * @param value
319 * @see org.mortbay.jetty.handler.ContextHandler#setAttribute(java.lang.String, java.lang.Object)
320 */
321 public void setAttribute(String name, Object value)
322 {
323 _context.setAttribute(name,value);
324 }
325
326 /* ------------------------------------------------------------ */
327 /**
328 * @param classLoader
329 * @see org.mortbay.jetty.handler.ContextHandler#setClassLoader(java.lang.ClassLoader)
330 */
331 public void setClassLoader(ClassLoader classLoader)
332 {
333 _context.setClassLoader(classLoader);
334 }
335
336 /* ------------------------------------------------------------ */
337 /**
338 * @param contextPath
339 * @see org.mortbay.jetty.handler.ContextHandler#setContextPath(java.lang.String)
340 */
341 public void setContextPath(String contextPath)
342 {
343 _context.setContextPath(contextPath);
344 }
345
346 /* ------------------------------------------------------------ */
347 /**
348 * @param eventListeners
349 * @see org.mortbay.jetty.handler.ContextHandler#setEventListeners(java.util.EventListener[])
350 */
351 public void setEventListeners(EventListener[] eventListeners)
352 {
353 _context.setEventListeners(eventListeners);
354 }
355
356 /* ------------------------------------------------------------ */
357 /**
358 * @param resourceBase
359 * @see org.mortbay.jetty.handler.ContextHandler#setResourceBase(java.lang.String)
360 */
361 public void setResourceBase(String resourceBase)
362 {
363 _context.setResourceBase(resourceBase);
364 }
365
366 /* ------------------------------------------------------------ */
367 public void setMaxIdleTime(int maxIdleTime)
368 {
369 _maxIdleTime = maxIdleTime;
370 }
371 }