001: /*
002: * MultiHostHandler.java
003: *
004: * Brazil project web application Framework,
005: * export version: 1.1
006: * Copyright (c) 1999-2000 Sun Microsystems, Inc.
007: *
008: * Sun Public License Notice
009: *
010: * The contents of this file are subject to the Sun Public License Version
011: * 1.0 (the "License"). You may not use this file except in compliance with
012: * the License. A copy of the License is included as the file "license.terms",
013: * and also available at http://www.sun.com/
014: *
015: * The Original Code is from:
016: * Brazil project web application Framework release 1.1.
017: * The Initial Developer of the Original Code is: cstevens.
018: * Portions created by cstevens are Copyright (C) Sun Microsystems, Inc.
019: * All Rights Reserved.
020: *
021: * Contributor(s): cstevens, suhler.
022: *
023: * Version: 1.5
024: * Created by cstevens on 99/11/03
025: * Last modified by suhler on 00/12/11 13:28:26
026: */
027:
028: package sunlabs.brazil.server;
029:
030: import java.io.IOException;
031: import java.util.Hashtable;
032: import java.util.Properties;
033: import java.util.StringTokenizer;
034:
035: /**
036: * The <code>MultiHostHandler</code> allows the user to handle a set
037: * of host names that are all running on the same IP address. This
038: * handler looks at the "Host:" and redispatches the request to the
039: * appropriate sub-server.
040: * <p>
041: * Only the main server is actually listening to the port on the specified IP
042: * address. The sub-servers are not running in separate threads. Indeed,
043: * they are not "running" at all. They exist merely as a convenient bag to
044: * hold each of the server-specific configuration parameters.
045: * <p>
046: * The <code>respond</code> method of the main handler for the appropriate
047: * sub-server is called directly from the <code>respond</code> method of
048: * this handler.
049: * <p>
050: * This handler uses the following configuration parameters: <dl class=props>
051: *
052: * <dt> servers
053: * <dd> The list of prefixes for the other servers. Each server will be
054: * initialized from the main <code>server.props</code> with the
055: * specified prefix. In this way, the configuration parameters for
056: * all the sub-servers can be stored in the same <code>Properties</code>
057: * object.
058: *
059: * <dt> <i>prefix</i>.host
060: * <dd> Each server is started with a given <i>prefix</i>. The property
061: * <i>prefix</i>.host specifies the virtual hostname that the server
062: * will be expected to handle. If this property is not specified,
063: * the server's virtual hostname will just be <i>prefix</i>.
064: *
065: * <dt> <i>prefix</i>.handler
066: * <dd> The main handler for the server with the given <i>prefix</i>. If
067: * this property is not specified, it defaults to the
068: * <code>FileHandler</code>.
069: *
070: * <dt> <i>prefix</i>.log
071: * <dd> The log level for the server with the given <i>prefix</i>. If this
072: * property is not specified, it defaults to the log level of the
073: * parent server.
074: * </dl>
075: *
076: * A sample set of configuration parameters illustrating how to use this
077: * handler follows:
078: * <pre>
079: * handler=host
080: * port=8081
081: * log=5
082: *
083: * host.class=sunlabs.brazil.server.MultiHostHandler
084: * host.servers=mars jupiter saturn
085: *
086: * mars.host=www.mars.com
087: * mars.log=2
088: * mars.handler=mars.file
089: * mars.file.class=sunlabs.brazil.server.FileHandler
090: * mars.file.root=public_html/mars
091: *
092: * jupiter.host=jupiter.planet.org
093: * jupiter.handler=sunlabs.brazil.server.FileHandler
094: * jupiter.root=public_html/jupiter
095: *
096: * saturn.host=saturn.planet.org
097: * saturn.handler=sunlabs.brazil.server.FileHandler
098: * saturn.root=public_html/saturn
099: * </pre>
100: * These parameters set up a normal <code>Server</code> on port 8081,
101: * running a <code>MultiHostHandler</code>. The <code>MultiHostHandler</code>
102: * will create three additional servers that respond to the virtual hosts
103: * "www.mars.com", "jupiter.planet.org", and "saturn.planet.org". The
104: * "mars" server will have a <code>Server.prefix</code> of "mars",
105: * so that all other configuration parameters that the "mars" server
106: * examines can begin with "mars" and be kept distinct from the "jupiter"
107: * and "saturn" parameters.
108: * <p>
109: * In fact, the main server and the three sub-servers will all share the
110: * same properties object, but can use their own individual prefixes to
111: * keep their data separate.
112: * <p>
113: * NOTE: This handler is in the Server package because it depends
114: * on implementation details of the Server and Request classes, not
115: * because it represents essential or "core" functionallity.
116: *
117: * @author Colin Stevens (colin.stevens@sun.com)
118: * @version 1.5, 00/12/11
119: */
120: public class MultiHostHandler implements Handler {
121: private final Hashtable servers = new Hashtable();
122:
123: /**
124: * Initializes the servers for the virtual hosts. After creating
125: * and initializing each sub-server, the <code>init</code> method of the
126: * main handler for each sub-server is called.
127: *
128: * @param server
129: * The HTTP server that created this handler.
130: *
131: * @param prefix
132: * A prefix to prepend to all of the keys that this
133: * handler uses to extract configuration information.
134: *
135: * @return <code>true</code> if at least one sub-server was found and
136: * could be initialized, <code>false</code> otherwise.
137: * Diagnostic messages are logged for each sub-server started.
138: */
139: public boolean init(Server server, String prefix) {
140: Properties props = server.props;
141:
142: String list = props.getProperty(prefix + "servers", "");
143: StringTokenizer st = new StringTokenizer(list);
144: while (st.hasMoreTokens()) {
145: String name = st.nextToken();
146:
147: server.log(Server.LOG_DIAGNOSTIC, prefix,
148: "creating subserver " + name);
149:
150: String handler = props.getProperty(name + ".handler",
151: FileHandler.class.getName());
152:
153: Server sub = new Server(server.listen, handler, props);
154: sub.hostName = props.getProperty(name + ".host", name);
155: sub.prefix = name;
156: try {
157: String str = props.getProperty(name + ".log");
158: sub.logLevel = Integer.decode(str).intValue();
159: } catch (Exception e) {
160: sub.logLevel = server.logLevel;
161: }
162:
163: try {
164: if (sub.init()) {
165: servers.put(sub.hostName, sub);
166: }
167: } catch (IOException e) {
168: }
169: }
170: return (servers.size() > 0);
171: }
172:
173: /**
174: * Responds to an HTTP request by examining the "Host:" request header
175: * and dispatching to the main handler of the server that handles
176: * that virtual host. If the "Host:" request header was not specified,
177: * or named a virtual host that was not initialized in <code>init</code>
178: * from the list of virtual hosts, this method returns without
179: * handling the request.
180: *
181: * @param request
182: * The HTTP request to be forwarded to one of the sub-servers.
183: *
184: * @return <code>true</code> if the sub-server handled the message,
185: * <code>false</code> if it did not. <code>false</code> is
186: * also returned if the "Host:" was unspecified or unknown.
187: */
188: public boolean respond(Request request) throws IOException {
189: String host = request.getRequestHeader("Host");
190: if (host == null) {
191: return false;
192: }
193: Server server = (Server) servers.get(host);
194: if (server == null) {
195: return false;
196: }
197:
198: request.server = server;
199: return server.handler.respond(request);
200: }
201: }
|