001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hdfs.tools.offlineImageViewer; 019 020import com.google.common.annotations.VisibleForTesting; 021import io.netty.bootstrap.ServerBootstrap; 022import io.netty.channel.Channel; 023import io.netty.channel.ChannelInitializer; 024import io.netty.channel.ChannelPipeline; 025import io.netty.channel.EventLoopGroup; 026import io.netty.channel.group.ChannelGroup; 027import io.netty.channel.group.DefaultChannelGroup; 028import io.netty.channel.nio.NioEventLoopGroup; 029import io.netty.channel.socket.SocketChannel; 030import io.netty.channel.socket.nio.NioServerSocketChannel; 031import io.netty.handler.codec.http.HttpRequestDecoder; 032import io.netty.handler.codec.http.HttpResponseEncoder; 033import io.netty.handler.codec.string.StringEncoder; 034import io.netty.util.concurrent.GlobalEventExecutor; 035import org.apache.commons.logging.Log; 036import org.apache.commons.logging.LogFactory; 037 038import java.io.Closeable; 039import java.io.IOException; 040import java.net.InetSocketAddress; 041 042/** 043 * WebImageViewer loads a fsimage and exposes read-only WebHDFS API for its 044 * namespace. 045 */ 046public class WebImageViewer implements Closeable { 047 public static final Log LOG = LogFactory.getLog(WebImageViewer.class); 048 049 private Channel channel; 050 private InetSocketAddress address; 051 052 private final ServerBootstrap bootstrap; 053 private final EventLoopGroup bossGroup; 054 private final EventLoopGroup workerGroup; 055 private final ChannelGroup allChannels; 056 057 public WebImageViewer(InetSocketAddress address) { 058 this.address = address; 059 this.bossGroup = new NioEventLoopGroup(); 060 this.workerGroup = new NioEventLoopGroup(); 061 this.allChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); 062 this.bootstrap = new ServerBootstrap() 063 .group(bossGroup, workerGroup) 064 .channel(NioServerSocketChannel.class); 065 } 066 067 /** 068 * Start WebImageViewer and wait until the thread is interrupted. 069 * @param fsimage the fsimage to load. 070 * @throws IOException if failed to load the fsimage. 071 */ 072 public void start(String fsimage) throws IOException { 073 try { 074 initServer(fsimage); 075 channel.closeFuture().await(); 076 } catch (InterruptedException e) { 077 LOG.info("Interrupted. Stopping the WebImageViewer."); 078 close(); 079 } 080 } 081 082 /** 083 * Start WebImageViewer. 084 * @param fsimage the fsimage to load. 085 * @throws IOException if fail to load the fsimage. 086 */ 087 @VisibleForTesting 088 public void initServer(String fsimage) 089 throws IOException, InterruptedException { 090 final FSImageLoader loader = FSImageLoader.load(fsimage); 091 092 bootstrap.childHandler(new ChannelInitializer<SocketChannel>() { 093 @Override 094 protected void initChannel(SocketChannel ch) throws Exception { 095 ChannelPipeline p = ch.pipeline(); 096 p.addLast(new HttpRequestDecoder(), 097 new StringEncoder(), 098 new HttpResponseEncoder(), 099 new FSImageHandler(loader, allChannels)); 100 } 101 }); 102 103 channel = bootstrap.bind(address).sync().channel(); 104 allChannels.add(channel); 105 106 address = (InetSocketAddress) channel.localAddress(); 107 LOG.info("WebImageViewer started. Listening on " + address.toString() + ". Press Ctrl+C to stop the viewer."); 108 } 109 110 /** 111 * Get the listening port. 112 * @return the port WebImageViewer is listening on 113 */ 114 @VisibleForTesting 115 public int getPort() { 116 return address.getPort(); 117 } 118 119 @Override 120 public void close() { 121 allChannels.close().awaitUninterruptibly(); 122 bossGroup.shutdownGracefully(); 123 workerGroup.shutdownGracefully(); 124 } 125}