1 /*
2 * $Header: /u/cvs/Projects/EnhydraOrg/enhydra3x/Enhydra/modules/Tomcat/src/share/org/apache/tomcat/core/ContextManager.java,v 1.2 2000/02/27 01:13:39 shawn Exp $
3 * $Revision: 1.2 $
4 * $Date: 2000/02/27 01:13:39 $
5 *
6 * ====================================================================
7 *
8 * The Apache Software License, Version 1.1
9 *
10 * Copyright (c) 1999 The Apache Software Foundation. All rights
11 * reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 *
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 *
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in
22 * the documentation and/or other materials provided with the
23 * distribution.
24 *
25 * 3. The end-user documentation included with the redistribution, if
26 * any, must include the following acknowlegement:
27 * "This product includes software developed by the
28 * Apache Software Foundation (http://www.apache.org/)."
29 * Alternately, this acknowlegement may appear in the software itself,
30 * if and wherever such third-party acknowlegements normally appear.
31 *
32 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
33 * Foundation" must not be used to endorse or promote products derived
34 * from this software without prior written permission. For written
35 * permission, please contact apache@apache.org.
36 *
37 * 5. Products derived from this software may not be called "Apache"
38 * nor may "Apache" appear in their names without prior written
39 * permission of the Apache Group.
40 *
41 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
45 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
48 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
49 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 * ====================================================================
54 *
55 * This software consists of voluntary contributions made by many
56 * individuals on behalf of the Apache Software Foundation. For more
57 * information on the Apache Software Foundation, please see
58 * <http://www.apache.org/>.
59 *
60 * [Additional notices, if required by prior licensing conditions]
61 *
62 */
63
64
65 package org.apache.tomcat.core;
66
67 import org.apache.tomcat.core;
68 import org.apache.tomcat.net;
69 import org.apache.tomcat.util;
70 import java.io;
71 import java.net;
72 import java.util;
73
74
75 /**
76 * A collection class representing the Contexts associated with a particular
77 * Server. The managed Contexts can be accessed directly by name, or
78 * indirectly by requesting the Context responsible for processing a
79 * particular path. One particular Context can be distinguished as the
80 * default Context, which is selected to process paths for which no other
81 * Context is responsible.
82 *
83 * @author James Duncan Davidson [duncan@eng.sun.com]
84 * @author James Todd [gonzo@eng.sun.com]
85 * @author Harish Prabandham
86 */
87
88 public class ContextManager implements Server {
89
90 /**
91 * The string constants for this ContextManager.
92 */
93
94 private StringManager sm =
95 StringManager.getManager(Constants.Package);
96
97
98 /**
99 * The default Context used to process paths not associated with
100 * any other Context.
101 */
102
103 private Context defaultContext;
104
105 /**
106 * The set of Contexts associated with this ContextManager,
107 * keyed by context name.
108 */
109
110 private Hashtable contexts = new Hashtable();
111
112
113 /**
114 * The set of Contexts associated with this ContextManager,
115 * keyed by the path prefix to be processed by this Context.
116 */
117
118 private Hashtable contextMaps = new Hashtable();
119
120
121 /**
122 * The server information string to be returned by the server
123 * associated with this ContextManager.
124 */
125
126 private String serverInfo = null;
127
128
129 /**
130 * The virtual host name for the Server this ContextManager
131 * is associated with.
132 * XXX Why is this here instead of in the Server?
133 */
134 // Used by Contexts
135 String hostname;
136
137 /**
138 * The port number being listed to by the Server this ContextManager
139 * is associated with.
140 * XXX Why is this here instead of in the Server?
141 */
142
143 int port;
144
145
146 /**
147 * Construct a new ContextManager instance with default values.
148 */
149
150 public ContextManager() {
151
152 }
153
154
155 /**
156 * Gets the server info string for this server
157 */
158
159 public String getServerInfo() {
160 return serverInfo;
161 // that is the behavior in the current tomcat
162 // return defaultContext.getEngineHeader();
163
164 }
165
166
167 /**
168 * Sets the server info string for this server. This string must
169 * be of the form <productName>/<productVersion> [(<optionalInfo>)]
170 *
171 * @param serverInfo The new server information string
172 */
173
174 public void setServerInfo(String serverInfo) {
175 this.serverInfo = serverInfo;
176 }
177
178
179 /**
180 * Gets the document base of the default context for this server.
181 */
182
183 public URL getDocumentBase() {
184 return defaultContext.getDocumentBase();
185 }
186
187
188 /**
189 * Sets the document base of the default context for this server.
190 *
191 * @param docBase The new document base
192 */
193
194 public void setDocumentBase(URL docBase) {
195 defaultContext.setDocumentBase(docBase);
196 }
197
198
199 /**
200 * Gets the default Context for this server.
201 */
202
203 public Context getDefaultContext() {
204 return defaultContext;
205 }
206
207
208 /**
209 * Sets the default Context for this server.
210 *
211 * @param ctx The new default Context
212 */
213
214 public void setDefaultContext(Context ctx) {
215 defaultContext=ctx;
216 }
217
218
219 /**
220 * Get the names of all the contexts in this server.
221 */
222
223 public Enumeration getContextNames() {
224 return contexts.keys();
225 }
226
227
228 /**
229 * Gets a context by it's name, or <code>null</code> if there is
230 * no such context.
231 *
232 * @param name Name of the requested context
233 */
234
235 public Context getContext(String name) {
236 return (Context)contexts.get(name);
237 }
238
239
240 /**
241 * Gets the context that is responsible for requests for a
242 * particular path. If no specifically assigned Context can be
243 * identified, returns the default Context.
244 *
245 * @param path The path for which a Context is requested
246 */
247
248 public Context getContextByPath(String path) {
249 String realPath = path;
250 Context ctx = null;
251
252 // XXX
253 // needs help ... this needs to be optimized out.
254
255 lookup:
256 do {
257 ctx = (Context)contextMaps.get(path);
258 if (ctx == null) {
259 int i = path.lastIndexOf('/');
260 if (i > -1 && path.length() > 1) {
261 path = path.substring(0, i);
262 if (path.length() == 0) {
263 path = "/";
264 }
265 } else {
266 // path too short
267 break lookup;
268 }
269 } else {
270 }
271 } while (ctx == null);
272
273 if (ctx == null) {
274 ctx = defaultContext;
275 }
276
277 return ctx;
278 }
279
280
281 /**
282 * Adds a new Context to the set managed by this ContextManager.
283 * XXX Why is there no context name argument?
284 * XXX Should this be synchronized?
285 *
286 * @param path Path prefix to be processed by this Context
287 * @param docBase Document base URL for this Context
288 */
289
290 public Context addContext(String path, URL docBase) {
291 if (path == null) {
292 String msg = sm.getString("server.defaultContext.path.npe");
293
294 throw new NullPointerException(msg);
295 }
296
297 path = path.trim();
298
299 if (path.length() > 0 &&
300 docBase == null) {
301 String msg = sm.getString("server.defaultContext.docBase.npe");
302
303 throw new NullPointerException(msg);
304 }
305
306 if (contexts.get(path) != null) {
307 String msg = sm.getString("server.createctx.existname",
308 path);
309
310 throw new IllegalStateException(msg);
311 }
312
313 if (contextMaps.get(path) != null) {
314 String msg = sm.getString("server.createctx.existmap",
315 path);
316
317 throw new IllegalStateException(msg);
318 }
319
320 Context context = new Context(this, path);
321
322 if (docBase != null) {
323 context.setDocumentBase(docBase);
324 }
325
326 // check to see if defaultContext
327
328 if (path.length() == 0) {
329 contexts.put(
330 org.apache.tomcat.core.Constants.Context.Default.Name,
331 context);
332 } else {
333 contexts.put(path, context);
334 contextMaps.put(path, context);
335 }
336
337 return context;
338 }
339
340
341 /**
342 * Removes a context from service.
343 * XXX Should this be synchronized?
344 *
345 * @param name Name of the Context to be removed
346 */
347
348 public void removeContext(String name) {
349 if (name.equals(
350 org.apache.tomcat.core.Constants.Context.Default.Name)){
351 throw new IllegalArgumentException(name);
352 }
353
354 Context context = (Context)contexts.get(name);
355
356 if(context != null) {
357 context.shutdown();
358 contexts.remove(name);
359 contextMaps.remove(name);
360 }
361 }
362
363
364 /**
365 * Sets the port number on which this server listens.
366 *
367 * @param port The new port number
368 */
369
370 public void setPort(int port) {
371 this.port=port;
372 }
373
374
375 /**
376 * Gets the port number on which this server listens.
377 */
378
379 public int getPort() {
380 return port;
381 }
382
383
384 /**
385 * Sets the virtual host name of this server.
386 *
387 * @param host The new virtual host name
388 */
389
390 public void setHostName( String host) {
391 this.hostname=host;
392 }
393
394
395 /**
396 * Gets the virtual host name of this server.
397 */
398
399 public String getHostName() {
400 return hostname;
401 }
402
403
404 /** Common for all connectors, needs to be shared in order to avoid
405 code duplication
406 */
407 public void service( Request rrequest, Response rresponse ) {
408 try {
409 rrequest.setResponse(rresponse);
410 rresponse.setRequest(rrequest);
411
412 // XXX
413 // return if an error was detected in processing the
414 // request line
415 if (rresponse.getStatus() >= 400) {
416 rresponse.finish();
417 rrequest.recycle();
418 rresponse.recycle();
419 return;
420 }
421
422 // resolve the server that we are for
423 String path = rrequest.getRequestURI();
424
425 Context ctx= this.getContextByPath(path);
426
427 // final fix on response & request
428 // rresponse.setServerHeader(server.getServerHeader());
429
430 String ctxPath = ctx.getPath();
431 String pathInfo =path.substring(ctxPath.length(),
432 path.length());
433 // don't do headers if request protocol is http/0.9
434 if (rrequest.getProtocol() == null) {
435 rresponse.setOmitHeaders(true);
436 }
437
438 // do it
439 // System.out.println( request + " " + rresponse );
440 ctx.handleRequest(rrequest, rresponse);
441
442 // finish and clean up
443 rresponse.finish();
444
445 // protocol notification
446 rresponse.endResponse();
447
448 } catch (Exception e) {
449 // XXX
450 // this isn't what we want, we want to log the problem somehow
451 System.out.println("HANDLER THREAD PROBLEM: " + e);
452 e.printStackTrace();
453 }
454 }
455
456
457 }