All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.hadoop.hbase.client.example.HttpProxyExample Maven / Gradle / Ivy

There is a newer version: 3.0.0-beta-1
Show newest version
/*
 * 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.client.example;

import static org.apache.hadoop.hbase.util.FutureUtils.addListener;
import static org.apache.hadoop.hbase.util.NettyFutureUtils.safeWriteAndFlush;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.AsyncConnection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.ipc.NettyRpcClientConfigHelper;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.yetus.audience.InterfaceAudience;

import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
import org.apache.hbase.thirdparty.com.google.common.base.Splitter;
import org.apache.hbase.thirdparty.com.google.common.base.Throwables;
import org.apache.hbase.thirdparty.io.netty.bootstrap.ServerBootstrap;
import org.apache.hbase.thirdparty.io.netty.buffer.ByteBuf;
import org.apache.hbase.thirdparty.io.netty.channel.Channel;
import org.apache.hbase.thirdparty.io.netty.channel.ChannelHandlerContext;
import org.apache.hbase.thirdparty.io.netty.channel.ChannelInitializer;
import org.apache.hbase.thirdparty.io.netty.channel.ChannelOption;
import org.apache.hbase.thirdparty.io.netty.channel.EventLoopGroup;
import org.apache.hbase.thirdparty.io.netty.channel.SimpleChannelInboundHandler;
import org.apache.hbase.thirdparty.io.netty.channel.group.ChannelGroup;
import org.apache.hbase.thirdparty.io.netty.channel.group.DefaultChannelGroup;
import org.apache.hbase.thirdparty.io.netty.channel.nio.NioEventLoopGroup;
import org.apache.hbase.thirdparty.io.netty.channel.socket.nio.NioServerSocketChannel;
import org.apache.hbase.thirdparty.io.netty.channel.socket.nio.NioSocketChannel;
import org.apache.hbase.thirdparty.io.netty.handler.codec.http.DefaultFullHttpResponse;
import org.apache.hbase.thirdparty.io.netty.handler.codec.http.FullHttpRequest;
import org.apache.hbase.thirdparty.io.netty.handler.codec.http.HttpHeaderNames;
import org.apache.hbase.thirdparty.io.netty.handler.codec.http.HttpObjectAggregator;
import org.apache.hbase.thirdparty.io.netty.handler.codec.http.HttpResponseStatus;
import org.apache.hbase.thirdparty.io.netty.handler.codec.http.HttpServerCodec;
import org.apache.hbase.thirdparty.io.netty.handler.codec.http.HttpVersion;
import org.apache.hbase.thirdparty.io.netty.handler.codec.http.QueryStringDecoder;
import org.apache.hbase.thirdparty.io.netty.util.concurrent.GlobalEventExecutor;

/**
 * A simple example on how to use {@link org.apache.hadoop.hbase.client.AsyncTable} to write a fully
 * asynchronous HTTP proxy server. The {@link AsyncConnection} will share the same event loop with
 * the HTTP server.
 * 

* The request URL is: * *

 * http://<host>:<port>/<table>/<rowgt;/<family>:<qualifier>
 * 
* * Use HTTP GET to fetch data, and use HTTP PUT to put data. Encode the value as the request content * when doing PUT. *

* Notice that, future class methods will all return a new Future, so you always have one future * that will not been checked, so we need to suppress error-prone "FutureReturnValueIgnored" * warnings on the methods such as join and stop. In your real production code, you should use your * own convenient way to address the warning. */ @InterfaceAudience.Private public class HttpProxyExample { private final EventLoopGroup bossGroup = new NioEventLoopGroup(1); private final EventLoopGroup workerGroup = new NioEventLoopGroup(); private final Configuration conf; private final int port; private AsyncConnection conn; private Channel serverChannel; private ChannelGroup channelGroup; public HttpProxyExample(Configuration conf, int port) { this.conf = conf; this.port = port; } private static final class Params { public final String table; public final String row; public final String family; public final String qualifier; public Params(String table, String row, String family, String qualifier) { this.table = table; this.row = row; this.family = family; this.qualifier = qualifier; } } private static final class RequestHandler extends SimpleChannelInboundHandler { private final AsyncConnection conn; private final ChannelGroup channelGroup; public RequestHandler(AsyncConnection conn, ChannelGroup channelGroup) { this.conn = conn; this.channelGroup = channelGroup; } @Override public void channelActive(ChannelHandlerContext ctx) { channelGroup.add(ctx.channel()); ctx.fireChannelActive(); } @Override public void channelInactive(ChannelHandlerContext ctx) { channelGroup.remove(ctx.channel()); ctx.fireChannelInactive(); } private void write(ChannelHandlerContext ctx, HttpResponseStatus status) { write(ctx, status, null); } private void write(ChannelHandlerContext ctx, HttpResponseStatus status, String content) { DefaultFullHttpResponse resp; if (content != null) { ByteBuf buf = ctx.alloc().buffer().writeBytes(Bytes.toBytes(content)); resp = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, buf); resp.headers().set(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes()); } else { resp = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status); } resp.headers().set(HttpHeaderNames.CONTENT_TYPE, "text-plain; charset=UTF-8"); safeWriteAndFlush(ctx, resp); } private Params parse(FullHttpRequest req) { List components = Splitter.on('/').splitToList(new QueryStringDecoder(req.uri()).path()); Preconditions.checkArgument(components.size() == 4, "Unrecognized uri: %s", req.uri()); Iterator i = components.iterator(); // path is start with '/' so split will give an empty component i.next(); String table = i.next(); String row = i.next(); List cfAndCq = Splitter.on(':').splitToList(i.next()); Preconditions.checkArgument(cfAndCq.size() == 2, "Unrecognized uri: %s", req.uri()); i = cfAndCq.iterator(); String family = i.next(); String qualifier = i.next(); return new Params(table, row, family, qualifier); } private void get(ChannelHandlerContext ctx, FullHttpRequest req) { Params params = parse(req); addListener( conn.getTable(TableName.valueOf(params.table)).get(new Get(Bytes.toBytes(params.row)) .addColumn(Bytes.toBytes(params.family), Bytes.toBytes(params.qualifier))), (r, e) -> { if (e != null) { exceptionCaught(ctx, e); } else { byte[] value = r.getValue(Bytes.toBytes(params.family), Bytes.toBytes(params.qualifier)); if (value != null) { write(ctx, HttpResponseStatus.OK, Bytes.toStringBinary(value)); } else { write(ctx, HttpResponseStatus.NOT_FOUND); } } }); } private void put(ChannelHandlerContext ctx, FullHttpRequest req) { Params params = parse(req); byte[] value = new byte[req.content().readableBytes()]; req.content().readBytes(value); addListener( conn.getTable(TableName.valueOf(params.table)).put(new Put(Bytes.toBytes(params.row)) .addColumn(Bytes.toBytes(params.family), Bytes.toBytes(params.qualifier), value)), (r, e) -> { if (e != null) { exceptionCaught(ctx, e); } else { write(ctx, HttpResponseStatus.OK); } }); } @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) { switch (req.method().name()) { case "GET": get(ctx, req); break; case "PUT": put(ctx, req); break; default: write(ctx, HttpResponseStatus.METHOD_NOT_ALLOWED); break; } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { if (cause instanceof IllegalArgumentException) { write(ctx, HttpResponseStatus.BAD_REQUEST, cause.getMessage()); } else { write(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, Throwables.getStackTraceAsString(cause)); } } } public void start() throws InterruptedException, ExecutionException { NettyRpcClientConfigHelper.setEventLoopConfig(conf, workerGroup, NioSocketChannel.class); conn = ConnectionFactory.createAsyncConnection(conf).get(); channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); serverChannel = new ServerBootstrap().group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) .childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_REUSEADDR, true) .childHandler(new ChannelInitializer() { @Override protected void initChannel(Channel ch) throws Exception { ch.pipeline().addFirst(new HttpServerCodec(), new HttpObjectAggregator(4 * 1024 * 1024), new RequestHandler(conn, channelGroup)); } }).bind(port).syncUninterruptibly().channel(); } @SuppressWarnings("FutureReturnValueIgnored") public void join() { serverChannel.closeFuture().awaitUninterruptibly(); } public int port() { if (serverChannel == null) { return port; } else { return ((InetSocketAddress) serverChannel.localAddress()).getPort(); } } @SuppressWarnings("FutureReturnValueIgnored") public void stop() throws IOException { serverChannel.close().syncUninterruptibly(); serverChannel = null; channelGroup.close().syncUninterruptibly(); channelGroup = null; conn.close(); conn = null; } public static void main(String[] args) throws InterruptedException, ExecutionException { int port = Integer.parseInt(args[0]); HttpProxyExample proxy = new HttpProxyExample(HBaseConfiguration.create(), port); proxy.start(); proxy.join(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy