Java tutorial
/** * 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.util.Map; 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; /** * * ???server * * @param args */ public static void main(String[] args) { if (args.length != 2) { LOGGER.error("can not get enough parameters for starting file server"); printUsage(); System.exit(-1); } int port = -1; try { port = Integer.valueOf(args[0]); } catch (NumberFormatException e) { LOGGER.error("parameter is not correct, [port = {}]", args[0]); printUsage(); System.exit(-1); } String location = args[1]; if (StringUtils.isEmpty(location)) { LOGGER.error("the location can not be empty"); printUsage(); System.exit(-1); } File f = new File(location); if (!f.exists() && !f.mkdirs()) { LOGGER.error("invalidation location [{}] please verify the input", args[1]); printUsage(); 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> port location "); LOGGER.info("= eg: java -jar <jar file> 8080 /tmp "); LOGGER.info("= location: the root path of the file store location"); LOGGER.info("= port: the server port "); 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 * @param service2 */ 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 * @param service */ 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(); } }