com.baidu.rigel.biplatform.ma.file.serv.FileServer.java Source code

Java tutorial

Introduction

Here is the source code for com.baidu.rigel.biplatform.ma.file.serv.FileServer.java

Source

/**
 * Copyright (c) 2014 Baidu, Inc. All Rights Reserved.
 *
 * Licensed 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 com.baidu.rigel.biplatform.ma.file.serv;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.io.File;
import java.io.FileInputStream;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.baidu.rigel.biplatform.ma.common.file.protocol.Request;
import com.baidu.rigel.biplatform.ma.common.file.protocol.Response;
import com.baidu.rigel.biplatform.ma.common.file.protocol.ResponseStatus;
import com.baidu.rigel.biplatform.ma.file.serv.service.FileLocation;
import com.baidu.rigel.biplatform.ma.file.serv.service.LocalFileOperationService;
import com.baidu.rigel.biplatform.ma.file.serv.service.impl.LocalFileOperationServiceImpl;
import com.baidu.rigel.biplatform.ma.file.serv.util.LocalFileOperationUtils;

/**
 * 
 * ?server ?????
 * 
 * @author david.wang
 * @version 1.0.0.1
 */
public class FileServer extends ChannelHandlerAdapter {

    /**
     * 
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(FileServer.class);

    /**
     * ?target
     */
    private static final String TARGET = "target";

    /**
     * ?data
     */
    private static final String DATA = "data";

    /**
     * ?replace
     */
    private static final String REPLACE = "replace";

    /**
     * ?src
     */
    private static final String SRC = "src";

    /**
     * ?dir
     */
    private static final String DIR = "dir";

    /**
     * 
     */
    private static FileLocation fileLocation;

    /**
     * ???
     */
    private static LocalFileOperationService service = null;

    /**
     * file server root directory property key
     */
    private static final String ROOT_DIR_KEY = "biplatform.fileserver.rootdir";

    /**
     * file server port property key
     */
    private static final String PORT_NUM_KEY = "biplatform.fileserver.port";

    /**
     * 
     * ???server
     * 
     * @param args
     */
    public static void main(String[] args) throws Exception {
        //        if (args.length != 1) {
        //            LOGGER.error("can not get enough parameters for starting file server");
        //            printUsage();
        //            System.exit(-1);
        //        }

        FileInputStream fis = null;
        String classLocation = FileServer.class.getProtectionDomain().getCodeSource().getLocation().toString();
        final File configFile = new File(classLocation + "/../conf/fileserver.conf");
        Properties properties = new Properties();
        try {
            if (configFile.exists()) {
                fis = new FileInputStream(configFile);
            } else if (StringUtils.isNotEmpty(args[0])) {
                fis = new FileInputStream(args[0]);
            } else {
                printUsage();
                throw new RuntimeException("can't find correct file server configuration file!");
            }
            properties.load(fis);
        } finally {
            if (fis != null) {
                fis.close();
            }
        }
        int port = -1;
        try {
            port = Integer.valueOf(properties.getProperty(PORT_NUM_KEY));
        } catch (NumberFormatException e) {
            LOGGER.error("parameter is not correct, [port = {}]", args[0]);
            System.exit(-1);
        }

        String location = properties.getProperty(ROOT_DIR_KEY);
        if (StringUtils.isEmpty(location)) {
            LOGGER.error("the location can not be empty");
            System.exit(-1);
        }

        File f = new File(location);
        if (!f.exists() && !f.mkdirs()) {
            LOGGER.error("invalidation location [{}] please verify the input", args[1]);
            System.exit(-1);
        }
        startServer(location, port);
    }

    private static void startServer(String location, int port) {
        fileLocation = new FileLocation(location);
        service = new LocalFileOperationServiceImpl(fileLocation);
        EventLoopGroup bossGroup = new NioEventLoopGroup(10);
        EventLoopGroup workGroup = new NioEventLoopGroup(50);
        try {
            ServerBootstrap strap = new ServerBootstrap();
            strap.group(bossGroup, workGroup).channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 100).handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel channel) throws Exception {
                            // ??
                            channel.pipeline().addLast(new ObjectDecoder(ClassResolvers
                                    .weakCachingConcurrentResolver(FileServer.class.getClassLoader())));
                            channel.pipeline().addLast(new ObjectEncoder());
                            //                        channel.pipeline().addLast("HeartBeatHandler", new HeartBeatRespHandler());
                            channel.pipeline().addLast(new FileServer());
                        }
                    });
            ChannelFuture future = strap.bind(port).sync();
            LOGGER.info("start file server successfully");
            LOGGER.info("port : " + port);
            LOGGER.info("location : " + location);
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            LOGGER.error("can not start file server with [port : {}] and fileLocation {{}}", port, location);
            printUsage();
            System.exit(-1);
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    /**
     * ????
     */
    private static void printUsage() {
        LOGGER.info("=====================================================");
        LOGGER.info("=  Usage: java -jar <jar file> <config_file_location>");
        LOGGER.info("=  eg: java -jar <jar file> /tmp/config.properties   ");
        LOGGER.info("=====================================================");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        LOGGER.info("get message from client " + msg);
        Request req = (Request) msg;
        // ??
        switch (req.getCommand()) {
        case COPY:
            doCopy(ctx, req);
            break;
        case FILE_ATTRIBUTES:
            doGetFileAttribuets(ctx, req);
            break;
        case LS:
            doLs(ctx, req);
            break;
        case MKDIR:
            doMkDir(ctx, req);
            break;
        case MKDIRS:
            doMkDirs(ctx, req);
            break;
        case MV:
            doMv(ctx, req);
            break;
        case RM:
            doRm(ctx, req);
            break;
        case WRITE:
            doWrite(ctx, req);
            break;
        case READ:
            doRead(ctx, req);
            break;
        default:
            Response rs = new Response(ResponseStatus.UNKNOW, "", null);
            ctx.writeAndFlush(rs);
            return;
        }
    }

    private void doRead(ChannelHandlerContext ctx, Request req) {
        String dir = (String) req.getParams().get(DIR);
        Map<String, Object> result = service.read(dir);
        response(ctx, result);
    }

    /**
     * 
     * 
     * @param ctx
     * @param req
     */
    private void doWrite(ChannelHandlerContext ctx, Request req) {
        Map<String, Object> params = req.getParams();
        Response response = checkInput(ctx, params);
        if (response != null) {
            ctx.writeAndFlush(response);
            return;
        }

        if (!params.containsKey(REPLACE)) {
            response = new Response(ResponseStatus.FAIL, "request must content parameter with name replace", null);
            ctx.writeAndFlush(response);
            return;
        }

        if (!params.containsKey(DATA)) {
            response = new Response(ResponseStatus.FAIL, "request must content parameter with name data", null);
            ctx.writeAndFlush(response);
            return;
        }

        String path = (String) params.get(DIR);
        boolean replace = (boolean) params.get(REPLACE);
        byte[] content = (byte[]) params.get(DATA);
        Map<String, Object> rs = service.write(getAbsPath(path), content, replace);
        response(ctx, rs);

    }

    /**
     * 
     * 
     * @param ctx
     * @param req
     */
    private void doRm(ChannelHandlerContext ctx, Request req) {
        Map<String, Object> params = req.getParams();
        Response response = checkInput(ctx, params);
        if (response != null) {
            ctx.writeAndFlush(response);
            return;
        }
        String path = (String) params.get(DIR);
        Map<String, Object> rs = service.rm(getAbsPath(path));
        response(ctx, rs);
    }

    /**
     * 
     * 
     * @param ctx
     * @param req
     */
    private void doMv(ChannelHandlerContext ctx, Request req) {
        Map<String, Object> params = req.getParams();
        Response response = checkInputs(ctx, params);
        if (response != null) {
            ctx.writeAndFlush(response);
            return;
        }
        String srcFile = (String) params.get(SRC);
        String targetFile = (String) params.get(TARGET);
        boolean replace = (boolean) params.get(REPLACE);
        Map<String, Object> rs = service.mv(getAbsPath(srcFile), getAbsPath(targetFile), replace);
        response(ctx, rs);

    }

    /**
     * ?
     * 
     * @param ctx
     * @param params
     */
    private Response checkInputs(ChannelHandlerContext ctx, Map<String, Object> params) {
        if (params == null) {
            return new Response(ResponseStatus.FAIL, "bad reqeust", null);
        }

        if (!params.containsKey(SRC)) {
            return new Response(ResponseStatus.FAIL, "request must content parameter with name src", null);
        }

        if (!params.containsKey(TARGET)) {
            return new Response(ResponseStatus.FAIL, "request must content parameter with name target", null);
        }

        if (!params.containsKey(REPLACE)) {
            return new Response(ResponseStatus.FAIL, "request must content parameter with name replace", null);
        }
        return null;
    }

    /**
     * 
     * 
     * @param ctx
     * @param req
     */
    private void doMkDirs(ChannelHandlerContext ctx, Request req) {
        Map<String, Object> params = req.getParams();
        Response response = checkInput(ctx, params);
        if (response != null) {
            ctx.writeAndFlush(response);
            return;
        }
        String path = (String) params.get(DIR);
        Map<String, Object> rs = service.mkdirs(getAbsPath(path));
        response(ctx, rs);
    }

    /**
     * 
     * 
     * @param ctx
     * @param req
     */
    private void doMkDir(ChannelHandlerContext ctx, Request req) {
        Map<String, Object> params = req.getParams();
        Response response = checkInput(ctx, params);
        if (response != null) {
            ctx.writeAndFlush(response);
            return;
        }
        String path = (String) params.get(DIR);
        Map<String, Object> rs = service.mkdir(getAbsPath(path));
        response(ctx, rs);
    }

    /**
     * ?
     * 
     * @param ctx
     * @param params
     * @return
     */
    private Response checkInput(ChannelHandlerContext ctx, Map<String, Object> params) {
        if (params == null) {
            return new Response(ResponseStatus.FAIL, "bad reqeust", null);
        }

        if (!params.containsKey(DIR)) {
            return new Response(ResponseStatus.FAIL, "request must content parameter with name dir", null);
        }
        return null;
    }

    /**
     * ?
     * 
     * @param ctx
     * @param req
     */
    private void doLs(ChannelHandlerContext ctx, Request req) {
        Map<String, Object> params = req.getParams();
        Response response = checkInput(ctx, params);
        if (response != null) {
            ctx.writeAndFlush(response);
            return;
        }
        String path = (String) params.get(DIR);
        Map<String, Object> rs = service.ls(getAbsPath(path));
        response(ctx, rs);
    }

    /**
     * ??
     * 
     * @param ctx
     * @param req
     */
    private void doGetFileAttribuets(ChannelHandlerContext ctx, Request req) {
        Map<String, Object> params = req.getParams();
        Response response = checkInput(ctx, params);
        if (response != null) {
            ctx.writeAndFlush(response);
            return;
        }
        String path = (String) params.get(DIR);
        Map<String, Object> rs = service.getFileAttributes(getAbsPath(path));
        response(ctx, rs);
    }

    /**
     * ??
     * 
     * @param path
     * @return
     */
    private String getAbsPath(String path) {
        return fileLocation.value() + "/" + path;
    }

    /**
     * ??
     * 
     * @param ctx
     * @param req
     */
    private void doCopy(ChannelHandlerContext ctx, Request req) {
        Map<String, Object> params = req.getParams();
        Response response = checkInputs(ctx, params);
        if (response != null) {
            ctx.writeAndFlush(response);
            return;
        }
        String srcFile = (String) params.get(SRC);
        String targetFile = (String) params.get(TARGET);
        boolean replace = (boolean) params.get(REPLACE);
        Map<String, Object> rs = service.copy(getAbsPath(srcFile), getAbsPath(targetFile), replace);
        response(ctx, rs);
    }

    /**
     * ???
     * 
     * @param ctx
     * @param rs
     */
    private void response(ChannelHandlerContext ctx, Map<String, Object> rs) {
        if (rs.get(LocalFileOperationUtils.RESULT).equals(LocalFileOperationUtils.FAIL)) {
            Response response = new Response(ResponseStatus.FAIL, (String) rs.get(LocalFileOperationUtils.MSG), rs);
            ctx.writeAndFlush(response);
        } else {
            Response response = new Response(ResponseStatus.SUCCESS, (String) rs.get(LocalFileOperationUtils.MSG),
                    rs);
            ctx.writeAndFlush(response);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        LOGGER.error(cause.getMessage(), cause);
        ctx.close();
    }

}