Package org.apache.hadoop.hbase.rest

Source Code of org.apache.hadoop.hbase.rest.Dispatcher

/**
* Copyright 2007 The Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.rest;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.util.InfoServer;
import org.apache.hadoop.mapred.StatusHttpServer;
import org.mortbay.http.NCSARequestLog;
import org.mortbay.http.SocketListener;
import org.mortbay.jetty.servlet.WebApplicationContext;

/**
* Servlet implementation class for hbase REST interface.
* Presumes container ensures single thread through here at any one time
* (Usually the default configuration).  In other words, code is not
* written thread-safe.
* <p>This servlet has explicit dependency on Jetty server; it uses the
* jetty implementation of MultipartResponse.
*
* <p>TODO:
* <ul>
* <li>multipart/related response is not correct; the servlet setContentType
* is broken.  I am unable to add parameters such as boundary or start to
* multipart/related.  They get stripped.</li>
* <li>Currently creating a scanner, need to specify a column.  Need to make
* it so the HTable instance has current table's metadata to-hand so easy to
* find the list of all column families so can make up list of columns if none
* specified.</li>
* <li>Minor items are we are decoding URLs in places where probably already
* done and how to timeout scanners that are in the scanner list.</li>
* </ul>
* @see <a href="http://wiki.apache.org/lucene-hadoop/Hbase/HbaseRest">Hbase REST Specification</a>
*/
public class Dispatcher extends javax.servlet.http.HttpServlet
implements javax.servlet.Servlet {
  private static final Log LOG = LogFactory.getLog(Dispatcher.class.getName());
  private MetaHandler metaHandler;
  private TableHandler tableHandler;
  private ScannerHandler scannerHandler;

  private static final String SCANNER = "scanner";
  private static final String ROW = "row";
     
  /**
   * Default constructor
   */
  public Dispatcher() {
    super();
  }

  public void init() throws ServletException {
    super.init();
   
    HBaseConfiguration conf = new HBaseConfiguration();
    HBaseAdmin admin = null;
   
    try{
      admin = new HBaseAdmin(conf);
      metaHandler = new MetaHandler(conf, admin);
      tableHandler = new TableHandler(conf, admin);
      scannerHandler = new ScannerHandler(conf, admin);
    } catch(Exception e){
      throw new ServletException(e);
    }
  }

  protected void doGet(HttpServletRequest request, HttpServletResponse response)
  throws IOException, ServletException {
    String [] pathSegments = getPathSegments(request);
   
    if (pathSegments.length == 0 || pathSegments[0].length() <= 0) {
      // if it was a root request, then get some metadata about
      // the entire instance.
      metaHandler.doGet(request, response, pathSegments);
    } else {
      // otherwise, it must be a GET request suitable for the
      // table handler.
      tableHandler.doGet(request, response, pathSegments);
    }
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response)
  throws IOException, ServletException {
    String [] pathSegments = getPathSegments(request);
   
    // there should be at least two path segments (table name and row or scanner)
    if (pathSegments.length >= 2 && pathSegments[0].length() > 0) {
      if (pathSegments[1].toLowerCase().equals(SCANNER) &&
          pathSegments.length >= 2) {
        scannerHandler.doPost(request, response, pathSegments);
        return;
      } else if (pathSegments[1].toLowerCase().equals(ROW) && pathSegments.length >= 3) {
        tableHandler.doPost(request, response, pathSegments);
        return;
      }
    }

    // if we get to this point, then no handler was matched this request.
    GenericHandler.doNotFound(response, "No handler for " + request.getPathInfo());
  }
 

  protected void doPut(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
    // Equate PUT with a POST.
    doPost(request, response);
  }

  protected void doDelete(HttpServletRequest request,
      HttpServletResponse response)
  throws IOException, ServletException {
    String [] pathSegments = getPathSegments(request);
   
    // must be at least two path segments (table name and row or scanner)
    if (pathSegments.length >= 2 && pathSegments[0].length() > 0) {
      // DELETE to a scanner requires at least three path segments
      if (pathSegments[1].toLowerCase().equals(SCANNER) &&
          pathSegments.length == 3 && pathSegments[2].length() > 0) {
        scannerHandler.doDelete(request, response, pathSegments);
        return;
      } else if (pathSegments[1].toLowerCase().equals(ROW) &&
          pathSegments.length >= 3) {
        tableHandler.doDelete(request, response, pathSegments);
        return;
      }
    }
   
    // if we reach this point, then no handler exists for this request.
    GenericHandler.doNotFound(response, "No handler");
  }
 
  /*
   * @param request
   * @return request pathinfo split on the '/' ignoring the first '/' so first
   * element in pathSegment is not the empty string.
   */
  private String [] getPathSegments(final HttpServletRequest request) {
    int context_len = request.getContextPath().length() + 1;
    return request.getRequestURI().substring(context_len).split("/");
  }

  //
  // Main program and support routines
  //
 
  private static void printUsageAndExit() {
    printUsageAndExit(null);
  }
 
  private static void printUsageAndExit(final String message) {
    if (message != null) {
      System.err.println(message);
    }
    System.out.println("Usage: java org.apache.hadoop.hbase.rest.Dispatcher " +
      "--help | [--port=PORT] [--bind=ADDR] start");
    System.out.println("Arguments:");
    System.out.println(" start Start REST server");
    System.out.println(" stop  Stop REST server");
    System.out.println("Options:");
    System.out.println(" port  Port to listen on. Default: 60050.");
    System.out.println(" bind  Address to bind on. Default: 0.0.0.0.");
    System.out.println(" max-num-threads  The maximum number of threads for Jetty to run. Defaults to 256.");
    System.out.println(" help  Print this message and exit.");

    System.exit(0);
  }

  /*
   * Start up the REST servlet in standalone mode.
   * @param args
   */
  protected static void doMain(final String [] args) throws Exception {
    if (args.length < 1) {
      printUsageAndExit();
    }

    int port = 60050;
    String bindAddress = "0.0.0.0";
    int numThreads = 256;

    // Process command-line args. TODO: Better cmd-line processing
    // (but hopefully something not as painful as cli options).
    final String addressArgKey = "--bind=";
    final String portArgKey = "--port=";
    final String numThreadsKey = "--max-num-threads=";
    for (String cmd: args) {
      if (cmd.startsWith(addressArgKey)) {
        bindAddress = cmd.substring(addressArgKey.length());
        continue;
      } else if (cmd.startsWith(portArgKey)) {
        port = Integer.parseInt(cmd.substring(portArgKey.length()));
        continue;
      } else if (cmd.equals("--help") || cmd.equals("-h")) {
        printUsageAndExit();
      } else if (cmd.equals("start")) {
        continue;
      } else if (cmd.equals("stop")) {
        printUsageAndExit("To shutdown the REST server run " +
          "bin/hbase-daemon.sh stop rest or send a kill signal to " +
          "the REST server pid");
      } else if (cmd.startsWith(numThreadsKey)) {
        numThreads = Integer.parseInt(cmd.substring(numThreadsKey.length()));
        continue;
      }
     
      // Print out usage if we get to here.
      printUsageAndExit();
    }
    org.mortbay.jetty.Server webServer = new org.mortbay.jetty.Server();
    SocketListener listener = new SocketListener();
    listener.setPort(port);
    listener.setHost(bindAddress);
    listener.setMaxThreads(numThreads);
    webServer.addListener(listener);
    NCSARequestLog ncsa = new NCSARequestLog();
    ncsa.setLogLatency(true);
    webServer.setRequestLog(ncsa);
    WebApplicationContext context =
      webServer.addWebApplication("/api", InfoServer.getWebAppDir("rest"));
    context.addServlet("stacks", "/stacks",
      StatusHttpServer.StackServlet.class.getName());
    context.addServlet("logLevel", "/logLevel",
      org.apache.hadoop.log.LogLevel.Servlet.class.getName());
    webServer.start();
  }
 
  /**
   * @param args
   * @throws Exception
   */
  public static void main(String [] args) throws Exception {
    doMain(args);
  }
}
TOP

Related Classes of org.apache.hadoop.hbase.rest.Dispatcher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.