View Javadoc

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.lang.reflect.Method;
25  import java.net.URL;
26  import java.util.Map;
27  
28  import org.apache.hadoop.classification.InterfaceAudience;
29  import org.apache.hadoop.conf.Configuration;
30  import org.apache.hadoop.hbase.HBaseConfiguration;
31  import org.apache.hadoop.http.HttpServer;
32  import org.mortbay.jetty.handler.ContextHandlerCollection;
33  import org.mortbay.jetty.servlet.Context;
34  import org.mortbay.jetty.servlet.DefaultServlet;
35  
36  /**
37   * Create a Jetty embedded server to answer http requests. The primary goal
38   * is to serve up status information for the server.
39   * There are three contexts:
40   *   "/stacks/" -> points to stack trace
41   *   "/static/" -> points to common static files (src/hbase-webapps/static)
42   *   "/" -> the jsp server code from (src/hbase-webapps/<name>)
43   */
44  @InterfaceAudience.Private
45  public class InfoServer extends HttpServer {
46    private final Configuration config;
47  
48    /**
49     * Create a status server on the given port.
50     * The jsp scripts are taken from src/hbase-webapps/<code>name<code>.
51     * @param name The name of the server
52     * @param bindAddress address to bind to
53     * @param port The port to use on the server
54     * @param findPort whether the server should start at the given port and
55     * increment by 1 until it finds a free port.
56     * @throws IOException e
57     */
58    public InfoServer(String name, String bindAddress, int port, boolean findPort,
59        final Configuration c)
60    throws IOException {
61      super(name, bindAddress, port, findPort, c);
62      this.config = c;
63      fixupLogsServletLocation();
64    }
65  
66    /**
67     * Fixup where the logs app points, make it point at hbase logs rather than
68     * hadoop logs.
69     */
70    private void fixupLogsServletLocation() {
71      // Must be same as up in hadoop.
72      final String logsContextPath = "/logs";
73      // Now, put my logs in place of hadoops... disable old one first.
74      Context oldLogsContext = null;
75      for (Map.Entry<Context, Boolean> e : defaultContexts.entrySet()) {
76        if (e.getKey().getContextPath().equals(logsContextPath)) {
77          oldLogsContext = e.getKey();
78          break;
79        }
80      }
81      if (oldLogsContext != null) {
82        this.defaultContexts.put(oldLogsContext, Boolean.FALSE);
83      }
84      // Now do my logs.
85      // Set up the context for "/logs/" if "hbase.log.dir" property is defined.
86      String logDir = System.getProperty("hbase.log.dir");
87      if (logDir != null) {
88        // This is a little presumptious but seems to work.
89        Context logContext =
90          new Context((ContextHandlerCollection)this.webServer.getHandler(),
91            logsContextPath);
92        logContext.setResourceBase(logDir);
93        logContext.addServlet(DefaultServlet.class, "/");
94        defaultContexts.put(logContext, true);
95      }
96    }
97  
98    /**
99     * Get the pathname to the webapps files.
100    * @param appName eg "secondary" or "datanode"
101    * @return the pathname as a URL
102    * @throws FileNotFoundException if 'webapps' directory cannot be found on CLASSPATH.
103    */
104   protected String getWebAppsPath(String appName) throws FileNotFoundException {
105     // Copied from the super-class.
106     String resourceName = "hbase-webapps/" + appName;
107     URL url = getClass().getClassLoader().getResource(resourceName);
108     if (url == null)
109       throw new FileNotFoundException(resourceName + " not found in CLASSPATH");
110     String urlString = url.toString();
111     return urlString.substring(0, urlString.lastIndexOf('/'));
112   }
113 
114   /**
115    * Get the pathname to the <code>path</code> files.
116    * @return the pathname as a URL
117    */
118   protected String getWebAppsPath() throws IOException {
119     // Hack: webapps is not a unique enough element to find in CLASSPATH
120     // We'll more than likely find the hadoop webapps dir.  So, instead
121     // look for the 'master' webapp in the webapps subdir.  That should
122     // get us the hbase context.  Presumption is that place where the
123     // master webapp resides is where we want this InfoServer picking up
124     // web applications.
125     final String master = "master";
126     String p = getWebAppsPath(master);
127     // Now strip master off the end if it is present
128     if(p.endsWith(master)) {
129       return p.substring(0, p.lastIndexOf(master));
130     }
131     return p;
132   }
133 }