00001
package com.quadcap.http.server22;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
import java.io.File;
00042
import java.io.InputStream;
00043
import java.io.InputStreamReader;
00044
import java.io.IOException;
00045
import java.io.Reader;
00046
00047
import java.util.ArrayList;
00048
import java.util.Collections;
00049
import java.util.Comparator;
00050
import java.util.Enumeration;
00051
import java.util.HashMap;
00052
import java.util.Hashtable;
00053
import java.util.List;
00054
import java.util.Properties;
00055
import java.util.Vector;
00056
00057
import java.net.URL;
00058
import java.net.MalformedURLException;
00059
00060
import javax.servlet.RequestDispatcher;
00061
import javax.servlet.Servlet;
00062
import javax.servlet.ServletContext;
00063
import javax.servlet.ServletException;
00064
import javax.servlet.ServletRequest;
00065
import javax.servlet.ServletResponse;
00066
00067
import javax.servlet.http.HttpServlet;
00068
import javax.servlet.http.HttpServletRequest;
00069
import javax.servlet.http.HttpSession;
00070
import javax.servlet.http.HttpSessionContext;
00071
00072
import com.quadcap.io.dir.Directory;
00073
import com.quadcap.io.dir.Entry;
00074
00075
import com.quadcap.util.Debug;
00076
import com.quadcap.util.Util;
00077
00078
00079
00080
00081
00082
00083
00084 public class WebApplication implements ServletContext {
00085 WebServer server;
00086 WebClassLoader classLoader;
00087 String
contextPath;
00088
00089
00090
00091
00092 HashMap
servlets =
new HashMap();
00093
00094
00095
00096
00097 Hashtable
sessions =
new Hashtable();
00098
00099
00100
00101
00102 Hashtable
attributes =
new Hashtable();
00103
00104
00105
00106
00107 Hashtable
mimeTypes =
new Hashtable();
00108
00109
00110
00111
00112 Hashtable
pathMappings =
new Hashtable();
00113 Hashtable
extMappings =
new Hashtable();
00114 Hashtable
exactMappings =
new Hashtable();
00115
00116 WebServlet defaultServlet = null;
00117
00118
00119
00120
00121 List
welcomeFiles =
new ArrayList();
00122
00123
00124
00125
00126 String
errorPage = null;
00127
00128
00129
00130
00131 Directory
docRoot;
00132
00133 String
displayName =
"";
00134
00135 long sessionCount = 0;
00136 int sessionTimeout = 3600;
00137
00138 Properties
initParams =
new Properties();
00139
00140 public WebApplication() {}
00141
00142 public void init(
WebServer server, String root, Directory dir)
00143
throws ServletException, IOException
00144 {
00145
00146
if (
Trace.level() > 0) {
00147
Debug.println(
toString() +
".init(" + root +
", " +
00148 dir.getRootPath() +
")");
00149 }
00150
00151
this.server =
server;
00152
this.docRoot = dir;
00153
this.contextPath = root;
00154
00155 File tmp =
server.
getTempDir();
00156 File myTmp =
new File(tmp, root);
00157
if (!myTmp.isDirectory() && !myTmp.mkdirs()) {
00158
throw new ServletException(
"Can't create repository: " + myTmp);
00159 }
00160
setAttribute(
"repository", myTmp);
00161
classLoader =
new WebClassLoader(dir, myTmp);
00162
classLoader.
init();
00163
attributes.put(
"com.quadcap.classLoader",
classLoader);
00164 InputStream dis = ClassLoader.getSystemResourceAsStream(
00165
"com/quadcap/http/server22/defaultContext.xml");
00166
if (dis == null) {
00167
throw new ServletException(
"Can't load default context");
00168 }
00169 Reader dfr =
new InputStreamReader(dis);
00170
try {
00171
parseDeploymentDescriptor(dfr);
00172 } finally {
00173 dfr.close();
00174 }
00175
setDisplayName(
"");
00176
00177
Entry entry = dir.getEntry(
"WEB-INF/web.xml");
00178
if (entry != null) {
00179 Reader ddr =
new InputStreamReader(entry.
getInputStream());
00180
try {
00181
parseDeploymentDescriptor(ddr);
00182 } finally {
00183 ddr.close();
00184 }
00185 }
00186
resolveServlets(
pathMappings);
00187
resolveServlets(
extMappings);
00188
resolveServlets(
exactMappings);
00189
loadInitialServlets();
00190 }
00191
00192 public void shutdown() {
00193
synchronized (
sessions) {
00194 Enumeration e =
sessions.keys();
00195
while (e.hasMoreElements()) {
00196 String sessionId = (String)e.nextElement();
00197
HSession session = (
HSession)
getSession(sessionId);
00198 session.
invalidate();
00199 }
00200 }
00201
if (
docRoot != null) {
00202
try {
00203
docRoot.close();
00204 }
catch (Throwable t) {}
00205 }
00206 }
00207
00208 final void resolveServlets(Hashtable t) {
00209 Enumeration e = t.keys();
00210
while (e.hasMoreElements()) {
00211 Object key = e.nextElement();
00212 Object obj = t.get(key);
00213
if (obj instanceof String) {
00214 Object s =
servlets.get(obj);
00215
if (s == null) {
00216
Debug.println(
"No servlet for mapping: " + obj);
00217 t.remove(key);
00218 }
else {
00219 t.put(key, s);
00220 }
00221 }
00222 }
00223 }
00224
00225 void parseDeploymentDescriptor(Reader r)
00226
throws ServletException, IOException {
00227
try {
00228
new DDParser().parse(r,
this);
00229 }
catch (Exception e) {
00230
throw new ServletException(e);
00231 } finally {
00232 r.close();
00233 }
00234 }
00235
00236 public void setDisplayName(String name) {
00237
this.displayName = name;
00238 }
00239
00240 public String
getDisplayName() {
00241
return displayName;
00242 }
00243
00244 public void addInitParam(String prop, String val) {
00245
initParams.setProperty(prop, val);
00246 }
00247
00248 public Enumeration
getInitParameterNames() {
00249
return initParams.keys();
00250 }
00251
00252 public String
getInitParameter(String name) {
00253
return initParams.getProperty(name);
00254 }
00255
00256 public void addWelcomeFile(String s) {
00257
welcomeFiles.add(s.trim());
00258 }
00259
00260 public List
getWelcomeFiles() {
00261
if (
welcomeFiles.size() == 0) {
00262
welcomeFiles.add(
"index.html");
00263
welcomeFiles.add(
"index.jsp");
00264 }
00265
return welcomeFiles;
00266 }
00267
00268 public void addServlet(
WebServlet servlet) {
00269
00270
if (
Trace.level() > 1) {
00271
Debug.println(
toString() +
".addServlet(" +
00272 servlet.
getServletName() +
")");
00273 }
00274
00275
servlets.put(servlet.
getServletName(), servlet);
00276 }
00277
00278 WebServlet getServletForRequest(
HttpDispatcher rd) {
00279 String path = rd.
getServletPath();
00280
00281
WebServlet s = (
WebServlet)
exactMappings.get(path);
00282
if (s != null) {
00283 rd.
setServlet(s, path);
00284 }
else {
00285
int lastDot = -1;
00286
for (
int i = path.length() - 1; i >= 0; i--) {
00287
char c = path.charAt(i);
00288
if (c ==
'/') {
00289 String subPath = path.substring(0, i);
00290 s = (
WebServlet)
pathMappings.get(subPath);
00291
if (s != null) {
00292 rd.
setServlet(s, subPath);
00293 rd.
setPathInfo(path.substring(i));
00294
break;
00295 }
00296 }
else if (c ==
'.' && lastDot < 0) {
00297 lastDot = i;
00298 }
00299 }
00300
if (s == null && lastDot >= 0) {
00301 String ext = path.substring(lastDot + 1);
00302 s = (
WebServlet)
extMappings.get(ext);
00303
if (s != null) {
00304 rd.
setServlet(s, path);
00305 }
00306 }
00307
if (s == null) {
00308 s =
defaultServlet;
00309 rd.
setServlet(s, path);
00310 }
00311 }
00312
00313
if (
Trace.level() > 1) {
00314
Debug.println(
toString() +
".getServlet(" + path +
") = " + s);
00315 }
00316
00317
return s;
00318 }
00319
00320 public void setSessionTimeout(
int timeout) {
00321
this.sessionTimeout = timeout;
00322 }
00323
00324 public int getSessionTimeout() {
00325
return sessionTimeout;
00326 }
00327
00328 public void addServletMapping(String servletName, String urlPattern) {
00329
00330
if (
Trace.level() > 0) {
00331
Debug.println(
this +
".addServletMapping(" + servletName +
00332
", " + urlPattern +
")");
00333 }
00334
00335
00336
if (urlPattern.equals(
"*.*")) {
00337
defaultServlet = (
WebServlet)
servlets.get(servletName);
00338 }
else if (urlPattern.endsWith(
"*")) {
00339 String path = urlPattern.substring(0, urlPattern.length() - 2);
00340
pathMappings.put(path, servletName);
00341 }
else if (urlPattern.startsWith(
"*.")) {
00342 String ext = urlPattern.substring(2);
00343
extMappings.put(ext, servletName);
00344 }
else {
00345
exactMappings.put(urlPattern, servletName);
00346 }
00347 }
00348
00349 public void setErrorPage(String errorPage) {
00350
this.errorPage = errorPage;
00351 }
00352
00353 public String
getErrorPage() {
00354
return errorPage;
00355 }
00356
00357 public Object
getAttribute(String name) {
00358
return attributes.get(name);
00359 }
00360
00361 public Enumeration
getAttributeNames() {
00362
return attributes.keys();
00363 }
00364
00365 public void setAttribute(String name, Object val) {
00366
attributes.put(name, val);
00367 }
00368
00369 public void removeAttribute(String name) {
00370
attributes.remove(name);
00371 }
00372
00373
00374
00375
00376
00377
00378
00379 public String
getServerInfo() {
00380
00381
00382
return "Quadcap Web Server 3.4";
00383
00384 }
00385
00386
00387
00388
00389 public int getMajorVersion() {
00390
return 2;
00391 }
00392
00393
00394
00395
00396 public int getMinorVersion() {
00397
return 2;
00398 }
00399
00400 public ServletContext
getContext(String path) {
00401
return server.
getContext(path);
00402 }
00403
00404
00405
00406
00407
00408 public RequestDispatcher
getRequestDispatcher(String path) {
00409
HttpDispatcher rd =
new HttpDispatcher(
this, path);
00410
WebServlet ws = getServletForRequest(rd);
00411
return (ws != null) ? rd : null;
00412 }
00413
00414 public RequestDispatcher
getNamedDispatcher(String name) {
00415
WebServlet ws = (
WebServlet)
servlets.get(name);
00416
if (ws != null) {
00417
return new HttpDispatcher(ws, name);
00418 }
else {
00419
return null;
00420 }
00421 }
00422
00423 public RequestDispatcher
getRelativeRequestDispatcher(String path,
00424
HttpRequest base) {
00425
if (path.charAt(0) ==
'/') {
00426
return getRequestDispatcher(path);
00427 }
else {
00428 String spath = base.
getServletPath();
00429
int spos = spath.length() - 1;
00430
while (spos >= 0 && spath.charAt(spos) !=
'/') spos--;
00431
00432
while (path.startsWith(
"./") || path.startsWith(
"../")) {
00433
if (path.startsWith(
"./")) {
00434 path = path.substring(2);
00435 }
else {
00436
if (spos > 0) {
00437 spos--;
00438
while (spos >= 0 && spath.charAt(spos) !=
'/') spos--;
00439 }
else {
00440
return null;
00441 }
00442 }
00443 }
00444 String absPath = spath.substring(0, spos+1) + path;
00445
return getRequestDispatcher(absPath);
00446 }
00447 }
00448
00449 void addMimeMapping(String ext, String type) {
00450
00451
if (
Trace.level() > 0) {
00452
Debug.println(
toString() +
".addMimeMapping(" + ext +
00453
", " + type +
")");
00454 }
00455
00456
mimeTypes.put(ext, type);
00457 }
00458
00459 public String
getMimeType(String file) {
00460 String type = null;
00461
int lastDot = file.lastIndexOf(
'.');
00462
int lastSep = file.lastIndexOf(
'/');
00463
if (lastDot != -1 && (lastSep == -1 || lastDot > lastSep)) {
00464 String ext = file.substring(lastDot + 1);
00465 type = (String)
mimeTypes.get(ext);
00466
if (type == null) {
00467 type =
server.
getMimeTypeForExt(ext);
00468 }
00469 }
00470
return type;
00471 }
00472
00473
00474
00475
00476
00477
00478 String
resolveDirectory(String path) {
00479 String ret = path;
00480 String sav = path +
"/";
00481
if (sav.endsWith(
"//")) {
00482 sav = sav.substring(0, sav.length()-1);
00483 }
00484
Entry e =
docRoot.getEntry(path);
00485
if (e != null) {
00486
if (e.
isDirectory()) {
00487 e = null;
00488 List w =
getWelcomeFiles();
00489
for (
int i = 0; e == null && i < w.size(); i++) {
00490 e =
docRoot.getEntry(path = sav + w.get(i));
00491 }
00492 }
00493 }
00494
if (e != null) ret = path;
00495
return ret;
00496 }
00497
00498 public String
getRealPath(String path) {
00499 String rpath = resolveDirectory(path);
00500 String ret =
docRoot.getRealPath(rpath);
00501
return ret;
00502 }
00503
00504 public URL
getResource(String path)
throws MalformedURLException {
00505
return docRoot.getURL(path);
00506 }
00507
00508 public InputStream
getResourceAsStream(String path) {
00509
try {
00510 URL url = getResource(path);
00511
if (url != null) {
00512
return url.openStream();
00513 }
00514 }
catch (Throwable t) {}
00515
return null;
00516 }
00517
00518
00519
00520
00521
00522
00523
00524
00525 public HSession getSession(String sessionId) {
00526
synchronized (
sessions) {
00527
return (
HSession)
sessions.get(sessionId);
00528 }
00529 }
00530
00531 void removeSession(
HSession session) {
00532
00533
if (
Trace.level() > 1) {
00534
Debug.println(
"removeSession(" + session.
getId() +
")");
00535 }
00536
00537
synchronized (
sessions) {
00538
sessions.remove(session.
getId());
00539 }
00540 }
00541
00542
00543
00544
00545 public HSession createSession() {
00546 String sessionId =
server.
makeSessionId();
00547
00548
if (
Trace.level() > 1) {
00549
Debug.println(
"++++++ createSession(): " + sessionId);
00550 }
00551
00552
HSession session =
new HSession(
this, sessionId,
sessionTimeout);
00553
synchronized (
sessions) {
00554
sessions.put(sessionId, session);
00555 }
00556
return session;
00557 }
00558
00559
00560
00561
00562
00563 public void expireSessions() {
00564
synchronized (
sessions) {
00565 Enumeration e =
sessions.keys();
00566
long now = System.currentTimeMillis();
00567
while (e.hasMoreElements()) {
00568 String sessionId = (String)e.nextElement();
00569
HSession session = (
HSession)getSession(sessionId);
00570
if (now - session.
getLastAccessedTime() >
00571 (session.
getMaxInactiveInterval() * 1000)) {
00572
try {
00573 session.
invalidate();
00574 }
catch (Throwable t) {
00575
Debug.print(t);
00576 }
00577 }
00578 }
00579 }
00580 }
00581
00582
00583
00584
00585
00586
00587 public void log(String msg) {
00588
Debug.println(msg);
00589 }
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599 public void log(Exception e, String msg) {
00600
Debug.println(msg);
00601
Debug.print(e);
00602 }
00603
00604
00605
00606
00607
00608
00609
00610
00611 public void log(String msg, Throwable e) {
00612
Debug.println(msg);
00613
Debug.print(e);
00614 }
00615
00616
00617
00618
00619 public Servlet
getServlet(String name) {
00620
return null;
00621 }
00622
00623
00624
00625
00626 public Enumeration
getServletNames() {
00627
return new Vector().elements();
00628 }
00629
00630
00631
00632
00633 public Enumeration
getServlets() {
00634
return new Vector().elements();
00635 }
00636
00637 public String
getContextPath() {
00638
return contextPath;
00639 }
00640
00641
00642
00643
00644
00645 public String
getContextClassPath() {
00646
return classLoader.
getClassPath();
00647 }
00648
00649 final ClassLoader
getClassLoader() {
00650
return classLoader;
00651 }
00652
00653 final void loadInitialServlets() throws ServletException {
00654 ServletException ex = null;
00655
00656 ArrayList l =
new ArrayList();
00657 l.addAll(
servlets.values());
00658 Collections.sort(l,
new Comparator() {
00659
public int compare(Object a, Object b) {
00660
WebServlet wa = (
WebServlet)a;
00661 WebServlet wb = (WebServlet)b;
00662
if (wa.getLoadOnStartup() < wb.getLoadOnStartup())
return -1;
00663
if (wa.getLoadOnStartup() > wb.getLoadOnStartup())
return 1;
00664
return 0;
00665 }
00666 });
00667
for (
int i = 0; i < l.size(); i++) {
00668 WebServlet w = (WebServlet)l.get(i);
00669
if (w.getLoadOnStartup() >= 0) {
00670
try {
00671 w.init();
00672 }
catch (
ServletException e) {
00673 ex = e;
00674 Debug.print(e);
00675 }
00676 }
00677 }
00678
00679
if (ex != null)
throw ex;
00680 }
00681
00682 public WebServer getWebServer() {
return server; }
00683
00684 public String getRootPath() {
return docRoot.getRootPath(); }
00685
00686 public boolean isDirectory(String d) {
00687
try {
00688
return docRoot.getEntry(d).isDirectory();
00689 }
catch (Throwable t) {
00690
return false;
00691 }
00692 }
00693
00694
00695 public String toString() {
00696
return "[" + contextPath +
"]";
00697 }
00698
00699 }