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.cluster;
0031:
0032: import com.caucho.config.ConfigException;
0033: import com.caucho.config.SchemaBean;
0034: import com.caucho.config.types.Bytes;
0035: import com.caucho.config.types.Period;
0036: import com.caucho.lifecycle.Lifecycle;
0037: import com.caucho.loader.ClassLoaderListener;
0038: import com.caucho.loader.DynamicClassLoader;
0039: import com.caucho.loader.Environment;
0040: import com.caucho.loader.EnvironmentBean;
0041: import com.caucho.loader.EnvironmentClassLoader;
0042: import com.caucho.loader.EnvironmentLocal;
0043: import com.caucho.make.AlwaysModified;
0044: import com.caucho.management.server.CacheItem;
0045: import com.caucho.management.server.ServerMXBean;
0046: import com.caucho.security.PermissionManager;
0047: import com.caucho.server.admin.Management;
0048: import com.caucho.server.cache.AbstractCache;
0049: import com.caucho.server.dispatch.ErrorFilterChain;
0050: import com.caucho.server.dispatch.ExceptionFilterChain;
0051: import com.caucho.server.dispatch.Invocation;
0052: import com.caucho.server.dispatch.InvocationMatcher;
0053: import com.caucho.server.e_app.EarConfig;
0054: import com.caucho.server.host.Host;
0055: import com.caucho.server.host.HostConfig;
0056: import com.caucho.server.host.HostContainer;
0057: import com.caucho.server.host.HostController;
0058: import com.caucho.server.host.HostExpandDeployGenerator;
0059: import com.caucho.server.log.AccessLog;
0060: import com.caucho.server.port.AbstractSelectManager;
0061: import com.caucho.server.port.Port;
0062: import com.caucho.server.port.ProtocolDispatchServer;
0063: import com.caucho.server.resin.Resin;
0064: import com.caucho.server.rewrite.RewriteDispatch;
0065: import com.caucho.server.webapp.ErrorPage;
0066: import com.caucho.server.webapp.WebApp;
0067: import com.caucho.server.webapp.WebAppConfig;
0068: import com.caucho.util.Alarm;
0069: import com.caucho.util.AlarmListener;
0070: import com.caucho.util.L10N;
0071: import com.caucho.util.ThreadPool;
0072: import com.caucho.vfs.Path;
0073: import com.caucho.vfs.Vfs;
0074:
0075: import javax.annotation.PostConstruct;
0076: import javax.servlet.http.HttpServletResponse;
0077: import javax.resource.spi.ResourceAdapter;
0078: import java.lang.reflect.Method;
0079: import java.util.ArrayList;
0080: import java.util.Collection;
0081: import java.util.Collections;
0082: import java.util.HashMap;
0083: import java.util.logging.Level;
0084: import java.util.logging.Logger;
0085: import java.util.regex.Matcher;
0086: import java.util.regex.Pattern;
0087:
0088: public class Server extends ProtocolDispatchServer implements
0089: EnvironmentBean, SchemaBean, AlarmListener, ClassLoaderListener {
0090: private static final L10N L = new L10N(Server.class);
0091: private static final Logger log = Logger.getLogger(Server.class
0092: .getName());
0093:
0094: private static final long ALARM_INTERVAL = 60000;
0095:
0096: private static final EnvironmentLocal<String> _serverIdLocal = new EnvironmentLocal<String>(
0097: "caucho.server-id");
0098:
0099: private final ClusterServer _clusterServer;
0100: private final Resin _resin;
0101:
0102: private EnvironmentClassLoader _classLoader;
0103:
0104: private Throwable _configException;
0105:
0106: private HostContainer _hostContainer;
0107:
0108: private String _serverHeader = "Resin/"
0109: + com.caucho.Version.VERSION;
0110:
0111: private String _url = "";
0112:
0113: private int _srunCount;
0114:
0115: private AccessLog _accessLog;
0116:
0117: private long _waitForActiveTime = 10000L;
0118:
0119: // <server> configuration compat
0120: private int _acceptListenBacklog = 100;
0121:
0122: private int _acceptThreadMin = 5;
0123: private int _acceptThreadMax = 10;
0124:
0125: private int _keepaliveMax = 128;
0126:
0127: private long _keepaliveConnectionTimeMax = 10 * 60 * 1000L;
0128:
0129: private boolean _keepaliveSelectEnable = true;
0130: private int _keepaliveSelectMax = -1;
0131: private long _keepaliveSelectThreadTimeout = 1000;
0132:
0133: private Management _management;
0134:
0135: private long _suspendTimeMax = 600000;
0136:
0137: private long _memoryFreeMin = 1024 * 1024;
0138:
0139: private long _shutdownWaitMax = 60 * 1000;
0140:
0141: private int _threadMax = 4096;
0142: private int _threadExecutorTaskMax = -1;
0143: private int _threadIdleMin = 5;
0144: private int _threadIdleMax = 10;
0145:
0146: // <cluster> configuration
0147:
0148: private String _connectionErrorPage;
0149:
0150: private ServerAdmin _admin;
0151:
0152: private Alarm _alarm;
0153: private AbstractCache _cache;
0154:
0155: private boolean _isBindPortsAtEnd = true;
0156: private volatile boolean _isStartedPorts;
0157:
0158: private long _startTime;
0159:
0160: private final Lifecycle _lifecycle;
0161:
0162: /**
0163: * Creates a new servlet server.
0164: */
0165: public Server(ClusterServer clusterServer) {
0166: if (clusterServer == null)
0167: throw new NullPointerException();
0168:
0169: _clusterServer = clusterServer;
0170: _resin = _clusterServer.getCluster().getResin();
0171:
0172: try {
0173: Thread thread = Thread.currentThread();
0174:
0175: ClassLoader loader = clusterServer.getCluster()
0176: .getClassLoader();
0177: _classLoader = (EnvironmentClassLoader) loader;
0178:
0179: Environment.addClassLoaderListener(this , _classLoader);
0180:
0181: PermissionManager permissionManager = new PermissionManager();
0182: PermissionManager.setPermissionManager(permissionManager);
0183:
0184: ClassLoader oldLoader = thread.getContextClassLoader();
0185:
0186: try {
0187: thread.setContextClassLoader(_classLoader);
0188:
0189: _serverIdLocal.set(_clusterServer.getId());
0190:
0191: _hostContainer = new HostContainer();
0192: _hostContainer.setClassLoader(_classLoader);
0193: _hostContainer.setDispatchServer(this );
0194:
0195: _admin = new ServerAdmin(this );
0196:
0197: _alarm = new Alarm(this );
0198:
0199: _clusterServer.getServerProgram().configure(this );
0200: } finally {
0201: thread.setContextClassLoader(oldLoader);
0202: }
0203: } catch (Throwable e) {
0204: log.log(Level.WARNING, e.toString(), e);
0205:
0206: _configException = e;
0207: } finally {
0208: _lifecycle = new Lifecycle(log, toString(), Level.INFO);
0209: }
0210: }
0211:
0212: /**
0213: * Returns the classLoader
0214: */
0215: public ClassLoader getClassLoader() {
0216: return _classLoader;
0217: }
0218:
0219: /**
0220: * Returns the configuration exception
0221: */
0222: public Throwable getConfigException() {
0223: return _configException;
0224: }
0225:
0226: /**
0227: * Returns the configuration instance.
0228: */
0229: public void setConfigException(Throwable exn) {
0230: _configException = exn;
0231: }
0232:
0233: //
0234: // Configuration from <server>
0235: //
0236:
0237: /**
0238: * Sets the socket's listen property
0239: */
0240: public void setAcceptListenBacklog(int backlog) {
0241: _acceptListenBacklog = backlog;
0242: }
0243:
0244: /**
0245: * Gets the socket's listen property
0246: */
0247: public int getAcceptListenBacklog() {
0248: return _acceptListenBacklog;
0249: }
0250:
0251: /**
0252: * Sets the minimum spare listen.
0253: */
0254: public void setAcceptThreadMin(int minSpare) throws ConfigException {
0255: if (minSpare < 1)
0256: throw new ConfigException(L
0257: .l("accept-thread-max must be at least 1."));
0258:
0259: _acceptThreadMin = minSpare;
0260: }
0261:
0262: /**
0263: * Gets the minimum spare listen.
0264: */
0265: public int getAcceptThreadMin() {
0266: return _acceptThreadMin;
0267: }
0268:
0269: /**
0270: * Sets the maximum spare listen.
0271: */
0272: public void setAcceptThreadMax(int maxSpare) throws ConfigException {
0273: if (maxSpare < 1)
0274: throw new ConfigException(L
0275: .l("accept-thread-max must be at least 1."));
0276:
0277: _acceptThreadMax = maxSpare;
0278: }
0279:
0280: /**
0281: * Sets the maximum spare listen.
0282: */
0283: public int getAcceptThreadMax() {
0284: return _acceptThreadMax;
0285: }
0286:
0287: /**
0288: * Sets the minimum free memory after a GC
0289: */
0290: public void setMemoryFreeMin(Bytes min) {
0291: _memoryFreeMin = min.getBytes();
0292: }
0293:
0294: /**
0295: * Sets the minimum free memory after a GC
0296: */
0297: public long getMemoryFreeMin() {
0298: return _memoryFreeMin;
0299: }
0300:
0301: /**
0302: * Sets the maximum keepalive
0303: */
0304: public void setKeepaliveMax(int max) {
0305: _keepaliveMax = max;
0306: }
0307:
0308: /**
0309: * Returns the thread-based keepalive max.
0310: *
0311: * @return the keepalive max.
0312: */
0313: public int getKeepaliveMax() {
0314: return _keepaliveMax;
0315: }
0316:
0317: /**
0318: * Sets the keepalive timeout
0319: */
0320: public void setKeepaliveTimeout(Period period) {
0321: _clusterServer.setKeepaliveTimeout(period);
0322: }
0323:
0324: /**
0325: * Sets the keepalive timeout
0326: */
0327: public long getKeepaliveTimeout() {
0328: return _clusterServer.getKeepaliveTimeout();
0329: }
0330:
0331: /**
0332: * Sets the keepalive connection timeout
0333: */
0334: public void setKeepaliveConnectionTimeMax(Period period) {
0335: _keepaliveConnectionTimeMax = period.getPeriod();
0336: }
0337:
0338: /**
0339: * Sets the keepalive timeout
0340: */
0341: public long getKeepaliveConnectionTimeMax() {
0342: return _keepaliveConnectionTimeMax;
0343: }
0344:
0345: /**
0346: * Sets the select-based keepalive timeout
0347: */
0348: public void setKeepaliveSelectEnable(boolean enable) {
0349: _keepaliveSelectEnable = enable;
0350: }
0351:
0352: /**
0353: * Sets the select-based keepalive timeout
0354: */
0355: public void setKeepaliveSelectMax(int max) {
0356: _keepaliveSelectMax = max;
0357: }
0358:
0359: /**
0360: * Gets the select-based keepalive timeout
0361: */
0362: public boolean isKeepaliveSelectEnable() {
0363: return _keepaliveSelectEnable;
0364: }
0365:
0366: /**
0367: * Sets the select-based keepalive timeout
0368: */
0369: public void getKeepaliveSelectThreadTimeout(Period period) {
0370: _keepaliveSelectThreadTimeout = period.getPeriod();
0371: }
0372:
0373: /**
0374: * Sets the select-based keepalive timeout
0375: */
0376: public long getKeepaliveSelectThreadTimeout() {
0377: return _keepaliveSelectThreadTimeout;
0378: }
0379:
0380: public Management createManagement() {
0381: if (_management == null && _resin != null) {
0382: _management = _resin.createManagement();
0383:
0384: _management.setCluster(getCluster());
0385: }
0386:
0387: return _management;
0388: }
0389:
0390: /**
0391: * Sets the redeploy mode
0392: */
0393: public void setRedeployMode(String redeployMode) {
0394: }
0395:
0396: /**
0397: * Sets the max wait time for shutdown.
0398: */
0399: public void setShutdownWaitMax(Period waitTime) {
0400: _shutdownWaitMax = waitTime.getPeriod();
0401: }
0402:
0403: /**
0404: * Sets the suspend timeout
0405: */
0406: public void setSuspendTimeMax(Period period) {
0407: _suspendTimeMax = period.getPeriod();
0408: }
0409:
0410: /**
0411: * Sets the suspend timeout
0412: */
0413: public long getSuspendTimeMax() {
0414: return _suspendTimeMax;
0415: }
0416:
0417: /**
0418: * Gets the max wait time for a shutdown.
0419: */
0420: public long getShutdownWaitMax() {
0421: return _shutdownWaitMax;
0422: }
0423:
0424: /**
0425: * Sets the default read/write timeout for the request sockets.
0426: */
0427: public void setSocketTimeout(Period period) {
0428: _clusterServer.setSocketTimeout(period);
0429: }
0430:
0431: /**
0432: * Gets the read timeout for the request sockets.
0433: */
0434: public long getSocketTimeout() {
0435: return _clusterServer.getSocketTimeout();
0436: }
0437:
0438: /**
0439: * Sets the maximum thread-based keepalive
0440: */
0441: public void setThreadMax(int max) {
0442: if (max < 0)
0443: throw new ConfigException(L.l(
0444: "<thread-max> ({0}) must be greater than zero.",
0445: max));
0446:
0447: _threadMax = max;
0448: }
0449:
0450: /**
0451: * Sets the maximum executor (background) thread.
0452: */
0453: public void setThreadExecutorTaskMax(int max) {
0454: _threadExecutorTaskMax = max;
0455: }
0456:
0457: /**
0458: * Sets the minimum number of idle threads in the thread pool.
0459: */
0460: public void setThreadIdleMin(int min) {
0461: _threadIdleMin = min;
0462: }
0463:
0464: /**
0465: * Sets the maximum number of idle threads in the thread pool.
0466: */
0467: public void setThreadIdleMax(int max) {
0468: _threadIdleMax = max;
0469: }
0470:
0471: //
0472: // Configuration from <cluster>
0473: //
0474:
0475: /**
0476: * Sets the connection error page.
0477: */
0478: public void setConnectionErrorPage(String errorPage) {
0479: _connectionErrorPage = errorPage;
0480: }
0481:
0482: /**
0483: * Gets the connection error page.
0484: */
0485: public String getConnectionErrorPage() {
0486: return _connectionErrorPage;
0487: }
0488:
0489: /**
0490: * Return true if idle.
0491: */
0492: public boolean isDeployError() {
0493: return _configException != null;
0494: }
0495:
0496: /**
0497: * Returns the relax schema.
0498: */
0499: public String getSchema() {
0500: return "com/caucho/server/resin/cluster.rnc";
0501: }
0502:
0503: /**
0504: * Returns the id.
0505: */
0506: public String getServerId() {
0507: return _clusterServer.getId();
0508: }
0509:
0510: /**
0511: * Sets the root directory.
0512: */
0513: public void setRootDirectory(Path path) {
0514: _hostContainer.setRootDirectory(path);
0515:
0516: Vfs.setPwd(path, _classLoader);
0517: }
0518:
0519: /**
0520: * Sets the root directory.
0521: */
0522: public Path getRootDirectory() {
0523: return _hostContainer.getRootDirectory();
0524: }
0525:
0526: /**
0527: * Sets the root directory.
0528: */
0529: public void setRootDir(Path path) {
0530: setRootDirectory(path);
0531: }
0532:
0533: /**
0534: * Sets the server header.
0535: */
0536: public void setServerHeader(String server) {
0537: _serverHeader = server;
0538: }
0539:
0540: /**
0541: * Gets the server header.
0542: */
0543: public String getServerHeader() {
0544: return _serverHeader;
0545: }
0546:
0547: /**
0548: * Adds a WebAppDefault.
0549: */
0550: public void addWebAppDefault(WebAppConfig init) {
0551: _hostContainer.addWebAppDefault(init);
0552: }
0553:
0554: /**
0555: * Adds an EarDefault
0556: */
0557: public void addEarDefault(EarConfig config) {
0558: _hostContainer.addEarDefault(config);
0559: }
0560:
0561: /**
0562: * Adds a HostDefault.
0563: */
0564: public void addHostDefault(HostConfig init) {
0565: _hostContainer.addHostDefault(init);
0566: }
0567:
0568: /**
0569: * Adds a HostDeploy.
0570: */
0571: public HostExpandDeployGenerator createHostDeploy() {
0572: return _hostContainer.createHostDeploy();
0573: }
0574:
0575: /**
0576: * Adds a HostDeploy.
0577: */
0578: public void addHostDeploy(HostExpandDeployGenerator deploy) {
0579: _hostContainer.addHostDeploy(deploy);
0580: }
0581:
0582: /**
0583: * Adds the host.
0584: */
0585: public void addHost(HostConfig host) throws Exception {
0586: _hostContainer.addHost(host);
0587: }
0588:
0589: /**
0590: * Returns the cluster.
0591: */
0592: public Cluster getCluster() {
0593: return _clusterServer.getCluster();
0594: }
0595:
0596: /**
0597: * Adds rewrite-dispatch.
0598: */
0599: public RewriteDispatch createRewriteDispatch() {
0600: return _hostContainer.createRewriteDispatch();
0601: }
0602:
0603: /**
0604: * Adds the cache.
0605: */
0606: public AbstractCache createCache() throws ConfigException {
0607: try {
0608: Class cl = Class.forName("com.caucho.server.cache.Cache");
0609:
0610: _cache = (AbstractCache) cl.newInstance();
0611: } catch (Throwable e) {
0612: e.printStackTrace();
0613: }
0614:
0615: if (_cache == null) {
0616: throw new ConfigException(
0617: L
0618: .l("<cache> requires Resin Professional. Please see http://www.caucho.com for Resin Professional information and licensing."));
0619: }
0620:
0621: return _cache;
0622: }
0623:
0624: /**
0625: * Sets the access log.
0626: */
0627: public void setAccessLog(AccessLog log) {
0628: _accessLog = log;
0629:
0630: Environment.setAttribute("caucho.server.access-log", log);
0631: }
0632:
0633: /**
0634: * Returns the dependency check interval.
0635: */
0636: public long getDependencyCheckInterval() {
0637: return Environment.getDependencyCheckInterval(getClassLoader());
0638: }
0639:
0640: /**
0641: * Sets the session cookie
0642: */
0643: public void setSessionCookie(String cookie) {
0644: getInvocationDecoder().setSessionCookie(cookie);
0645: }
0646:
0647: /**
0648: * Gets the session cookie
0649: */
0650: public String getSessionCookie() {
0651: return getInvocationDecoder().getSessionCookie();
0652: }
0653:
0654: /**
0655: * Sets the ssl session cookie
0656: */
0657: public void setSSLSessionCookie(String cookie) {
0658: getInvocationDecoder().setSSLSessionCookie(cookie);
0659: }
0660:
0661: /**
0662: * Gets the ssl session cookie
0663: */
0664: public String getSSLSessionCookie() {
0665: return getInvocationDecoder().getSSLSessionCookie();
0666: }
0667:
0668: /**
0669: * Sets the session url prefix.
0670: */
0671: public void setSessionURLPrefix(String urlPrefix) {
0672: getInvocationDecoder().setSessionURLPrefix(urlPrefix);
0673: }
0674:
0675: /**
0676: * Gets the session url prefix.
0677: */
0678: public String getSessionURLPrefix() {
0679: return getInvocationDecoder().getSessionURLPrefix();
0680: }
0681:
0682: /**
0683: * Sets the alternate session url prefix.
0684: */
0685: public void setAlternateSessionURLPrefix(String urlPrefix)
0686: throws ConfigException {
0687: getInvocationDecoder().setAlternateSessionURLPrefix(urlPrefix);
0688: }
0689:
0690: /**
0691: * Gets the alternate session url prefix.
0692: */
0693: public String getAlternateSessionURLPrefix() {
0694: return getInvocationDecoder().getAlternateSessionURLPrefix();
0695: }
0696:
0697: /**
0698: * Sets URL encoding.
0699: */
0700: public void setURLCharacterEncoding(String encoding)
0701: throws ConfigException {
0702: getInvocationDecoder().setEncoding(encoding);
0703: }
0704:
0705: /**
0706: * Creates the ping.
0707: */
0708: @Deprecated
0709: public ResourceAdapter createPing() throws ConfigException {
0710: return createManagement().createPing();
0711: }
0712:
0713: /**
0714: * Adds the ping.
0715: */
0716: @Deprecated
0717: public void addPing(ResourceAdapter ping) throws ConfigException {
0718: createManagement().addPing(ping);
0719: }
0720:
0721: /**
0722: * Sets true if the select manager should be enabled
0723: */
0724: @Override
0725: public boolean isSelectManagerEnabled() {
0726: return getSelectManager() != null;
0727: }
0728:
0729: public void addSelectManager(SelectManagerCompat selectManager) {
0730:
0731: }
0732:
0733: /**
0734: * Returns the number of select keepalives available.
0735: */
0736: public int getFreeKeepaliveSelect() {
0737: AbstractSelectManager selectManager = getSelectManager();
0738:
0739: if (selectManager != null)
0740: return selectManager.getFreeKeepalive();
0741: else
0742: return Integer.MAX_VALUE / 2;
0743: }
0744:
0745: /**
0746: * Adds an error page
0747: */
0748: public void addErrorPage(ErrorPage errorPage) {
0749: getErrorWebApp().addErrorPage(errorPage);
0750: }
0751:
0752: //
0753: // cluster server information
0754: //
0755: public int getServerIndex() {
0756: return _clusterServer.getIndex();
0757: }
0758:
0759: //
0760: // statistics
0761: //
0762:
0763: /**
0764: * Returns the time the server started in ms.
0765: */
0766: public long getStartTime() {
0767: return _startTime;
0768: }
0769:
0770: /**
0771: * Returns the lifecycle state
0772: */
0773: public String getState() {
0774: return _lifecycle.getStateName();
0775: }
0776:
0777: /**
0778: * Returns the select keepalive count.
0779: */
0780: public int getKeepaliveSelectCount() {
0781: AbstractSelectManager selectManager = getSelectManager();
0782:
0783: if (selectManager != null)
0784: return selectManager.getSelectCount();
0785: else
0786: return -1;
0787: }
0788:
0789: /**
0790: * Returns the cache stuff.
0791: */
0792: public ArrayList<CacheItem> getCacheStatistics() {
0793: ArrayList<Invocation> invocationList = getInvocations();
0794:
0795: if (invocationList == null)
0796: return null;
0797:
0798: HashMap<String, CacheItem> itemMap = new HashMap<String, CacheItem>();
0799:
0800: for (int i = 0; i < invocationList.size(); i++) {
0801: Invocation inv = (Invocation) invocationList.get(i);
0802:
0803: String uri = inv.getURI();
0804: int p = uri.indexOf('?');
0805: if (p >= 0)
0806: uri = uri.substring(0, p);
0807:
0808: CacheItem item = itemMap.get(uri);
0809:
0810: if (item == null) {
0811: item = new CacheItem();
0812: item.setUrl(uri);
0813:
0814: itemMap.put(uri, item);
0815: }
0816: }
0817:
0818: return null;
0819: }
0820:
0821: //
0822: // runtime operations
0823: //
0824:
0825: /**
0826: * Sets the invocation
0827: */
0828: public Invocation buildInvocation(Invocation invocation)
0829: throws Throwable {
0830: if (_configException != null) {
0831: invocation.setFilterChain(new ExceptionFilterChain(
0832: _configException));
0833: invocation.setWebApp(getErrorWebApp());
0834: invocation.setDependency(AlwaysModified.create());
0835:
0836: return invocation;
0837: } else if (_lifecycle.waitForActive(_waitForActiveTime)) {
0838: return _hostContainer.buildInvocation(invocation);
0839: } else {
0840: int code = HttpServletResponse.SC_SERVICE_UNAVAILABLE;
0841:
0842: invocation.setFilterChain(new ErrorFilterChain(code));
0843: invocation.setWebApp(getErrorWebApp());
0844: invocation.setDependency(AlwaysModified.create());
0845:
0846: return invocation;
0847: }
0848: }
0849:
0850: /**
0851: * Returns the matching servlet pattern for a URL.
0852: */
0853: public String getServletPattern(String hostName, int port,
0854: String url) {
0855: try {
0856: Host host = _hostContainer.getHost(hostName, port);
0857:
0858: if (host == null)
0859: return null;
0860:
0861: WebApp app = host.findWebAppByURI(url);
0862:
0863: if (app == null)
0864: return null;
0865:
0866: String pattern = app.getServletPattern(url);
0867:
0868: return pattern;
0869: } catch (Throwable e) {
0870: log.log(Level.WARNING, e.toString(), e);
0871:
0872: return null;
0873: }
0874: }
0875:
0876: /**
0877: * Returns the admin.
0878: */
0879: public ServerMXBean getAdmin() {
0880: return _admin;
0881: }
0882:
0883: /**
0884: * Returns the default web-app or error web-app for top-level errors
0885: */
0886: public WebApp getDefaultWebApp() {
0887: WebApp webApp = getWebApp("", 80, "");
0888:
0889: if (webApp != null)
0890: return webApp;
0891: else
0892: return getErrorWebApp();
0893: }
0894:
0895: /**
0896: * Returns the matching web-app for a URL.
0897: */
0898: public WebApp getWebApp(String hostName, int port, String url) {
0899: try {
0900: HostContainer hostContainer = _hostContainer;
0901:
0902: if (hostContainer == null)
0903: return null;
0904:
0905: Host host = hostContainer.getHost(hostName, port);
0906:
0907: if (host == null)
0908: return null;
0909:
0910: return host.findWebAppByURI(url);
0911: } catch (Throwable e) {
0912: log.log(Level.WARNING, e.toString(), e);
0913:
0914: return null;
0915: }
0916: }
0917:
0918: /**
0919: * Returns the error webApp during startup.
0920: */
0921: public WebApp getErrorWebApp() {
0922: HostContainer hostContainer = _hostContainer;
0923:
0924: if (hostContainer != null)
0925: return hostContainer.getErrorWebApp();
0926: else
0927: return null;
0928: }
0929:
0930: /**
0931: * Returns the host controllers.
0932: */
0933: public Collection<HostController> getHostControllers() {
0934: HostContainer hostContainer = _hostContainer;
0935:
0936: if (hostContainer == null)
0937: return Collections.emptyList();
0938:
0939: return Collections
0940: .unmodifiableList(hostContainer.getHostList());
0941: }
0942:
0943: /**
0944: * Returns the matching servlet pattern for a URL.
0945: */
0946: public Host getHost(String hostName, int port) {
0947: try {
0948: return _hostContainer.getHost(hostName, port);
0949: } catch (Throwable e) {
0950: log.log(Level.WARNING, e.toString(), e);
0951:
0952: return null;
0953: }
0954: }
0955:
0956: /**
0957: * If true, ports are bound at end.
0958: */
0959: public void setBindPortsAfterStart(boolean bindAtEnd) {
0960: _isBindPortsAtEnd = bindAtEnd;
0961: }
0962:
0963: /**
0964: * If true, ports are bound at end.
0965: */
0966: public boolean isBindPortsAfterStart() {
0967: return _isBindPortsAtEnd;
0968: }
0969:
0970: /**
0971: * Returns the {@link Port}s for this server.
0972: */
0973: public Collection<Port> getPorts() {
0974: return Collections.unmodifiableList(_clusterServer.getPorts());
0975: }
0976:
0977: /**
0978: * Handles the case where a class loader is activated.
0979: */
0980: public void classLoaderInit(DynamicClassLoader loader) {
0981: try {
0982: //Jmx.register(_controller.getThreadPool(), "resin:type=ThreadPool");
0983: } catch (Exception e) {
0984: log.log(Level.WARNING, e.toString(), e);
0985: }
0986: }
0987:
0988: /**
0989: * Handles the case where a class loader is dropped.
0990: */
0991: public void classLoaderDestroy(DynamicClassLoader loader) {
0992: /*
0993: try {
0994: Jmx.unregister("resin:name=default,type=Server");
0995: Jmx.unregister("resin:type=ThreadPool");
0996: } catch (Throwable e) {
0997: log.log(Level.FINEST, e.toString(), e);
0998: }
0999: */
1000: }
1001:
1002: /**
1003: * Initialization.
1004: */
1005: @PostConstruct
1006: public void init() {
1007: _classLoader.init();
1008:
1009: super .init();
1010:
1011: // backwards compat
1012: if (_resin != null && _resin.getManagementPath() != null)
1013: createManagement().setManagementPath(
1014: _resin.getManagementPath());
1015:
1016: if (_resin != null) {
1017: createManagement().setCluster(getCluster());
1018: createManagement().setServer(this );
1019: createManagement().init();
1020: }
1021:
1022: if (_threadMax < _threadIdleMax)
1023: throw new ConfigException(
1024: L
1025: .l(
1026: "<thread-idle-max> ({0}) must be less than <thread-max> ({1})",
1027: _threadIdleMax, _threadMax));
1028:
1029: if (_threadIdleMax < _threadIdleMin)
1030: throw new ConfigException(
1031: L
1032: .l(
1033: "<thread-idle-min> ({0}) must be less than <thread-idle-max> ({1})",
1034: _threadIdleMin, _threadIdleMax));
1035:
1036: if (_threadMax < _threadExecutorTaskMax)
1037: throw new ConfigException(
1038: L
1039: .l(
1040: "<thread-executor-task-max> ({0}) must be less than <thread-max> ({1})",
1041: _threadExecutorTaskMax, _threadMax));
1042:
1043: ThreadPool threadPool = ThreadPool.getThreadPool();
1044:
1045: threadPool.setThreadMax(_threadMax);
1046: threadPool.setThreadIdleMax(_threadIdleMax);
1047: threadPool.setThreadIdleMin(_threadIdleMin);
1048: threadPool.setExecutorTaskMax(_threadExecutorTaskMax);
1049:
1050: if (_keepaliveSelectEnable) {
1051: try {
1052: Class cl = Class
1053: .forName("com.caucho.server.port.JniSelectManager");
1054: Method method = cl.getMethod("create", new Class[0]);
1055:
1056: initSelectManager((AbstractSelectManager) method
1057: .invoke(null, null));
1058: } catch (ClassNotFoundException e) {
1059: log
1060: .warning(L
1061: .l("'select-manager' requires Resin Professional. See http://www.caucho.com for information and licensing."));
1062: } catch (Throwable e) {
1063: log.warning(L.l("Cannot enable select-manager {0}", e
1064: .toString()));
1065:
1066: log.log(Level.FINER, e.toString());
1067: }
1068:
1069: if (getSelectManager() != null) {
1070: if (_keepaliveSelectMax > 0)
1071: getSelectManager()
1072: .setSelectMax(_keepaliveSelectMax);
1073: }
1074: }
1075: }
1076:
1077: /**
1078: * Start the server.
1079: */
1080: public void start() {
1081: init();
1082:
1083: Thread thread = Thread.currentThread();
1084: ClassLoader oldLoader = thread.getContextClassLoader();
1085: try {
1086: thread.setContextClassLoader(_classLoader);
1087:
1088: if (!_lifecycle.toStarting())
1089: return;
1090:
1091: _startTime = Alarm.getCurrentTime();
1092:
1093: if (!Alarm.isTest()) {
1094: log.info("");
1095:
1096: log.info(System.getProperty("os.name") + " "
1097: + System.getProperty("os.version") + " "
1098: + System.getProperty("os.arch"));
1099:
1100: log.info("Java "
1101: + System.getProperty("java.vm.version") + ", "
1102: + System.getProperty("sun.arch.data.model")
1103: + ", " + System.getProperty("java.vm.info")
1104: + ", " + System.getProperty("file.encoding")
1105: + ", " + System.getProperty("user.language")
1106: + ", " + System.getProperty("java.vm.vendor"));
1107:
1108: log.info("user.name: "
1109: + System.getProperty("user.name"));
1110:
1111: Resin resin = Resin.getLocal();
1112:
1113: if (resin != null) {
1114: log.info("resin.home = "
1115: + resin.getResinHome().getNativePath());
1116: log.info("resin.root = "
1117: + resin.getRootDirectory().getNativePath());
1118: log.info("resin.conf = " + resin.getResinConf());
1119: } else {
1120: log.info("resin.home = "
1121: + System.getProperty("resin.home"));
1122: }
1123:
1124: log.info("");
1125: }
1126:
1127: _lifecycle.toStarting();
1128:
1129: if (_resin != null && _resin.getManagement() != null)
1130: _resin.getManagement().start(this );
1131:
1132: AbstractSelectManager selectManager = getSelectManager();
1133:
1134: if (!_keepaliveSelectEnable || selectManager == null
1135: || !selectManager.start()) {
1136: initSelectManager(null);
1137: }
1138:
1139: if (!_isBindPortsAtEnd) {
1140: bindPorts();
1141: startPorts();
1142: }
1143:
1144: _classLoader.start();
1145:
1146: _hostContainer.start();
1147:
1148: // will only occur if bind-ports-at-end is true
1149: if (_isBindPortsAtEnd) {
1150: bindPorts();
1151: startPorts();
1152: }
1153:
1154: _alarm.queue(ALARM_INTERVAL);
1155:
1156: _lifecycle.toActive();
1157: } catch (RuntimeException e) {
1158: _lifecycle.toError();
1159:
1160: throw e;
1161: } catch (Exception e) {
1162: _lifecycle.toError();
1163:
1164: // if the server can't start, it needs to completely fail, especially
1165: // for the watchdog
1166: throw new RuntimeException(e);
1167:
1168: // log.log(Level.WARNING, e.toString(), e);
1169:
1170: // _configException = e;
1171: } finally {
1172: thread.setContextClassLoader(oldLoader);
1173: }
1174: }
1175:
1176: /**
1177: * Bind the ports.
1178: */
1179: public void bindPorts() throws Exception {
1180: synchronized (this ) {
1181: if (_isStartedPorts)
1182: return;
1183:
1184: _isStartedPorts = true;
1185: }
1186:
1187: Thread thread = Thread.currentThread();
1188: ClassLoader oldLoader = thread.getContextClassLoader();
1189: try {
1190: thread.setContextClassLoader(_classLoader);
1191:
1192: ArrayList<Port> ports = _clusterServer.getPorts();
1193: for (int i = 0; i < ports.size(); i++) {
1194: Port port = ports.get(i);
1195:
1196: port.setServer(this );
1197:
1198: port.bind();
1199: }
1200: } finally {
1201: thread.setContextClassLoader(oldLoader);
1202: }
1203: }
1204:
1205: /**
1206: * Start the ports.
1207: */
1208: public void startPorts() throws Exception {
1209: Thread thread = Thread.currentThread();
1210: ClassLoader oldLoader = thread.getContextClassLoader();
1211: try {
1212: thread.setContextClassLoader(_classLoader);
1213:
1214: ArrayList<Port> ports = _clusterServer.getPorts();
1215: for (int i = 0; i < ports.size(); i++) {
1216: Port port = ports.get(i);
1217:
1218: port.start();
1219: }
1220: } finally {
1221: thread.setContextClassLoader(oldLoader);
1222: }
1223: }
1224:
1225: /**
1226: * Handles the alarm.
1227: */
1228: public void handleAlarm(Alarm alarm) {
1229: if (!_lifecycle.isActive())
1230: return;
1231:
1232: try {
1233: long now = Alarm.getCurrentTime();
1234:
1235: if (isModified()) {
1236: // XXX: message slightly wrong
1237: log
1238: .warning("Resin restarting due to configuration change");
1239:
1240: _clusterServer.getCluster().getResin().destroy();
1241: return;
1242: }
1243:
1244: try {
1245: ArrayList<Port> ports = _clusterServer.getPorts();
1246:
1247: for (int i = 0; i < ports.size(); i++) {
1248: Port port = ports.get(i);
1249:
1250: if (port.isClosed()) {
1251: log
1252: .severe("Resin restarting due to closed port: "
1253: + port);
1254: // destroy();
1255: //_controller.restart();
1256: }
1257: }
1258: } catch (Throwable e) {
1259: log.log(Level.WARNING, e.toString(), e);
1260: // destroy();
1261: //_controller.restart();
1262: return;
1263: }
1264: } finally {
1265: alarm.queue(ALARM_INTERVAL);
1266: }
1267: }
1268:
1269: /**
1270: * Returns true if the server has been modified and needs restarting.
1271: */
1272: public boolean isModified() {
1273: boolean isModified = _classLoader.isModified();
1274:
1275: if (isModified)
1276: log.fine("server is modified");
1277:
1278: return isModified;
1279: }
1280:
1281: /**
1282: * Returns true if the server has been modified and needs restarting.
1283: */
1284: public boolean isModifiedNow() {
1285: boolean isModified = _classLoader.isModifiedNow();
1286:
1287: if (isModified)
1288: log.fine("server is modified");
1289:
1290: return isModified;
1291: }
1292:
1293: /**
1294: * Returns true if the server is stopped.
1295: */
1296: public boolean isStopping() {
1297: return _lifecycle.isStopping();
1298: }
1299:
1300: /**
1301: * Returns true if the server is stopped.
1302: */
1303: public boolean isStopped() {
1304: return _lifecycle.isStopped();
1305: }
1306:
1307: /**
1308: * Returns true if the server is closed.
1309: */
1310: public boolean isDestroyed() {
1311: return _lifecycle.isDestroyed();
1312: }
1313:
1314: /**
1315: * Returns true if the server is closed.
1316: */
1317: public boolean isDestroying() {
1318: return _lifecycle.isDestroying();
1319: }
1320:
1321: /**
1322: * Returns true if the server is currently active and accepting requests
1323: */
1324: public boolean isActive() {
1325: return _lifecycle.isActive();
1326: }
1327:
1328: /**
1329: * Clears the catch by matching the invocation.
1330: */
1331: public void clearCacheByPattern(String hostPattern,
1332: String uriPattern) {
1333: final Matcher hostMatcher;
1334: if (hostPattern != null)
1335: hostMatcher = Pattern.compile(hostPattern).matcher("");
1336: else
1337: hostMatcher = null;
1338:
1339: final Matcher uriMatcher;
1340: if (uriPattern != null)
1341: uriMatcher = Pattern.compile(uriPattern).matcher("");
1342: else
1343: uriMatcher = null;
1344:
1345: InvocationMatcher matcher = new InvocationMatcher() {
1346: public boolean isMatch(Invocation invocation) {
1347: if (hostMatcher != null) {
1348: hostMatcher.reset(invocation.getHost());
1349: if (!hostMatcher.find()) {
1350: return false;
1351: }
1352: }
1353:
1354: if (uriMatcher != null) {
1355: uriMatcher.reset(invocation.getURI());
1356: if (!uriMatcher.find()) {
1357: return false;
1358: }
1359: }
1360:
1361: return true;
1362: }
1363: };
1364:
1365: invalidateMatchingInvocations(matcher);
1366: }
1367:
1368: /**
1369: * Clears the proxy cache.
1370: */
1371: public void clearCache() {
1372: // skip the clear on restart
1373: if (isStopping())
1374: return;
1375:
1376: if (log.isLoggable(Level.FINEST))
1377: log.finest("ServletServer clearCache");
1378:
1379: // the invocation cache must be cleared first because the old
1380: // filter chain entries must not point to the cache's
1381: // soon-to-be-invalid entries
1382: super .clearCache();
1383:
1384: if (_cache != null)
1385: _cache.clear();
1386: }
1387:
1388: /**
1389: * Returns the proxy cache hit count.
1390: */
1391: public long getProxyCacheHitCount() {
1392: if (_cache != null)
1393: return _cache.getHitCount();
1394: else
1395: return 0;
1396: }
1397:
1398: /**
1399: * Returns the proxy cache miss count.
1400: */
1401: public long getProxyCacheMissCount() {
1402: if (_cache != null)
1403: return _cache.getMissCount();
1404: else
1405: return 0;
1406: }
1407:
1408: /**
1409: * Closes the server.
1410: */
1411: public void stop() {
1412: Thread thread = Thread.currentThread();
1413: ClassLoader oldLoader = thread.getContextClassLoader();
1414:
1415: try {
1416: thread.setContextClassLoader(_classLoader);
1417:
1418: if (!_lifecycle.toStopping())
1419: return;
1420:
1421: super .stop();
1422:
1423: Alarm alarm = _alarm;
1424: _alarm = null;
1425:
1426: if (alarm != null)
1427: alarm.dequeue();
1428:
1429: if (getSelectManager() != null)
1430: getSelectManager().stop();
1431:
1432: ArrayList<Port> ports = _clusterServer.getPorts();
1433: for (int i = 0; i < ports.size(); i++) {
1434: Port port = ports.get(i);
1435:
1436: try {
1437: port.close();
1438: } catch (Throwable e) {
1439: log.log(Level.WARNING, e.toString(), e);
1440: }
1441: }
1442:
1443: try {
1444: ThreadPool.getThreadPool().interrupt();
1445: } catch (Throwable e) {
1446: log.log(Level.WARNING, e.toString(), e);
1447: }
1448:
1449: try {
1450: Thread.yield();
1451: } catch (Throwable e) {
1452: }
1453:
1454: try {
1455: if (_hostContainer != null)
1456: _hostContainer.stop();
1457: } catch (Throwable e) {
1458: log.log(Level.WARNING, e.toString(), e);
1459: }
1460:
1461: try {
1462: _classLoader.stop();
1463: } catch (Throwable e) {
1464: log.log(Level.WARNING, e.toString(), e);
1465: }
1466:
1467: _lifecycle.toStop();
1468: } finally {
1469: thread.setContextClassLoader(oldLoader);
1470: }
1471: }
1472:
1473: /**
1474: * Closes the server.
1475: */
1476: public void destroy() {
1477: stop();
1478:
1479: if (!_lifecycle.toDestroy())
1480: return;
1481:
1482: Thread thread = Thread.currentThread();
1483: ClassLoader oldLoader = thread.getContextClassLoader();
1484:
1485: try {
1486: thread.setContextClassLoader(_classLoader);
1487:
1488: try {
1489: _hostContainer.destroy();
1490: } catch (Throwable e) {
1491: log.log(Level.WARNING, e.toString(), e);
1492: }
1493:
1494: super .destroy();
1495:
1496: log.fine(this + " destroyed");
1497:
1498: _classLoader.destroy();
1499:
1500: _hostContainer = null;
1501: _accessLog = null;
1502: _cache = null;
1503: } finally {
1504: DynamicClassLoader.setOldLoader(thread, oldLoader);
1505:
1506: Resin resin = _resin;
1507:
1508: if (resin != null)
1509: resin.destroy();
1510: }
1511: }
1512:
1513: public String toString() {
1514: return ("Server[id=" + getServerId() + ",cluster="
1515: + _clusterServer.getCluster().getId() + "]");
1516: }
1517:
1518: public static class SelectManagerCompat {
1519: private boolean _isEnable = true;
1520:
1521: public void setEnable(boolean isEnable) {
1522: _isEnable = isEnable;
1523: }
1524:
1525: public boolean isEnable() {
1526: return _isEnable;
1527: }
1528: }
1529: }
|