001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.server.host;
031:
032: import com.caucho.config.ConfigException;
033: import com.caucho.config.SchemaBean;
034: import com.caucho.lifecycle.Lifecycle;
035: import com.caucho.loader.EnvironmentBean;
036: import com.caucho.loader.EnvironmentClassLoader;
037: import com.caucho.loader.EnvironmentLocal;
038: import com.caucho.make.AlwaysModified;
039: import com.caucho.management.server.HostMXBean;
040: import com.caucho.server.cluster.Cluster;
041: import com.caucho.server.cluster.Server;
042: import com.caucho.server.deploy.EnvironmentDeployInstance;
043: import com.caucho.server.dispatch.DispatchServer;
044: import com.caucho.server.dispatch.ExceptionFilterChain;
045: import com.caucho.server.dispatch.Invocation;
046: import com.caucho.server.port.Port;
047: import com.caucho.server.webapp.WebAppContainer;
048: import com.caucho.util.L10N;
049: import com.caucho.vfs.Dependency;
050: import com.caucho.vfs.Path;
051:
052: import java.util.ArrayList;
053: import java.util.logging.Level;
054: import java.util.logging.Logger;
055:
056: /**
057: * Resin's virtual host implementation.
058: */
059: public class Host extends WebAppContainer implements EnvironmentBean,
060: Dependency, SchemaBean, EnvironmentDeployInstance {
061: private static final Logger log = Logger.getLogger(Host.class
062: .getName());
063: private static final L10N L = new L10N(Host.class);
064:
065: private static EnvironmentLocal<Host> _hostLocal = new EnvironmentLocal<Host>(
066: "caucho.host");
067:
068: private HostContainer _parent;
069:
070: // The Host entry
071: private HostController _controller;
072:
073: // The canonical host name. The host name may include the port.
074: private String _hostName = "";
075: // The canonical URL
076: private String _url;
077:
078: private String _serverName = "";
079: private int _serverPort = 0;
080:
081: // The secure host
082: private String _secureHostName;
083:
084: private boolean _isDefaultHost;
085:
086: // Alises
087: private ArrayList<String> _aliasList = new ArrayList<String>();
088:
089: private Throwable _configException;
090:
091: private boolean _isRootDirSet;
092: private boolean _isDocDirSet;
093:
094: private final Lifecycle _lifecycle;
095:
096: private String _configETag = null;
097:
098: /**
099: * Creates the webApp with its environment loader.
100: */
101: public Host(HostContainer parent, HostController controller,
102: String hostName) {
103: super (new EnvironmentClassLoader("host:" + hostName));
104:
105: try {
106: _controller = controller;
107:
108: setParent(parent);
109: setHostName(hostName);
110:
111: _hostLocal.set(this , getClassLoader());
112: } catch (Throwable e) {
113: _configException = e;
114: } finally {
115: _lifecycle = new Lifecycle(log, toString(), Level.INFO);
116: }
117: }
118:
119: /**
120: * Returns the local host.
121: */
122: public static Host getLocal() {
123: return _hostLocal.get();
124: }
125:
126: /**
127: * Sets the canonical host name.
128: */
129: private void setHostName(String name) throws ConfigException {
130: _hostName = name;
131:
132: if (name.equals(""))
133: _isDefaultHost = true;
134:
135: addHostAlias(name);
136:
137: getEnvironmentClassLoader().setId("host:" + name);
138:
139: // _jmxContext.put("J2EEServer", name);
140:
141: int p = name.indexOf("://");
142:
143: if (p >= 0)
144: name = name.substring(p + 3);
145:
146: _serverName = name;
147:
148: p = name.lastIndexOf(':');
149: if (p > 0) {
150: _serverName = name.substring(0, p);
151:
152: boolean isPort = true;
153: int port = 0;
154: for (p++; p < name.length(); p++) {
155: char ch = name.charAt(p);
156:
157: if ('0' <= ch && ch <= '9')
158: port = 10 * port + ch - '0';
159: else
160: isPort = false;
161: }
162:
163: if (isPort)
164: _serverPort = port;
165: }
166: }
167:
168: /**
169: * Returns the entry name
170: */
171: public String getName() {
172: return _controller.getName();
173: }
174:
175: /**
176: * Returns the canonical host name. The canonical host name may include
177: * the port.
178: */
179: public String getHostName() {
180: return _hostName;
181: }
182:
183: /**
184: * Returns the host (as an webApp container)
185: */
186: public Host getHost() {
187: return this ;
188: }
189:
190: /**
191: * Returns the secure host name. Used for redirects.
192: */
193: public String getSecureHostName() {
194: return _secureHostName;
195: }
196:
197: /**
198: * Sets the secure host name. Used for redirects.
199: */
200: public void setSecureHostName(String secureHostName) {
201: _secureHostName = secureHostName;
202: }
203:
204: /**
205: * Returns the relax schema.
206: */
207: public String getSchema() {
208: return "com/caucho/server/host/host.rnc";
209: }
210:
211: /**
212: * Returns the URL for the container.
213: */
214: public String getURL() {
215: if (_url != null)
216: return _url;
217: else if (_hostName == null || _hostName.equals("")) {
218: Server server = getServer();
219:
220: if (server == null)
221: return "";
222:
223: for (Port port : server.getPorts()) {
224: if ("http".equals(port.getProtocolName())) {
225: String address = port.getAddress();
226: if (address == null)
227: address = "localhost";
228:
229: return "http://" + address + ":" + port.getPort();
230: }
231: }
232:
233: for (Port port : server.getPorts()) {
234: if ("https".equals(port.getProtocolName())) {
235: String address = port.getAddress();
236: if (address == null)
237: address = "localhost";
238:
239: return "https://" + address + ":" + port.getPort();
240: }
241: }
242:
243: return "";
244: } else if (_hostName.startsWith("http:")
245: || _hostName.startsWith("https:"))
246: return _hostName;
247: else
248: return "http://" + _hostName;
249: }
250:
251: /**
252: * Adds an alias.
253: */
254: public void addHostAlias(String name) {
255: name = name.toLowerCase();
256:
257: if (!_aliasList.contains(name))
258: _aliasList.add(name);
259:
260: if (name.equals("") || name.equals("*"))
261: _isDefaultHost = true;
262:
263: _controller.addExtHostAlias(name);
264: }
265:
266: /**
267: * Gets the alias list.
268: */
269: public ArrayList<String> getAliasList() {
270: return _aliasList;
271: }
272:
273: /**
274: * Returns true if matches the default host.
275: */
276: public boolean isDefaultHost() {
277: return _isDefaultHost;
278: }
279:
280: /**
281: * Sets the parent container.
282: */
283: private void setParent(HostContainer parent) {
284: _parent = parent;
285:
286: setDispatchServer(parent.getDispatchServer());
287:
288: if (!_isRootDirSet) {
289: setRootDirectory(parent.getRootDirectory());
290: _isRootDirSet = false;
291: }
292: }
293:
294: /**
295: * Gets the environment class loader.
296: */
297: public EnvironmentClassLoader getEnvironmentClassLoader() {
298: return (EnvironmentClassLoader) getClassLoader();
299: }
300:
301: /**
302: * Sets the root dir.
303: */
304: public void setRootDirectory(Path rootDir) {
305: super .setRootDirectory(rootDir);
306: _isRootDirSet = true;
307:
308: if (!_isDocDirSet) {
309: setDocumentDirectory(rootDir);
310: _isDocDirSet = false;
311: }
312: }
313:
314: /**
315: * Sets the doc dir.
316: */
317: public void setDocumentDirectory(Path docDir) {
318: super .setDocumentDirectory(docDir);
319: _isDocDirSet = true;
320: }
321:
322: /**
323: * Sets the config exception.
324: */
325: public void setConfigException(Throwable e) {
326: if (e != null) {
327: // XXX:
328: _configException = e;
329: getEnvironmentClassLoader().addDependency(
330: AlwaysModified.create());
331: }
332: }
333:
334: /**
335: * Gets the config exception.
336: */
337: public Throwable getConfigException() {
338: return _configException;
339: }
340:
341: /**
342: * Returns the owning server.
343: */
344: public Server getServer() {
345: if (_parent != null) {
346: DispatchServer server = _parent.getDispatchServer();
347:
348: if (server instanceof Server)
349: return (Server) server;
350: }
351:
352: return null;
353: }
354:
355: /**
356: * Returns the current cluster.
357: */
358: public Cluster getCluster() {
359: Server server = getServer();
360:
361: if (server != null)
362: return server.getCluster();
363: else
364: return null;
365: }
366:
367: /**
368: * Returns the config etag.
369: */
370: public String getConfigETag() {
371: return _configETag;
372: }
373:
374: /**
375: * Returns the config etag.
376: */
377: public void setConfigETag(String etag) {
378: _configETag = etag;
379: }
380:
381: /**
382: * Returns the admin.
383: */
384: public HostMXBean getAdmin() {
385: return _controller.getAdmin();
386: }
387:
388: /**
389: * Starts the host.
390: */
391: public void start() {
392: if (!_lifecycle.toStarting())
393: return;
394:
395: if (getURL().equals("") && _parent != null) {
396: _url = _parent.getURL();
397: }
398:
399: EnvironmentClassLoader loader;
400: loader = getEnvironmentClassLoader();
401:
402: loader.setId("host:" + getURL());
403:
404: Thread thread = Thread.currentThread();
405: ClassLoader oldLoader = thread.getContextClassLoader();
406:
407: try {
408: thread.setContextClassLoader(loader);
409:
410: super .start();
411:
412: loader.start();
413:
414: if (_parent != null)
415: _parent.clearCache();
416: } finally {
417: _lifecycle.toActive();
418:
419: thread.setContextClassLoader(oldLoader);
420: }
421: }
422:
423: /**
424: * Clears the cache
425: */
426: public void clearCache() {
427: super .clearCache();
428:
429: setConfigETag(null);
430: }
431:
432: /**
433: * Builds the invocation for the host.
434: */
435: public Invocation buildInvocation(Invocation invocation)
436: throws Exception {
437: invocation.setHostName(_serverName);
438: invocation.setPort(_serverPort);
439:
440: Thread thread = Thread.currentThread();
441: ClassLoader oldLoader = thread.getContextClassLoader();
442:
443: try {
444: thread.setContextClassLoader(getClassLoader());
445:
446: if (_configException == null)
447: return super .buildInvocation(invocation);
448: else {
449: invocation.setFilterChain(new ExceptionFilterChain(
450: _configException));
451: invocation.setDependency(AlwaysModified.create());
452:
453: return invocation;
454: }
455: } finally {
456: thread.setContextClassLoader(oldLoader);
457: }
458: }
459:
460: /**
461: * Returns true if the host is modified.
462: */
463: public boolean isModified() {
464: return (isDestroyed() || getEnvironmentClassLoader()
465: .isModified());
466: }
467:
468: /**
469: * Returns true if the host is modified.
470: */
471: public boolean isModifiedNow() {
472: return (isDestroyed() || getEnvironmentClassLoader()
473: .isModifiedNow());
474: }
475:
476: /**
477: * Log the reason for modification.
478: */
479: public boolean logModified(Logger log) {
480: if (isDestroyed())
481: return true;
482: else
483: return getEnvironmentClassLoader().logModified(log);
484: }
485:
486: /**
487: * Returns true if the host deploy was an error
488: */
489: public boolean isDeployError() {
490: return _configException != null;
491: }
492:
493: /**
494: * Returns true if the host is idle
495: */
496: public boolean isDeployIdle() {
497: return false;
498: }
499:
500: /**
501: * Stops the host.
502: */
503: public boolean stop() {
504: Thread thread = Thread.currentThread();
505: ClassLoader oldLoader = thread.getContextClassLoader();
506:
507: try {
508: EnvironmentClassLoader envLoader = getEnvironmentClassLoader();
509: thread.setContextClassLoader(envLoader);
510:
511: if (!_lifecycle.toStopping())
512: return false;
513:
514: super .stop();
515:
516: envLoader.stop();
517:
518: return true;
519: } finally {
520: _lifecycle.toStop();
521:
522: thread.setContextClassLoader(oldLoader);
523: }
524: }
525:
526: /**
527: * Closes the host.
528: */
529: public void destroy() {
530: stop();
531:
532: if (isDestroyed())
533: return;
534:
535: Thread thread = Thread.currentThread();
536: ClassLoader oldLoader = thread.getContextClassLoader();
537: EnvironmentClassLoader classLoader = getEnvironmentClassLoader();
538:
539: thread.setContextClassLoader(classLoader);
540:
541: try {
542: super .destroy();
543: } finally {
544: thread.setContextClassLoader(oldLoader);
545:
546: classLoader.destroy();
547: }
548: }
549:
550: public String toString() {
551: return "Host[" + getHostName() + "]";
552: }
553: }
|