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 }