0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: *
0027: * @author Scott Ferguson
0028: */
0029:
0030: package com.caucho.server.webapp;
0031:
0032: import com.caucho.config.ConfigException;
0033: import com.caucho.lifecycle.Lifecycle;
0034: import com.caucho.loader.ClassLoaderListener;
0035: import com.caucho.loader.DynamicClassLoader;
0036: import com.caucho.loader.Environment;
0037: import com.caucho.loader.EnvironmentClassLoader;
0038: import com.caucho.loader.EnvironmentListener;
0039: import com.caucho.log.Log;
0040: import com.caucho.make.AlwaysModified;
0041: import com.caucho.server.cluster.Server;
0042: import com.caucho.server.deploy.DeployContainer;
0043: import com.caucho.server.deploy.DeployGenerator;
0044: import com.caucho.server.dispatch.DispatchBuilder;
0045: import com.caucho.server.dispatch.DispatchServer;
0046: import com.caucho.server.dispatch.ErrorFilterChain;
0047: import com.caucho.server.dispatch.ExceptionFilterChain;
0048: import com.caucho.server.dispatch.Invocation;
0049: import com.caucho.server.dispatch.InvocationDecoder;
0050: import com.caucho.server.e_app.EarConfig;
0051: import com.caucho.server.e_app.EarDeployController;
0052: import com.caucho.server.e_app.EarDeployGenerator;
0053: import com.caucho.server.e_app.EarSingleDeployGenerator;
0054: import com.caucho.server.host.Host;
0055: import com.caucho.server.log.AbstractAccessLog;
0056: import com.caucho.server.log.AccessLog;
0057: import com.caucho.server.session.SessionManager;
0058: import com.caucho.server.util.CauchoSystem;
0059: import com.caucho.server.rewrite.RewriteDispatch;
0060: import com.caucho.util.L10N;
0061: import com.caucho.util.LruCache;
0062: import com.caucho.vfs.Path;
0063: import com.caucho.vfs.Vfs;
0064:
0065: import javax.annotation.PostConstruct;
0066: import javax.servlet.FilterChain;
0067: import javax.servlet.RequestDispatcher;
0068: import javax.servlet.ServletException;
0069: import javax.servlet.UnavailableException;
0070: import javax.servlet.http.HttpServletResponse;
0071: import java.io.FileNotFoundException;
0072: import java.util.ArrayList;
0073: import java.util.logging.Level;
0074: import java.util.logging.Logger;
0075:
0076: /**
0077: * Resin's webApp implementation.
0078: */
0079: public class WebAppContainer implements DispatchBuilder,
0080: ClassLoaderListener, EnvironmentListener {
0081: static final L10N L = new L10N(WebApp.class);
0082: static final Logger log = Log.open(WebAppContainer.class);
0083:
0084: // The owning dispatch server
0085: private DispatchServer _dispatchServer;
0086:
0087: // The context class loader
0088: private EnvironmentClassLoader _classLoader;
0089:
0090: // The root directory.
0091: private Path _rootDir;
0092:
0093: // The document directory.
0094: private Path _docDir;
0095:
0096: // dispatch mapping
0097: private RewriteDispatch _rewriteDispatch;
0098: private WebApp _errorWebApp;
0099:
0100: // List of default ear webApp configurations
0101: private ArrayList<EarConfig> _earDefaultList = new ArrayList<EarConfig>();
0102:
0103: private DeployContainer<EarDeployController> _earDeploy;
0104: private DeployContainer<WebAppController> _appDeploy;
0105: private WebAppExpandDeployGenerator _warGenerator;
0106:
0107: private boolean _hasWarGenerator;
0108:
0109: // LRU cache for the webApp lookup
0110: private LruCache<String, WebAppController> _uriToAppCache = new LruCache<String, WebAppController>(
0111: 8192);
0112:
0113: // List of default webApp configurations
0114: private ArrayList<WebAppConfig> _webAppDefaultList = new ArrayList<WebAppConfig>();
0115:
0116: private AbstractAccessLog _accessLog;
0117: private ErrorPageManager _errorPageManager;
0118:
0119: private long _startWaitTime = 10000L;
0120:
0121: private Throwable _configException;
0122:
0123: // lifecycle
0124: private final Lifecycle _lifecycle = new Lifecycle();
0125:
0126: /**
0127: * Creates the webApp with its environment loader.
0128: */
0129: public WebAppContainer() {
0130: this ((EnvironmentClassLoader) Thread.currentThread()
0131: .getContextClassLoader());
0132: }
0133:
0134: /**
0135: * Creates the webApp with its environment loader.
0136: */
0137: public WebAppContainer(EnvironmentClassLoader loader) {
0138: _rootDir = Vfs.lookup();
0139: _docDir = Vfs.lookup();
0140:
0141: _classLoader = loader;
0142: _errorPageManager = new ErrorPageManager();
0143: _errorPageManager.setWebAppContainer(this );
0144:
0145: /*
0146: Environment.addEnvironmentListener(this, loader);
0147: Environment.addClassLoaderListener(this, loader);
0148: */
0149:
0150: Thread thread = Thread.currentThread();
0151: ClassLoader oldLoader = thread.getContextClassLoader();
0152: try {
0153: thread.setContextClassLoader(loader);
0154:
0155: // These need to be in the proper class loader so they can
0156: // register themselves with the environment
0157: _earDeploy = new DeployContainer<EarDeployController>();
0158:
0159: _appDeploy = new DeployContainer<WebAppController>();
0160:
0161: _warGenerator = new WebAppExpandDeployGenerator(_appDeploy,
0162: this );
0163: } finally {
0164: thread.setContextClassLoader(oldLoader);
0165: }
0166: }
0167:
0168: /**
0169: * Sets the dispatch server.
0170: */
0171: public void setDispatchServer(DispatchServer server) {
0172: _dispatchServer = server;
0173: }
0174:
0175: /**
0176: * Gets the dispatch server.
0177: */
0178: public DispatchServer getDispatchServer() {
0179: return _dispatchServer;
0180: }
0181:
0182: /**
0183: * Gets the class loader.
0184: */
0185: public ClassLoader getClassLoader() {
0186: return _classLoader;
0187: }
0188:
0189: /**
0190: * sets the class loader.
0191: */
0192: public void setEnvironmentClassLoader(EnvironmentClassLoader loader) {
0193: _classLoader = loader;
0194: }
0195:
0196: /**
0197: * Returns the owning host.
0198: */
0199: public Host getHost() {
0200: return null;
0201: }
0202:
0203: /**
0204: * Gets the root directory.
0205: */
0206: public Path getRootDirectory() {
0207: return _rootDir;
0208: }
0209:
0210: /**
0211: * Sets the root directory.
0212: */
0213: public void setRootDirectory(Path path) {
0214: _rootDir = path;
0215:
0216: Vfs.setPwd(path, getClassLoader());
0217: }
0218:
0219: /**
0220: * Gets the document directory.
0221: */
0222: public Path getDocumentDirectory() {
0223: return _docDir;
0224: }
0225:
0226: /**
0227: * Sets the document directory.
0228: */
0229: public void setDocumentDirectory(Path path) {
0230: _docDir = path;
0231: }
0232:
0233: /**
0234: * Sets the document directory.
0235: */
0236: public void setDocDir(Path path) {
0237: setDocumentDirectory(path);
0238: }
0239:
0240: /**
0241: * Sets the access log.
0242: */
0243: public AbstractAccessLog createAccessLog() {
0244: if (_accessLog == null)
0245: _accessLog = new AccessLog();
0246:
0247: return _accessLog;
0248: }
0249:
0250: /**
0251: * Sets the access log.
0252: */
0253: public void setAccessLog(AbstractAccessLog log) {
0254: _accessLog = log;
0255:
0256: Environment.setAttribute("caucho.server.access-log", log);
0257: }
0258:
0259: /**
0260: * Adds an error page
0261: */
0262: public void addErrorPage(ErrorPage errorPage) {
0263: _errorPageManager.addErrorPage(errorPage);
0264: }
0265:
0266: /**
0267: * Returns the error page manager
0268: */
0269: public ErrorPageManager getErrorPageManager() {
0270: return _errorPageManager;
0271: }
0272:
0273: /**
0274: * Sets a configuration exception.
0275: */
0276: public void setConfigException(Throwable e) {
0277: _configException = e;
0278: }
0279:
0280: /**
0281: * Returns the webApp generator
0282: */
0283: public DeployContainer<WebAppController> getWebAppGenerator() {
0284: return _appDeploy;
0285: }
0286:
0287: /**
0288: * Returns the container's session manager.
0289: */
0290: public SessionManager getSessionManager() {
0291: return null;
0292: }
0293:
0294: /**
0295: * Adds rewrite-dispatch.
0296: */
0297: public RewriteDispatch createRewriteDispatch() {
0298: if (_rewriteDispatch == null) {
0299: _rewriteDispatch = new RewriteDispatch(
0300: (Server) getDispatchServer());
0301: }
0302:
0303: return _rewriteDispatch;
0304: }
0305:
0306: /**
0307: * Returns true if modified.
0308: */
0309: public boolean isModified() {
0310: return _lifecycle.isDestroyed() || _classLoader.isModified();
0311: }
0312:
0313: /**
0314: * Adds an webApp.
0315: */
0316: public void addWebApp(WebAppConfig config) throws Exception {
0317: if (config.getURLRegexp() != null) {
0318: DeployGenerator<WebAppController> deploy = new WebAppRegexpDeployGenerator(
0319: _appDeploy, this , config);
0320: _appDeploy.add(deploy);
0321: return;
0322: }
0323:
0324: WebAppController oldEntry = _appDeploy.findController(config
0325: .getContextPath());
0326:
0327: if (oldEntry != null
0328: && oldEntry.getSourceType().equals("single")) {
0329: throw new ConfigException(L.l(
0330: "duplicate web-app '{0}' forbidden.", config
0331: .getId()));
0332: }
0333:
0334: WebAppSingleDeployGenerator deploy = new WebAppSingleDeployGenerator(
0335: _appDeploy, this , config);
0336: deploy.deploy();
0337:
0338: _appDeploy.add(deploy);
0339:
0340: clearCache();
0341: }
0342:
0343: /**
0344: * Removes an webApp.
0345: */
0346: void removeWebApp(WebAppController entry) {
0347: _appDeploy.remove(entry.getContextPath());
0348:
0349: clearCache();
0350: }
0351:
0352: /**
0353: * Adds a web-app default
0354: */
0355: public void addWebAppDefault(WebAppConfig init) {
0356: _webAppDefaultList.add(init);
0357: }
0358:
0359: /**
0360: * Returns the list of web-app defaults
0361: */
0362: public ArrayList<WebAppConfig> getWebAppDefaultList() {
0363: return _webAppDefaultList;
0364: }
0365:
0366: /**
0367: * Sets the war-expansion
0368: */
0369: public WebAppExpandDeployGenerator createWarDeploy() {
0370: return new WebAppExpandDeployGenerator(_appDeploy, this );
0371: }
0372:
0373: /**
0374: * Sets the war-expansion
0375: */
0376: public WebAppExpandDeployGenerator createWebAppDeploy() {
0377: return createWarDeploy();
0378: }
0379:
0380: /**
0381: * Sets the war-expansion
0382: */
0383: public void addWebAppDeploy(WebAppExpandDeployGenerator deploy)
0384: throws ConfigException {
0385: addWarDeploy(deploy);
0386: }
0387:
0388: /**
0389: * Sets the war-expansion
0390: */
0391: public void addWarDeploy(WebAppExpandDeployGenerator webAppDeploy)
0392: throws ConfigException {
0393: assert webAppDeploy.getContainer() == this ;
0394:
0395: if (!_hasWarGenerator) {
0396: _hasWarGenerator = true;
0397: _warGenerator = webAppDeploy;
0398: }
0399:
0400: _appDeploy.add(webAppDeploy);
0401: }
0402:
0403: /**
0404: * Sets the war-expansion
0405: */
0406: public void addDeploy(DeployGenerator deploy)
0407: throws ConfigException {
0408: if (deploy instanceof WebAppExpandDeployGenerator)
0409: addWebAppDeploy((WebAppExpandDeployGenerator) deploy);
0410: else
0411: _appDeploy.add(deploy);
0412: }
0413:
0414: /**
0415: * Removes a web-app-generator.
0416: */
0417: public void removeWebAppDeploy(DeployGenerator deploy) {
0418: _appDeploy.remove(deploy);
0419: }
0420:
0421: /**
0422: * Updates a WebApp deploy
0423: */
0424: public void updateWebAppDeploy(String name) throws Throwable {
0425: clearCache();
0426:
0427: _appDeploy.update();
0428: WebAppController controller = _appDeploy.update(name);
0429:
0430: if (controller != null) {
0431: Throwable configException = controller.getConfigException();
0432:
0433: if (configException != null)
0434: throw configException;
0435: }
0436: }
0437:
0438: /**
0439: * Adds an enterprise webApp.
0440: */
0441: public void addApplication(EarConfig config) {
0442: DeployGenerator<EarDeployController> deploy = new EarSingleDeployGenerator(
0443: _earDeploy, this , config);
0444:
0445: _earDeploy.add(deploy);
0446: }
0447:
0448: /**
0449: * Updates an ear deploy
0450: */
0451: public void updateEarDeploy(String name) throws Throwable {
0452: clearCache();
0453:
0454: _earDeploy.update();
0455: EarDeployController entry = _earDeploy.update(name);
0456:
0457: if (entry != null) {
0458: entry.start();
0459:
0460: Throwable configException = entry.getConfigException();
0461:
0462: if (configException != null)
0463: throw configException;
0464: }
0465: }
0466:
0467: /**
0468: * Updates an ear deploy
0469: */
0470: public void expandEarDeploy(String name) {
0471: clearCache();
0472:
0473: _earDeploy.update();
0474: EarDeployController entry = _earDeploy.update(name);
0475:
0476: if (entry != null)
0477: entry.start();
0478: }
0479:
0480: /**
0481: * Start an ear
0482: */
0483: public void startEarDeploy(String name) {
0484: clearCache();
0485:
0486: _earDeploy.update();
0487: EarDeployController entry = _earDeploy.update(name);
0488:
0489: if (entry != null)
0490: entry.start();
0491: }
0492:
0493: /**
0494: * Adds an ear default
0495: */
0496: public void addEarDefault(EarConfig config) {
0497: _earDefaultList.add(config);
0498: }
0499:
0500: /**
0501: * Returns the list of ear defaults
0502: */
0503: public ArrayList<EarConfig> getEarDefaultList() {
0504: return _earDefaultList;
0505: }
0506:
0507: /**
0508: * Sets the ear-expansion
0509: */
0510: public EarDeployGenerator createEarDeploy() throws Exception {
0511: return new EarDeployGenerator(_earDeploy, this );
0512: }
0513:
0514: /**
0515: * Adds the ear-expansion
0516: */
0517: public void addEarDeploy(EarDeployGenerator earDeploy)
0518: throws Exception {
0519: _earDeploy.add(earDeploy);
0520:
0521: // server/26cc - _appDeploy must be added first, because the
0522: // _earDeploy addition will automaticall register itself
0523: _appDeploy.add(new WebAppEarDeployGenerator(_appDeploy, this ,
0524: earDeploy));
0525:
0526: /*
0527: _earDeploy.add(earDeploy);
0528: */
0529: }
0530:
0531: /**
0532: * Returns the URL for the container.
0533: */
0534: public String getURL() {
0535: return "";
0536: }
0537:
0538: /**
0539: * Returns the host name for the container.
0540: */
0541: public String getHostName() {
0542: return "";
0543: }
0544:
0545: // backwards compatibility
0546:
0547: /**
0548: * Sets the war-dir for backwards compatibility.
0549: */
0550: public void setWarDir(Path warDir) throws ConfigException {
0551: _warGenerator.setPath(warDir);
0552:
0553: if (!_hasWarGenerator) {
0554: _hasWarGenerator = true;
0555: addWebAppDeploy(_warGenerator);
0556: }
0557: }
0558:
0559: /**
0560: * Gets the war-dir.
0561: */
0562: public Path getWarDir() {
0563: return _warGenerator.getPath();
0564: }
0565:
0566: /**
0567: * Sets the war-expand-dir.
0568: */
0569: public void setWarExpandDir(Path warDir) {
0570: _warGenerator.setExpandDirectory(warDir);
0571: }
0572:
0573: /**
0574: * Gets the war-expand-dir.
0575: */
0576: public Path getWarExpandDir() {
0577: return _warGenerator.getExpandDirectory();
0578: }
0579:
0580: /**
0581: * Init the container.
0582: */
0583: @PostConstruct
0584: public void init() throws Exception {
0585: if (!_lifecycle.toInitializing())
0586: return;
0587:
0588: log.fine(this + " initializing");
0589:
0590: _lifecycle.toInit();
0591: }
0592:
0593: /**
0594: * Starts the container.
0595: */
0596: protected void start() {
0597: if (!_lifecycle.toActive())
0598: return;
0599:
0600: /*
0601: try {
0602: _earDeploy.start();
0603: } catch (Throwable e) {
0604: log.log(Level.WARNING, e.toString(), e);
0605: }
0606: */
0607:
0608: try {
0609: _appDeploy.start();
0610: } catch (ConfigException e) {
0611: log.warning(e.toString());
0612:
0613: if (log.isLoggable(Level.FINE))
0614: log.log(Level.FINE, e.toString(), e);
0615: } catch (Exception e) {
0616: log.log(Level.WARNING, e.toString(), e);
0617: }
0618: }
0619:
0620: /**
0621: * Clears the cache
0622: */
0623: public void clearCache() {
0624: if (_dispatchServer != null)
0625: _dispatchServer.clearCache();
0626:
0627: _uriToAppCache.clear();
0628: }
0629:
0630: /**
0631: * Creates the invocation.
0632: */
0633: public Invocation buildInvocation(Invocation invocation)
0634: throws Exception {
0635: if (_configException != null) {
0636: FilterChain chain = new ExceptionFilterChain(
0637: _configException);
0638: invocation.setFilterChain(chain);
0639: invocation.setDependency(AlwaysModified.create());
0640:
0641: return invocation;
0642: } else if (!_lifecycle.waitForActive(_startWaitTime)) {
0643: int code = HttpServletResponse.SC_SERVICE_UNAVAILABLE;
0644: FilterChain chain = new ErrorFilterChain(code);
0645: invocation.setFilterChain(chain);
0646:
0647: if (_dispatchServer instanceof Server) {
0648: Server server = (Server) _dispatchServer;
0649: invocation.setWebApp(getErrorWebApp());
0650: }
0651:
0652: invocation.setDependency(AlwaysModified.create());
0653:
0654: return invocation;
0655: }
0656:
0657: FilterChain chain;
0658:
0659: WebApp app = getWebApp(invocation, true);
0660:
0661: boolean isAlwaysModified;
0662:
0663: if (app != null) {
0664: invocation = app.buildInvocation(invocation);
0665: chain = invocation.getFilterChain();
0666: isAlwaysModified = false;
0667: } else {
0668: int code = HttpServletResponse.SC_NOT_FOUND;
0669: chain = new ErrorFilterChain(code);
0670: ContextFilterChain contextChain = new ContextFilterChain(
0671: chain);
0672: contextChain.setErrorPageManager(_errorPageManager);
0673: chain = contextChain;
0674: invocation.setFilterChain(contextChain);
0675: isAlwaysModified = true;
0676: }
0677:
0678: if (_rewriteDispatch != null) {
0679: String uri = invocation.getURI();
0680: String queryString = invocation.getQueryString();
0681:
0682: FilterChain rewriteChain = _rewriteDispatch.map(uri,
0683: queryString, chain);
0684:
0685: if (rewriteChain != chain) {
0686: Server server = (Server) _dispatchServer;
0687: // server/13sf
0688: invocation.setWebApp(getErrorWebApp());
0689: invocation.setFilterChain(rewriteChain);
0690: isAlwaysModified = false;
0691: }
0692: }
0693:
0694: if (isAlwaysModified)
0695: invocation.setDependency(AlwaysModified.create());
0696:
0697: return invocation;
0698: }
0699:
0700: /**
0701: * Returns a dispatcher for the named servlet.
0702: */
0703: public RequestDispatcher getRequestDispatcher(String url) {
0704: // Currently no caching since this is only used for the error-page directive at the host level
0705:
0706: if (url == null)
0707: throw new IllegalArgumentException(L
0708: .l("request dispatcher url can't be null."));
0709: else if (!url.startsWith("/"))
0710: throw new IllegalArgumentException(L.l(
0711: "request dispatcher url `{0}' must be absolute",
0712: url));
0713:
0714: Invocation includeInvocation = new Invocation();
0715: Invocation forwardInvocation = new Invocation();
0716: Invocation errorInvocation = new Invocation();
0717: InvocationDecoder decoder = new InvocationDecoder();
0718:
0719: String rawURI = url;
0720:
0721: try {
0722: decoder.splitQuery(includeInvocation, rawURI);
0723: decoder.splitQuery(forwardInvocation, rawURI);
0724: decoder.splitQuery(errorInvocation, rawURI);
0725:
0726: buildIncludeInvocation(includeInvocation);
0727: buildForwardInvocation(forwardInvocation);
0728: buildErrorInvocation(errorInvocation);
0729:
0730: RequestDispatcher disp = new RequestDispatcherImpl(
0731: includeInvocation, forwardInvocation,
0732: errorInvocation,
0733: getWebApp(includeInvocation, false));
0734:
0735: return disp;
0736: } catch (Exception e) {
0737: log.log(Level.FINE, e.toString(), e);
0738:
0739: return null;
0740: }
0741: }
0742:
0743: /**
0744: * Creates the invocation.
0745: */
0746: public void buildIncludeInvocation(Invocation invocation)
0747: throws ServletException {
0748: WebApp app = buildSubInvocation(invocation);
0749:
0750: if (app != null)
0751: app.buildIncludeInvocation(invocation);
0752: }
0753:
0754: /**
0755: * Creates the invocation.
0756: */
0757: public void buildForwardInvocation(Invocation invocation)
0758: throws ServletException {
0759: WebApp app = buildSubInvocation(invocation);
0760:
0761: if (app != null)
0762: app.buildForwardInvocation(invocation);
0763: }
0764:
0765: /**
0766: * Creates the error invocation.
0767: */
0768: public void buildErrorInvocation(Invocation invocation)
0769: throws ServletException {
0770: WebApp app = buildSubInvocation(invocation);
0771:
0772: if (app != null)
0773: app.buildErrorInvocation(invocation);
0774: }
0775:
0776: /**
0777: * Creates the invocation.
0778: */
0779: public void buildLoginInvocation(Invocation invocation)
0780: throws ServletException {
0781: WebApp app = buildSubInvocation(invocation);
0782:
0783: if (app != null)
0784: app.buildErrorInvocation(invocation);
0785: }
0786:
0787: /**
0788: * Creates a sub invocation, handing unmapped URLs and stopped webApps.
0789: */
0790: private WebApp buildSubInvocation(Invocation invocation) {
0791: if (!_lifecycle.waitForActive(_startWaitTime)) {
0792: UnavailableException e;
0793: e = new UnavailableException(invocation.getURI());
0794:
0795: FilterChain chain = new ExceptionFilterChain(e);
0796: invocation.setFilterChain(chain);
0797: invocation.setDependency(AlwaysModified.create());
0798: return null;
0799: }
0800:
0801: WebAppController appController = getWebAppController(invocation);
0802:
0803: if (appController == null) {
0804: String url = invocation.getURI();
0805:
0806: FileNotFoundException e = new FileNotFoundException(url);
0807:
0808: FilterChain chain = new ExceptionFilterChain(e);
0809: invocation.setFilterChain(chain);
0810: invocation.setDependency(AlwaysModified.create());
0811: return null;
0812: }
0813:
0814: WebApp app = appController.subrequest();
0815:
0816: if (app == null) {
0817: UnavailableException e;
0818: e = new UnavailableException(invocation.getURI());
0819:
0820: FilterChain chain = new ExceptionFilterChain(e);
0821: invocation.setFilterChain(chain);
0822: invocation.setDependency(AlwaysModified.create());
0823: return null;
0824: }
0825:
0826: return app;
0827: }
0828:
0829: /**
0830: * Returns the webApp for the current request.
0831: */
0832: private WebApp getWebApp(Invocation invocation,
0833: boolean enableRedeploy) throws ServletException {
0834: try {
0835: WebAppController controller = getWebAppController(invocation);
0836:
0837: if (controller != null) {
0838: WebApp app;
0839:
0840: if (enableRedeploy)
0841: app = controller.request();
0842: else
0843: app = controller.subrequest();
0844:
0845: if (app == null) {
0846: return null;
0847: }
0848:
0849: invocation.setWebApp(app);
0850:
0851: return app;
0852: } else {
0853: return null;
0854: }
0855: } catch (Exception e) {
0856: throw new ServletException(e);
0857: }
0858: }
0859:
0860: /**
0861: * Returns the webApp controller for the current request. Side effect
0862: * of filling in the invocation's context path and context uri.
0863: *
0864: * @param invocation the request's invocation
0865: *
0866: * @return the controller or null if none match the url.
0867: */
0868: private WebAppController getWebAppController(Invocation invocation) {
0869: WebAppController controller = findByURI(invocation.getURI());
0870: if (controller == null)
0871: return null;
0872:
0873: String invocationURI = invocation.getURI();
0874:
0875: String contextPath = controller.getContextPath(invocationURI);
0876:
0877: invocation.setContextPath(invocationURI.substring(0,
0878: contextPath.length()));
0879:
0880: String uri = invocationURI.substring(contextPath.length());
0881: invocation.setContextURI(uri);
0882:
0883: return controller;
0884: }
0885:
0886: /**
0887: * Creates the invocation.
0888: */
0889: public WebApp findWebAppByURI(String uri) throws Exception {
0890: WebAppController controller = findByURI(uri);
0891:
0892: if (controller != null)
0893: return controller.request();
0894: else
0895: return null;
0896: }
0897:
0898: /**
0899: * Creates the invocation.
0900: */
0901: public WebApp findSubWebAppByURI(String uri) throws Exception {
0902: WebAppController controller = findByURI(uri);
0903:
0904: if (controller != null)
0905: return controller.subrequest();
0906: else
0907: return null;
0908: }
0909:
0910: /**
0911: * Finds the web-app matching the current entry.
0912: */
0913: public WebAppController findByURI(String uri) {
0914: if (_appDeploy.isModified())
0915: _uriToAppCache.clear();
0916:
0917: WebAppController controller = _uriToAppCache.get(uri);
0918:
0919: if (controller != null)
0920: return controller;
0921:
0922: String cleanUri = uri;
0923: if (CauchoSystem.isCaseInsensitive())
0924: cleanUri = cleanUri.toLowerCase();
0925:
0926: // server/105w
0927: try {
0928: cleanUri = InvocationDecoder.normalizeUri(cleanUri);
0929: } catch (java.io.IOException e) {
0930: log.log(Level.FINER, e.toString(), e);
0931: }
0932:
0933: controller = findByURIImpl(cleanUri);
0934:
0935: _uriToAppCache.put(uri, controller);
0936:
0937: return controller;
0938: }
0939:
0940: /**
0941: * Finds the web-app for the entry.
0942: */
0943: private WebAppController findByURIImpl(String subURI) {
0944: WebAppController controller = _uriToAppCache.get(subURI);
0945:
0946: if (controller != null) {
0947: return controller;
0948: }
0949:
0950: int length = subURI.length();
0951: int p = subURI.lastIndexOf('/');
0952:
0953: if (p < 0 || p < length - 1) { // server/26cf
0954: controller = _appDeploy.findController(subURI);
0955:
0956: if (controller != null) {
0957: _uriToAppCache.put(subURI, controller);
0958:
0959: return controller;
0960: }
0961: }
0962:
0963: if (p >= 0) {
0964: controller = findByURIImpl(subURI.substring(0, p));
0965:
0966: if (controller != null)
0967: _uriToAppCache.put(subURI, controller);
0968: }
0969:
0970: return controller;
0971: }
0972:
0973: /**
0974: * Finds the web-app for the entry, not checking for sub-apps.
0975: * (used by LocalDeployServlet)
0976: */
0977: public WebAppController findController(String subURI) {
0978: return _appDeploy.findController(subURI);
0979: }
0980:
0981: /**
0982: * Returns a list of the webApps.
0983: */
0984: public ArrayList<WebAppController> getWebAppList() {
0985: return _appDeploy.getControllers();
0986: }
0987:
0988: /**
0989: * Returns a list of the webApps.
0990: */
0991: public ArrayList<EarDeployController> getEntAppList() {
0992: return _earDeploy.getControllers();
0993: }
0994:
0995: /**
0996: * Returns true if the webApp container has been closed.
0997: */
0998: public final boolean isDestroyed() {
0999: return _lifecycle.isDestroyed();
1000: }
1001:
1002: /**
1003: * Returns true if the webApp container is active
1004: */
1005: public final boolean isActive() {
1006: return _lifecycle.isActive();
1007: }
1008:
1009: /**
1010: * Closes the container.
1011: */
1012: public boolean stop() {
1013: if (!_lifecycle.toStop())
1014: return false;
1015:
1016: _earDeploy.stop();
1017: _appDeploy.stop();
1018:
1019: return true;
1020: }
1021:
1022: /**
1023: * Closes the container.
1024: */
1025: public void destroy() {
1026: stop();
1027:
1028: if (!_lifecycle.toDestroy())
1029: return;
1030:
1031: _earDeploy.destroy();
1032: _appDeploy.destroy();
1033: }
1034:
1035: /**
1036: * Returns the error webApp during startup.
1037: */
1038: public WebApp getErrorWebApp() {
1039: if (_errorWebApp == null && _classLoader != null
1040: && !_classLoader.isModified()) {
1041: Thread thread = Thread.currentThread();
1042: ClassLoader loader = thread.getContextClassLoader();
1043: try {
1044: thread.setContextClassLoader(_classLoader);
1045:
1046: _errorWebApp = new WebApp(getRootDirectory().lookup(
1047: "caucho-web-app-error"));
1048: _errorWebApp.setParent(this );
1049: //_errorWebApp.init();
1050: //_errorWebApp.start();
1051: } catch (Throwable e) {
1052: log.log(Level.WARNING, e.toString(), e);
1053: } finally {
1054: thread.setContextClassLoader(loader);
1055: }
1056: }
1057:
1058: return _errorWebApp;
1059: }
1060:
1061: /**
1062: * Handles the case where a class loader has completed initialization
1063: */
1064: public void classLoaderInit(DynamicClassLoader loader) {
1065: }
1066:
1067: /**
1068: * Handles the case where a class loader is dropped.
1069: */
1070: public void classLoaderDestroy(DynamicClassLoader loader) {
1071: destroy();
1072: }
1073:
1074: /**
1075: * Handles the environment config phase
1076: */
1077: public void environmentConfig(EnvironmentClassLoader loader) {
1078: }
1079:
1080: /**
1081: * Handles the case where the environment is starting (after init).
1082: */
1083: public void environmentStart(EnvironmentClassLoader loader) {
1084: }
1085:
1086: /**
1087: * Handles the case where the environment is stopping
1088: */
1089: public void environmentStop(EnvironmentClassLoader loader) {
1090: stop();
1091: }
1092: }
|