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.program.ConfigProgram;
0033: import com.caucho.config.program.ContainerProgram;
0034: import com.caucho.config.ConfigException;
0035: import com.caucho.config.SchemaBean;
0036: import com.caucho.config.types.Period;
0037: import com.caucho.jmx.Jmx;
0038: import com.caucho.lifecycle.StartLifecycleException;
0039: import com.caucho.loader.DynamicClassLoader;
0040: import com.caucho.loader.Environment;
0041: import com.caucho.loader.EnvironmentBean;
0042: import com.caucho.loader.EnvironmentClassLoader;
0043: import com.caucho.loader.EnvironmentListener;
0044: import com.caucho.loader.EnvironmentLocal;
0045: import com.caucho.management.server.ClusterMXBean;
0046: import com.caucho.server.port.Port;
0047: import com.caucho.server.resin.Resin;
0048: import com.caucho.util.L10N;
0049: import com.caucho.util.RandomUtil;
0050: import com.caucho.vfs.Path;
0051: import com.caucho.vfs.Vfs;
0052: import com.caucho.webbeans.manager.*;
0053:
0054: import javax.management.ObjectName;
0055: import java.util.ArrayList;
0056: import java.util.logging.Level;
0057: import java.util.logging.Logger;
0058:
0059: /**
0060: * Defines a set of clustered servers.
0061: */
0062: public class Cluster implements EnvironmentListener, EnvironmentBean,
0063: SchemaBean {
0064: private static final L10N L = new L10N(Cluster.class);
0065: private static final Logger log = Logger.getLogger(Cluster.class
0066: .getName());
0067:
0068: static protected final EnvironmentLocal<String> _serverIdLocal = new EnvironmentLocal<String>(
0069: "caucho.server-id");
0070:
0071: static protected final EnvironmentLocal<Cluster> _clusterLocal = new EnvironmentLocal<Cluster>(
0072: "caucho.cluster");
0073:
0074: private static final int DECODE[];
0075:
0076: private String _id = "";
0077:
0078: private String _serverId = "";
0079:
0080: private EnvironmentClassLoader _classLoader;
0081:
0082: private Resin _resin;
0083:
0084: private Path _rootDirectory;
0085:
0086: private ClusterAdmin _admin;
0087: private ObjectName _objectName;
0088:
0089: private ArrayList<ContainerProgram> _serverDefaultList = new ArrayList<ContainerProgram>();
0090:
0091: private ArrayList<Machine> _machineList = new ArrayList<Machine>();
0092:
0093: private ArrayList<ClusterServer> _serverList = new ArrayList<ClusterServer>();
0094:
0095: private ClusterServer[] _serverArray = new ClusterServer[0];
0096:
0097: private StoreManager _clusterStore;
0098:
0099: // compatibility with 3.0
0100: private long _clientMaxIdleTime = 30000L;
0101: private long _clientFailRecoverTime = 15000L;
0102: private long _clientWarmupTime = 60000L;
0103:
0104: private long _clientReadTimeout = 60000L;
0105: private long _clientConnectTimeout = 5000L;
0106:
0107: private ContainerProgram _serverProgram = new ContainerProgram();
0108:
0109: private Server _server;
0110:
0111: private volatile boolean _isClosed;
0112:
0113: public Cluster(Resin resin) {
0114: this ();
0115:
0116: _resin = resin;
0117: }
0118:
0119: public Cluster() {
0120: _classLoader = new EnvironmentClassLoader("cluster:??");
0121:
0122: _clusterLocal.set(this , _classLoader);
0123:
0124: Environment.addEnvironmentListener(this , _classLoader);
0125:
0126: WebBeansContainer.create().addSingletonByName(new Var(),
0127: "cluster");
0128:
0129: _rootDirectory = Vfs.getPwd();
0130: }
0131:
0132: /**
0133: * Returns the currently active local cluster.
0134: */
0135: public static Cluster getLocal() {
0136: Cluster cluster = _clusterLocal.get();
0137:
0138: return cluster;
0139: }
0140:
0141: /**
0142: * Returns the currently active local cluster.
0143: */
0144: public static Cluster getCluster(ClassLoader loader) {
0145: Cluster cluster = _clusterLocal.get(loader);
0146:
0147: return cluster;
0148: }
0149:
0150: /**
0151: * Sets the cluster id.
0152: */
0153: public void setId(String id) {
0154: if (id == null)
0155: throw new NullPointerException();
0156:
0157: _id = id;
0158:
0159: _classLoader.setId("cluster:" + _id);
0160: }
0161:
0162: /**
0163: * Gets the cluster id.
0164: */
0165: public String getId() {
0166: return _id;
0167: }
0168:
0169: /**
0170: * Returns the owning resin server.
0171: */
0172: public Resin getResin() {
0173: return _resin;
0174: }
0175:
0176: /**
0177: * Returns the environment class loader.
0178: */
0179: public ClassLoader getClassLoader() {
0180: return _classLoader;
0181: }
0182:
0183: /**
0184: * Returns the relax schema.
0185: */
0186: public String getSchema() {
0187: return "com/caucho/server/resin/cluster.rnc";
0188: }
0189:
0190: /**
0191: * Gets the root directory.
0192: */
0193: public Path getRootDirectory() {
0194: return _rootDirectory;
0195: }
0196:
0197: /**
0198: * Sets the root directory.
0199: */
0200: public void setRootDirectory(Path rootDirectory) {
0201: Vfs.setPwd(rootDirectory);
0202:
0203: _rootDirectory = rootDirectory;
0204: }
0205:
0206: /**
0207: * Returns the admin.
0208: */
0209: public ClusterMXBean getAdmin() {
0210: return _admin;
0211: }
0212:
0213: /**
0214: * Finds the first server with the given server-id.
0215: */
0216: public ClusterServer findServer(String id) {
0217: for (int i = _serverList.size() - 1; i >= 0; i--) {
0218: ClusterServer server = _serverList.get(i);
0219:
0220: if (server != null && server.getId().equals(id))
0221: return server;
0222: }
0223:
0224: return null;
0225: }
0226:
0227: /**
0228: * Adds a new server to the cluster.
0229: */
0230: public void addServerDefault(ContainerProgram program)
0231: throws Throwable {
0232: _serverDefaultList.add(program);
0233: }
0234:
0235: /**
0236: * Adds a new server to the cluster.
0237: */
0238: public Machine createMachine() throws Exception {
0239: Machine machine = new Machine(this );
0240:
0241: _machineList.add(machine);
0242:
0243: return machine;
0244: }
0245:
0246: /**
0247: * Adds a new server to the cluster.
0248: */
0249: public ClusterServer createServer() throws Exception {
0250: Machine machine = createMachine();
0251:
0252: return machine.createServer();
0253: }
0254:
0255: ClusterServer createServer(ClusterServer server) {
0256: server.setIndex(_serverList.size());
0257:
0258: for (int i = 0; i < _serverDefaultList.size(); i++)
0259: _serverDefaultList.get(i).configure(server);
0260:
0261: return server;
0262: }
0263:
0264: /**
0265: * Adds a new server to the cluster.
0266: */
0267: public void addServer(ClusterServer server) throws ConfigException {
0268: ClusterServer oldServer = findServer(server.getId());
0269:
0270: if (oldServer != null)
0271: log.warning(L.l("duplicate <server> with id='{0}'", server
0272: .getId()));
0273:
0274: _serverList.add(server);
0275: _serverArray = new ClusterServer[_serverList.size()];
0276: _serverList.toArray(_serverArray);
0277:
0278: ClusterServer selfServer = getSelfServer();
0279:
0280: if (selfServer == server) {
0281: WebBeansContainer webBeans = WebBeansContainer.create();
0282:
0283: webBeans
0284: .addSingletonByName(new ServerVar(server), "server");
0285: }
0286: }
0287:
0288: /**
0289: * Adds a srun server.
0290: */
0291: public ServerConnector findConnector(String address, int port) {
0292: for (int i = _serverList.size() - 1; i >= 0; i--) {
0293: ClusterServer server = _serverList.get(i);
0294: ClusterPort clusterPort = server.getClusterPort();
0295:
0296: if (address.equals(clusterPort.getAddress())
0297: && port == clusterPort.getPort()) {
0298: // XXX:
0299: //return server.getClient();
0300: return null;
0301: }
0302: }
0303:
0304: return null;
0305: }
0306:
0307: /**
0308: * Returns the cluster store.
0309: */
0310: public StoreManager getStore() {
0311: return _clusterStore;
0312: }
0313:
0314: /**
0315: * Sets the cluster store.
0316: */
0317: void setStore(StoreManager store) {
0318: _clusterStore = store;
0319: }
0320:
0321: /**
0322: * Sets the max-idle time.
0323: */
0324: public void setClientMaxIdleTime(Period period) {
0325: _clientMaxIdleTime = period.getPeriod();
0326: }
0327:
0328: /**
0329: * Gets the live time.
0330: */
0331: public long getClientMaxIdleTime() {
0332: return _clientMaxIdleTime;
0333: }
0334:
0335: /**
0336: * Sets the live time.
0337: *
0338: * @deprecated
0339: */
0340: public void setClientLiveTime(Period period) {
0341: setClientMaxIdleTime(period);
0342: }
0343:
0344: /**
0345: * Sets the client connection fail-recover time.
0346: */
0347: public void setClientFailRecoverTime(Period period) {
0348: _clientFailRecoverTime = period.getPeriod();
0349: }
0350:
0351: /**
0352: * Gets the client fail-recover time.
0353: */
0354: public long getClientFailRecoverTime() {
0355: return _clientFailRecoverTime;
0356: }
0357:
0358: /**
0359: * Sets the dead time.
0360: *
0361: * @deprecated
0362: */
0363: public void setClientDeadTime(Period period) {
0364: setClientFailRecoverTime(period);
0365: }
0366:
0367: /**
0368: * Sets the client warmup time.
0369: */
0370: public void setClientWarmupTime(Period period) {
0371: _clientWarmupTime = period.getPeriod();
0372: }
0373:
0374: /**
0375: * Gets the client warmup time.
0376: */
0377: public long getClientWarmupTime() {
0378: return _clientWarmupTime;
0379: }
0380:
0381: /**
0382: * Sets the connect timeout.
0383: */
0384: public void setClientConnectTimeout(Period period) {
0385: _clientConnectTimeout = period.getPeriod();
0386: }
0387:
0388: /**
0389: * Gets the connect timeout.
0390: */
0391: public long getClientConnectTimeout() {
0392: return _clientConnectTimeout;
0393: }
0394:
0395: /**
0396: * Sets the read timeout.
0397: */
0398: public void setClientReadTimeout(Period period) {
0399: _clientReadTimeout = period.getPeriod();
0400: }
0401:
0402: /**
0403: * Gets the read timeout.
0404: */
0405: public long getClientReadTimeout() {
0406: return _clientReadTimeout;
0407: }
0408:
0409: /**
0410: * Sets the write timeout.
0411: */
0412: public void setClientWriteTimeout(Period period) {
0413: }
0414:
0415: public StoreManager createJdbcStore() throws ConfigException {
0416: if (getStore() != null)
0417: throw new ConfigException(
0418: L
0419: .l("multiple jdbc stores are not allowed in a cluster."));
0420:
0421: StoreManager store = null;
0422:
0423: try {
0424: Class cl = Class
0425: .forName("com.caucho.server.cluster.JdbcStore");
0426:
0427: store = (StoreManager) cl.newInstance();
0428:
0429: store.setCluster(this );
0430:
0431: setStore(store);
0432: } catch (Throwable e) {
0433: log.log(Level.FINER, e.toString(), e);
0434: }
0435:
0436: if (store == null)
0437: throw new ConfigException(
0438: L
0439: .l("'jdbc' persistent sessions are available in Resin Professional. See http://www.caucho.com for information and licensing."));
0440:
0441: return store;
0442: }
0443:
0444: public StoreManager createPrivateFileStore() throws ConfigException {
0445: StoreManager store = createFileStore();
0446:
0447: setStore(null);
0448:
0449: return store;
0450: }
0451:
0452: public StoreManager createFileStore() throws ConfigException {
0453: if (getStore() != null)
0454: throw new ConfigException(
0455: L
0456: .l("multiple file stores are not allowed in a cluster."));
0457:
0458: StoreManager store = null;
0459:
0460: try {
0461: Class cl = Class
0462: .forName("com.caucho.server.cluster.FileStore");
0463:
0464: store = (StoreManager) cl.newInstance();
0465:
0466: store.setCluster(this );
0467:
0468: setStore(store);
0469: } catch (Throwable e) {
0470: log.log(Level.FINER, e.toString(), e);
0471: }
0472:
0473: if (store == null)
0474: throw new ConfigException(
0475: L
0476: .l("'file' persistent sessions are available in Resin Professional. See http://www.caucho.com for information and licensing."));
0477:
0478: return store;
0479: }
0480:
0481: public StoreManager createClusterStore() throws ConfigException {
0482: if (getStore() != null)
0483: throw new ConfigException(
0484: L
0485: .l("multiple cluster stores are not allowed in a cluster."));
0486:
0487: StoreManager store = null;
0488:
0489: try {
0490: Class cl = Class
0491: .forName("com.caucho.server.cluster.ClusterStore");
0492:
0493: store = (StoreManager) cl.newInstance();
0494:
0495: store.setCluster(this );
0496:
0497: setStore(store);
0498: } catch (Throwable e) {
0499: log.log(Level.FINER, e.toString(), e);
0500: }
0501:
0502: if (store == null)
0503: throw new ConfigException(
0504: L
0505: .l("'cluster' persistent sessions are available in Resin Professional. See http://www.caucho.com for information and licensing."));
0506:
0507: return store;
0508: }
0509:
0510: /**
0511: * Adds a program.
0512: */
0513: public void addBuilderProgram(ConfigProgram program) {
0514: _serverProgram.addProgram(program);
0515: }
0516:
0517: /**
0518: * Initializes the cluster.
0519: */
0520: public void start() throws ConfigException {
0521: String serverId = _serverIdLocal.get();
0522:
0523: if (serverId == null)
0524: serverId = "";
0525:
0526: boolean isActive;
0527:
0528: ClusterServer self = findServer(serverId);
0529:
0530: if (self != null) {
0531: _clusterLocal.set(this );
0532: isActive = true;
0533: } else if (_clusterLocal.get() == null
0534: && _serverList.size() == 0) {
0535: // if it's the empty cluster, add it
0536: _clusterLocal.set(this );
0537: isActive = true;
0538: } else
0539: isActive = false;
0540:
0541: try {
0542: String name = _id;
0543:
0544: if (name == null)
0545: name = "";
0546:
0547: ObjectName objectName = Jmx
0548: .getObjectName("type=Cluster,name=" + name);
0549:
0550: _admin = new ClusterAdmin(this );
0551:
0552: Jmx.register(_admin, objectName);
0553:
0554: _objectName = objectName;
0555: } catch (Exception e) {
0556: log.log(Level.FINER, e.toString(), e);
0557: }
0558:
0559: for (ClusterServer server : _serverList) {
0560: try {
0561: server.init();
0562: } catch (Exception e) {
0563: throw ConfigException.create(e);
0564: }
0565: }
0566: }
0567:
0568: /**
0569: * Returns the server id.
0570: */
0571: public static String getServerId() {
0572: return _serverIdLocal.get();
0573: }
0574:
0575: /**
0576: * Returns the JMX object name.
0577: */
0578: public ObjectName getObjectName() {
0579: return _objectName == null ? null : _objectName;
0580: }
0581:
0582: /**
0583: * Returns the server corresponding to the current server-id.
0584: */
0585: public ClusterServer getSelfServer() {
0586: _serverId = _serverIdLocal.get();
0587:
0588: return getServer(_serverId);
0589: }
0590:
0591: /**
0592: * Returns the server list.
0593: */
0594: public ClusterServer[] getServerList() {
0595: return _serverArray;
0596: }
0597:
0598: /**
0599: * Returns the machine list.
0600: */
0601: public ArrayList<Machine> getMachineList() {
0602: return _machineList;
0603: }
0604:
0605: /**
0606: * Returns the server in the cluster with the given server-id.
0607: */
0608: public ClusterServer getServer(String serverId) {
0609: for (int i = 0; i < _serverList.size(); i++) {
0610: ClusterServer server = _serverList.get(i);
0611:
0612: if (server != null && server.getId().equals(serverId))
0613: return server;
0614: }
0615:
0616: return null;
0617: }
0618:
0619: /**
0620: * Returns the server with the matching index.
0621: */
0622: public ClusterServer getServer(int index) {
0623: for (int i = 0; i < _serverList.size(); i++) {
0624: ClusterServer server = _serverList.get(i);
0625:
0626: if (server != null && server.getIndex() == index)
0627: return server;
0628: }
0629:
0630: return null;
0631: }
0632:
0633: /**
0634: * Returns the matching ports.
0635: */
0636: public ArrayList<ClusterPort> getServerPorts(String serverId) {
0637: ArrayList<ClusterPort> ports = new ArrayList<ClusterPort>();
0638:
0639: for (int i = 0; i < _serverList.size(); i++) {
0640: ClusterServer server = _serverList.get(i);
0641:
0642: if (server != null) {
0643: ClusterPort port = server.getClusterPort();
0644:
0645: if (port.getServerId().equals(serverId))
0646: ports.add(port);
0647: }
0648: }
0649:
0650: return ports;
0651: }
0652:
0653: /**
0654: * Starts the server.
0655: */
0656: Server startServer(ClusterServer clusterServer)
0657: throws StartLifecycleException {
0658: synchronized (this ) {
0659: if (_server != null)
0660: return _server;
0661:
0662: Server server = new Server(clusterServer);
0663:
0664: _serverProgram.configure(server);
0665:
0666: server.start();
0667:
0668: _server = server;
0669:
0670: return server;
0671: }
0672: }
0673:
0674: /**
0675: * Generate the primary, secondary, tertiary, returning the value encoded
0676: * in a long.
0677: */
0678: public long generateBackupCode(int index) {
0679: ClusterServer[] srunList = getServerList();
0680: int srunLength = srunList.length;
0681: ArrayList<Machine> machineList = getMachineList();
0682: int machineLength = machineList.size();
0683:
0684: long backupCode = index;
0685:
0686: long backupLength = srunLength;
0687: if (backupLength < 3)
0688: backupLength = 3;
0689: int backup;
0690:
0691: if (srunLength <= 1) {
0692: backup = 0;
0693: backupCode |= 1L << 16;
0694: } else if (srunLength == 2) {
0695: backup = 0;
0696:
0697: backupCode |= ((index + 1L) % 2) << 16;
0698: } else if (machineLength == 1) {
0699: int sublen = srunLength - 1;
0700: if (sublen > 7)
0701: sublen = 7;
0702:
0703: backup = RandomUtil.nextInt(sublen);
0704:
0705: backupCode |= ((index + backup + 1L) % backupLength) << 16;
0706: } else {
0707: ClusterServer primaryServer = srunList[index];
0708: int machineIndex = primaryServer.getMachine().getIndex();
0709: int sublen = machineLength - 1;
0710: if (sublen > 7)
0711: sublen = 7;
0712:
0713: int backupMachine = ((machineIndex
0714: + RandomUtil.nextInt(sublen) + 1) % machineLength);
0715:
0716: Machine machine = machineList.get(backupMachine);
0717: ArrayList<ClusterServer> serverList = machine
0718: .getServerList();
0719:
0720: ClusterServer server;
0721:
0722: if (serverList.size() > 1)
0723: server = serverList.get(RandomUtil.nextInt(serverList
0724: .size()));
0725: else
0726: server = serverList.get(0);
0727:
0728: backup = (int) (server.getIndex() - index + srunLength)
0729: % srunLength - 1;
0730:
0731: backupCode |= ((index + backup + 1L) % backupLength) << 16;
0732: }
0733:
0734: if (srunLength <= 2)
0735: backupCode |= 2L << 32;
0736: else {
0737: int sublen = srunLength - 2;
0738: if (sublen > 6)
0739: sublen = 6;
0740:
0741: int third = RandomUtil.nextInt(sublen);
0742:
0743: if (backup <= third)
0744: third += 1;
0745:
0746: backupCode |= ((index + third + 1) % backupLength) << 32;
0747: }
0748:
0749: return backupCode;
0750: }
0751:
0752: /**
0753: * Adds the primary/backup/third digits to the id.
0754: */
0755: public void generateBackupCode(StringBuilder cb, long backupCode) {
0756: addDigit(cb, (int) (backupCode & 0xffff));
0757: addDigit(cb, (int) ((backupCode >> 16) & 0xffff));
0758: addDigit(cb, (int) ((backupCode >> 32) & 0xffff));
0759: }
0760:
0761: /**
0762: * Returns the primary server.
0763: */
0764: public ClusterServer getPrimary(String id, int offset) {
0765: ClusterServer[] srunList = getServerList();
0766: int srunLength = srunList.length;
0767:
0768: int index = 0;
0769:
0770: if (srunLength < 64) {
0771: index = decode(id.charAt(offset + 0));
0772: } else {
0773: int d1 = decode(id.charAt(offset + 0));
0774: int d2 = decode(id.charAt(offset + 1));
0775:
0776: index = d1 * 64 + d2;
0777: }
0778:
0779: if (index < srunLength)
0780: return srunList[index];
0781: else
0782: return null;
0783: }
0784:
0785: /**
0786: * Returns the secondary server.
0787: */
0788: public ClusterServer getSecondary(String id, int offset) {
0789: ClusterServer[] srunList = getServerList();
0790: int srunLength = srunList.length;
0791:
0792: int index = 0;
0793:
0794: if (srunLength < 64) {
0795: index = decode(id.charAt(offset + 1));
0796: } else {
0797: int d1 = decode(id.charAt(offset + 2));
0798: int d2 = decode(id.charAt(offset + 3));
0799:
0800: index = d1 * 64 + d2;
0801: }
0802:
0803: if (index < srunLength)
0804: return srunList[index];
0805: else
0806: return null;
0807: }
0808:
0809: /**
0810: * Returns the tertiary server.
0811: */
0812: public ClusterServer getTertiary(String id, int offset) {
0813: ClusterServer[] srunList = getServerList();
0814: int srunLength = srunList.length;
0815:
0816: int index = 0;
0817:
0818: if (srunLength < 64) {
0819: index = decode(id.charAt(offset + 2));
0820: } else {
0821: int d1 = decode(id.charAt(offset + 4));
0822: int d2 = decode(id.charAt(offset + 5));
0823:
0824: index = d1 * 64 + d2;
0825: }
0826:
0827: if (index < srunLength)
0828: return srunList[index];
0829: else
0830: return null;
0831: }
0832:
0833: private void addDigit(StringBuilder cb, int digit) {
0834: ClusterServer[] srunList = getServerList();
0835: int srunLength = srunList.length;
0836:
0837: if (srunLength < 64)
0838: cb.append(convert(digit));
0839: else {
0840: cb.append(convert(digit / 64));
0841: cb.append(convert(digit));
0842: }
0843: }
0844:
0845: /**
0846: * Handles the case where a class loader has completed initialization
0847: */
0848: public void classLoaderInit(DynamicClassLoader loader) {
0849: }
0850:
0851: /**
0852: * Handles the case where a class loader is dropped.
0853: */
0854: public void classLoaderDestroy(DynamicClassLoader loader) {
0855: }
0856:
0857: /**
0858: * Handles the case where the environment is starting (after init).
0859: */
0860: public void environmentConfig(EnvironmentClassLoader loader) {
0861: }
0862:
0863: /**
0864: * Handles the case where the environment is starting (after init).
0865: */
0866: public void environmentStart(EnvironmentClassLoader loader) {
0867: try {
0868: if (_clusterStore != null)
0869: _clusterStore.start();
0870: } catch (Exception e) {
0871: log.log(Level.WARNING, e.toString(), e);
0872: }
0873: }
0874:
0875: /**
0876: * Handles the case where the environment is stopping
0877: */
0878: public void environmentStop(EnvironmentClassLoader loader) {
0879: try {
0880: close();
0881: } catch (Throwable e) {
0882: log.log(Level.WARNING, e.toString(), e);
0883: }
0884: }
0885:
0886: /**
0887: * Closes the cluster.
0888: */
0889: public void close() {
0890: synchronized (this ) {
0891: if (_isClosed)
0892: return;
0893:
0894: _isClosed = true;
0895: }
0896:
0897: for (int i = 0; i < _serverList.size(); i++) {
0898: ClusterServer server = _serverList.get(i);
0899:
0900: try {
0901: if (server != null)
0902: server.close();
0903: } catch (Throwable e) {
0904: log.log(Level.WARNING, e.toString(), e);
0905: }
0906: }
0907: }
0908:
0909: public String toString() {
0910: return "Cluster[" + _id + "]";
0911: }
0912:
0913: /**
0914: * Converts an integer to a printable character
0915: */
0916: private static char convert(long code) {
0917: code = code & 0x3f;
0918:
0919: if (code < 26)
0920: return (char) ('a' + code);
0921: else if (code < 52)
0922: return (char) ('A' + code - 26);
0923: else if (code < 62)
0924: return (char) ('0' + code - 52);
0925: else if (code == 62)
0926: return '_';
0927: else
0928: return '-';
0929: }
0930:
0931: public static int decode(int code) {
0932: return DECODE[code & 0x7f];
0933: }
0934:
0935: /**
0936: * EL variables
0937: */
0938: public class Var {
0939: /**
0940: * Returns the resin.id
0941: */
0942: public String getId() {
0943: return _id;
0944: }
0945:
0946: /**
0947: * Returns the root directory.
0948: *
0949: * @return root directory
0950: */
0951: public Path getRoot() {
0952: return Cluster.this .getRootDirectory();
0953: }
0954:
0955: /**
0956: * Returns the root directory.
0957: *
0958: * @return root directory
0959: */
0960: public Path getRootDir() {
0961: return getRoot();
0962: }
0963:
0964: /**
0965: * Returns the root directory.
0966: *
0967: * @return root directory
0968: */
0969: public Path getRootDirectory() {
0970: return getRoot();
0971: }
0972: }
0973:
0974: public class ServerVar {
0975: private final ClusterServer _server;
0976:
0977: public ServerVar(ClusterServer server) {
0978: _server = server;
0979: }
0980:
0981: public String getId() {
0982: return _server.getId();
0983: }
0984:
0985: private int getPort(Port port) {
0986: if (port == null)
0987: return 0;
0988:
0989: return port.getPort();
0990: }
0991:
0992: private String getAddress(Port port) {
0993: if (port == null)
0994: return null;
0995:
0996: String address = port.getAddress();
0997:
0998: if (address == null || address.length() == 0)
0999: address = "INADDR_ANY";
1000:
1001: return address;
1002: }
1003:
1004: private Port getFirstPort(String protocol, boolean isSSL) {
1005: if (_server.getPorts() == null)
1006: return null;
1007:
1008: for (Port port : _server.getPorts()) {
1009: if (protocol.equals(port.getProtocolName())
1010: && (port.isSSL() == isSSL))
1011: return port;
1012: }
1013:
1014: return null;
1015: }
1016:
1017: public String getAddress() {
1018: return getAddress(_server.getClusterPort());
1019: }
1020:
1021: public int getPort() {
1022: return getPort(_server.getClusterPort());
1023: }
1024:
1025: public String getHttpAddress() {
1026: return getAddress(getFirstPort("http", false));
1027: }
1028:
1029: public int getHttpPort() {
1030: return getPort(getFirstPort("http", false));
1031: }
1032:
1033: public String getHttpsAddress() {
1034: return getAddress(getFirstPort("http", true));
1035: }
1036:
1037: public int getHttpsPort() {
1038: return getPort(getFirstPort("http", true));
1039: }
1040:
1041: /**
1042: * @deprecated backwards compat.
1043: */
1044: public Path getRoot() {
1045: Resin resin = Resin.getLocal();
1046:
1047: return resin == null ? Vfs.getPwd() : resin
1048: .getRootDirectory();
1049: }
1050: }
1051:
1052: static {
1053: DECODE = new int[128];
1054: for (int i = 0; i < 64; i++)
1055: DECODE[(int) convert(i)] = i;
1056: }
1057: }
|