1 /** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 package org.apache.hadoop.hbase.util; 21 22 import java.io.FileNotFoundException; 23 import java.io.IOException; 24 import java.net.URL; 25 import java.util.Map; 26 27 import org.apache.hadoop.classification.InterfaceAudience; 28 import org.apache.hadoop.conf.Configuration; 29 import org.apache.hadoop.http.HttpServer; 30 import org.mortbay.jetty.handler.ContextHandlerCollection; 31 import org.mortbay.jetty.servlet.Context; 32 import org.mortbay.jetty.servlet.DefaultServlet; 33 34 /** 35 * Create a Jetty embedded server to answer http requests. The primary goal 36 * is to serve up status information for the server. 37 * There are three contexts: 38 * "/stacks/" -> points to stack trace 39 * "/static/" -> points to common static files (src/hbase-webapps/static) 40 * "/" -> the jsp server code from (src/hbase-webapps/<name>) 41 */ 42 @InterfaceAudience.Private 43 public class InfoServer extends HttpServer { 44 private final Configuration config; 45 46 /** 47 * Create a status server on the given port. 48 * The jsp scripts are taken from src/hbase-webapps/<code>name<code>. 49 * @param name The name of the server 50 * @param bindAddress address to bind to 51 * @param port The port to use on the server 52 * @param findPort whether the server should start at the given port and 53 * increment by 1 until it finds a free port. 54 * @throws IOException e 55 */ 56 public InfoServer(String name, String bindAddress, int port, boolean findPort, 57 final Configuration c) 58 throws IOException { 59 super(name, bindAddress, port, findPort, c); 60 this.config = c; 61 fixupLogsServletLocation(); 62 } 63 64 /** 65 * Fixup where the logs app points, make it point at hbase logs rather than 66 * hadoop logs. 67 */ 68 private void fixupLogsServletLocation() { 69 // Must be same as up in hadoop. 70 final String logsContextPath = "/logs"; 71 // Now, put my logs in place of hadoops... disable old one first. 72 Context oldLogsContext = null; 73 for (Map.Entry<Context, Boolean> e : defaultContexts.entrySet()) { 74 if (e.getKey().getContextPath().equals(logsContextPath)) { 75 oldLogsContext = e.getKey(); 76 break; 77 } 78 } 79 if (oldLogsContext != null) { 80 this.defaultContexts.put(oldLogsContext, Boolean.FALSE); 81 } 82 // Now do my logs. 83 // Set up the context for "/logs/" if "hbase.log.dir" property is defined. 84 String logDir = System.getProperty("hbase.log.dir"); 85 if (logDir != null) { 86 // This is a little presumptious but seems to work. 87 Context logContext = 88 new Context((ContextHandlerCollection)this.webServer.getHandler(), 89 logsContextPath); 90 logContext.setResourceBase(logDir); 91 logContext.addServlet(DefaultServlet.class, "/"); 92 HttpServerUtil.constrainHttpMethods(logContext); 93 defaultContexts.put(logContext, true); 94 } 95 } 96 97 /** 98 * Get the pathname to the webapps files. 99 * @param appName eg "secondary" or "datanode" 100 * @return the pathname as a URL 101 * @throws FileNotFoundException if 'webapps' directory cannot be found on CLASSPATH. 102 */ 103 protected String getWebAppsPath(String appName) throws FileNotFoundException { 104 // Copied from the super-class. 105 String resourceName = "hbase-webapps/" + appName; 106 URL url = getClass().getClassLoader().getResource(resourceName); 107 if (url == null) 108 throw new FileNotFoundException(resourceName + " not found in CLASSPATH"); 109 String urlString = url.toString(); 110 return urlString.substring(0, urlString.lastIndexOf('/')); 111 } 112 113 /** 114 * Get the pathname to the <code>path</code> files. 115 * @return the pathname as a URL 116 */ 117 protected String getWebAppsPath() throws IOException { 118 // Hack: webapps is not a unique enough element to find in CLASSPATH 119 // We'll more than likely find the hadoop webapps dir. So, instead 120 // look for the 'master' webapp in the webapps subdir. That should 121 // get us the hbase context. Presumption is that place where the 122 // master webapp resides is where we want this InfoServer picking up 123 // web applications. 124 final String master = "master"; 125 String p = getWebAppsPath(master); 126 // Now strip master off the end if it is present 127 if(p.endsWith(master)) { 128 return p.substring(0, p.lastIndexOf(master)); 129 } 130 return p; 131 } 132 }