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.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 }