001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package org.apache.hadoop.lib.servlet;
020
021 import com.google.common.annotations.VisibleForTesting;
022 import org.apache.hadoop.classification.InterfaceAudience;
023 import org.apache.hadoop.conf.Configuration;
024 import org.apache.hadoop.lib.server.Server;
025 import org.apache.hadoop.lib.server.ServerException;
026
027 import javax.servlet.ServletContextEvent;
028 import javax.servlet.ServletContextListener;
029 import java.net.InetAddress;
030 import java.net.InetSocketAddress;
031 import java.net.UnknownHostException;
032 import java.text.MessageFormat;
033
034 /**
035 * {@link Server} subclass that implements <code>ServletContextListener</code>
036 * and uses its lifecycle to start and stop the server.
037 */
038 @InterfaceAudience.Private
039 public abstract class ServerWebApp extends Server implements ServletContextListener {
040
041 private static final String HOME_DIR = ".home.dir";
042 private static final String CONFIG_DIR = ".config.dir";
043 private static final String LOG_DIR = ".log.dir";
044 private static final String TEMP_DIR = ".temp.dir";
045 private static final String HTTP_HOSTNAME = ".http.hostname";
046 private static final String HTTP_PORT = ".http.port";
047 public static final String SSL_ENABLED = ".ssl.enabled";
048
049 private static ThreadLocal<String> HOME_DIR_TL = new ThreadLocal<String>();
050
051 private InetSocketAddress authority;
052
053 /**
054 * Method for testing purposes.
055 */
056 public static void setHomeDirForCurrentThread(String homeDir) {
057 HOME_DIR_TL.set(homeDir);
058 }
059
060 /**
061 * Constructor for testing purposes.
062 */
063 protected ServerWebApp(String name, String homeDir, String configDir, String logDir, String tempDir,
064 Configuration config) {
065 super(name, homeDir, configDir, logDir, tempDir, config);
066 }
067
068 /**
069 * Constructor for testing purposes.
070 */
071 protected ServerWebApp(String name, String homeDir, Configuration config) {
072 super(name, homeDir, config);
073 }
074
075 /**
076 * Constructor. Subclasses must have a default constructor specifying
077 * the server name.
078 * <p/>
079 * The server name is used to resolve the Java System properties that define
080 * the server home, config, log and temp directories.
081 * <p/>
082 * The home directory is looked in the Java System property
083 * <code>#SERVER_NAME#.home.dir</code>.
084 * <p/>
085 * The config directory is looked in the Java System property
086 * <code>#SERVER_NAME#.config.dir</code>, if not defined it resolves to
087 * the <code>#SERVER_HOME_DIR#/conf</code> directory.
088 * <p/>
089 * The log directory is looked in the Java System property
090 * <code>#SERVER_NAME#.log.dir</code>, if not defined it resolves to
091 * the <code>#SERVER_HOME_DIR#/log</code> directory.
092 * <p/>
093 * The temp directory is looked in the Java System property
094 * <code>#SERVER_NAME#.temp.dir</code>, if not defined it resolves to
095 * the <code>#SERVER_HOME_DIR#/temp</code> directory.
096 *
097 * @param name server name.
098 */
099 public ServerWebApp(String name) {
100 super(name, getHomeDir(name),
101 getDir(name, CONFIG_DIR, getHomeDir(name) + "/conf"),
102 getDir(name, LOG_DIR, getHomeDir(name) + "/log"),
103 getDir(name, TEMP_DIR, getHomeDir(name) + "/temp"), null);
104 }
105
106 /**
107 * Returns the server home directory.
108 * <p/>
109 * It is looked up in the Java System property
110 * <code>#SERVER_NAME#.home.dir</code>.
111 *
112 * @param name the server home directory.
113 *
114 * @return the server home directory.
115 */
116 static String getHomeDir(String name) {
117 String homeDir = HOME_DIR_TL.get();
118 if (homeDir == null) {
119 String sysProp = name + HOME_DIR;
120 homeDir = System.getProperty(sysProp);
121 if (homeDir == null) {
122 throw new IllegalArgumentException(MessageFormat.format("System property [{0}] not defined", sysProp));
123 }
124 }
125 return homeDir;
126 }
127
128 /**
129 * Convenience method that looks for Java System property defining a
130 * diretory and if not present defaults to the specified directory.
131 *
132 * @param name server name, used as prefix of the Java System property.
133 * @param dirType dir type, use as postfix of the Java System property.
134 * @param defaultDir the default directory to return if the Java System
135 * property <code>name + dirType</code> is not defined.
136 *
137 * @return the directory defined in the Java System property or the
138 * the default directory if the Java System property is not defined.
139 */
140 static String getDir(String name, String dirType, String defaultDir) {
141 String sysProp = name + dirType;
142 return System.getProperty(sysProp, defaultDir);
143 }
144
145 /**
146 * Initializes the <code>ServletContextListener</code> which initializes
147 * the Server.
148 *
149 * @param event servelt context event.
150 */
151 @Override
152 public void contextInitialized(ServletContextEvent event) {
153 try {
154 init();
155 } catch (ServerException ex) {
156 event.getServletContext().log("ERROR: " + ex.getMessage());
157 throw new RuntimeException(ex);
158 }
159 }
160
161 /**
162 * Resolves the host & port InetSocketAddress the web server is listening to.
163 * <p/>
164 * This implementation looks for the following 2 properties:
165 * <ul>
166 * <li>#SERVER_NAME#.http.hostname</li>
167 * <li>#SERVER_NAME#.http.port</li>
168 * </ul>
169 *
170 * @return the host & port InetSocketAddress the web server is listening to.
171 * @throws ServerException thrown if any of the above 2 properties is not defined.
172 */
173 protected InetSocketAddress resolveAuthority() throws ServerException {
174 String hostnameKey = getName() + HTTP_HOSTNAME;
175 String portKey = getName() + HTTP_PORT;
176 String host = System.getProperty(hostnameKey);
177 String port = System.getProperty(portKey);
178 if (host == null) {
179 throw new ServerException(ServerException.ERROR.S13, hostnameKey);
180 }
181 if (port == null) {
182 throw new ServerException(ServerException.ERROR.S13, portKey);
183 }
184 try {
185 InetAddress add = InetAddress.getByName(host);
186 int portNum = Integer.parseInt(port);
187 return new InetSocketAddress(add, portNum);
188 } catch (UnknownHostException ex) {
189 throw new ServerException(ServerException.ERROR.S14, ex.toString(), ex);
190 }
191 }
192
193 /**
194 * Destroys the <code>ServletContextListener</code> which destroys
195 * the Server.
196 *
197 * @param event servelt context event.
198 */
199 @Override
200 public void contextDestroyed(ServletContextEvent event) {
201 destroy();
202 }
203
204 /**
205 * Returns the hostname:port InetSocketAddress the webserver is listening to.
206 *
207 * @return the hostname:port InetSocketAddress the webserver is listening to.
208 */
209 public InetSocketAddress getAuthority() throws ServerException {
210 synchronized (this) {
211 if (authority == null) {
212 authority = resolveAuthority();
213 }
214 }
215 return authority;
216 }
217
218 /**
219 * Sets an alternate hostname:port InetSocketAddress to use.
220 * <p/>
221 * For testing purposes.
222 *
223 * @param authority alterante authority.
224 */
225 @VisibleForTesting
226 public void setAuthority(InetSocketAddress authority) {
227 this.authority = authority;
228 }
229
230
231 /**
232 *
233 */
234 public boolean isSslEnabled() {
235 return Boolean.valueOf(System.getProperty(getName() + SSL_ENABLED, "false"));
236 }
237 }