{
40 | /**
41 | * 日志组件.
42 | */
43 | private static final Logger LOGGER = LoggerFactory.getLogger(FileMsgEncoder.class);
44 |
45 | public FileMsgEncoder() {}
46 |
47 | /**
48 | * 编码.
49 | *
50 | * @param ctx Netty上下文
51 | * @param msg 信息实体
52 | * @param out 缓冲区
53 | *
54 | * 方法添加日期 :2014-10-11
55 | * 创建者:刘源
56 | */
57 | @Override
58 | protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) {
59 | LOGGER.info(String.format("[%s]发送出的报文:[%s]",
60 | ctx.channel().remoteAddress(),
61 | ByteBufUtil.hexDump((ByteBuf) msg)));
62 | out.writeBytes((byte[]) msg);
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/codec/StringCodec.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.codec;
4 |
5 | import io.netty.channel.ChannelDuplexHandler;
6 | import io.netty.channel.ChannelHandler;
7 | import io.netty.channel.CombinedChannelDuplexHandler;
8 | import io.netty.handler.codec.string.StringDecoder;
9 | import io.netty.handler.codec.string.StringEncoder;
10 | import io.netty.util.CharsetUtil;
11 |
12 | import java.nio.charset.Charset;
13 |
14 | /**
15 | * ━━━━━━神兽出没━━━━━━
16 | * ┏┓ ┏┓
17 | * ┏┛┻━━━┛┻┓
18 | * ┃ ┃
19 | * ┃ ━ ┃
20 | * ┃ ┳┛ ┗┳ ┃
21 | * ┃ ┃
22 | * ┃ ┻ ┃
23 | * ┃ ┃
24 | * ┗━┓ ┏━┛
25 | * ┃ ┃神兽保佑, 永无BUG!
26 | * ┃ ┃Code is far away from bug with the animal protecting
27 | * ┃ ┗━━━┓
28 | * ┃ ┣┓
29 | * ┃ ┏┛
30 | * ┗┓┓┏━┳┓┏┛
31 | * ┃┫┫ ┃┫┫
32 | * ┗┻┛ ┗┻┛
33 | * ━━━━━━感觉萌萌哒━━━━━━
34 | * Summary: TODO 描述信息
35 | * Author : anduo@qq.com
36 | * Version: 1.0
37 | * Date : 15/7/5
38 | * time : 17:06
39 | */
40 | public enum StringCodec {
41 |
42 | UTF8(new StrCodec(CharsetUtil.UTF_8));
43 |
44 | private final ChannelDuplexHandler c;
45 |
46 | StringCodec(ChannelDuplexHandler c) {
47 | this.c = c;
48 | }
49 |
50 | public ChannelDuplexHandler getCodec() {
51 | return c;
52 | }
53 |
54 | @ChannelHandler.Sharable
55 | private static class StrCodec extends CombinedChannelDuplexHandler {
56 | private StrCodec(Charset charset) {
57 | super(new StringDecoder(charset), new StringEncoder(charset));
58 | }
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/common/Constants.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.common;
4 |
5 | /**
6 | * ━━━━━━神兽出没━━━━━━
7 | * ┏┓ ┏┓
8 | * ┏┛┻━━━┛┻┓
9 | * ┃ ┃
10 | * ┃ ━ ┃
11 | * ┃ ┳┛ ┗┳ ┃
12 | * ┃ ┃
13 | * ┃ ┻ ┃
14 | * ┃ ┃
15 | * ┗━┓ ┏━┛
16 | * ┃ ┃神兽保佑, 永无BUG!
17 | * ┃ ┃Code is far away from bug with the animal protecting
18 | * ┃ ┗━━━┓
19 | * ┃ ┣┓
20 | * ┃ ┏┛
21 | * ┗┓┓┏━┳┓┏┛
22 | * ┃┫┫ ┃┫┫
23 | * ┗┻┛ ┗┻┛
24 | * ━━━━━━感觉萌萌哒━━━━━━
25 | * Summary: 常量
26 | * Author : anduo@qq.com
27 | * Version: 1.0
28 | * Date : 15/7/2
29 | * time : 22:32
30 | */
31 | public class Constants {
32 |
33 | /**
34 | * 配置文件路径
35 | */
36 | private static final String NAME_CONFIG_PATH = "name.properties";
37 | private static final String INIT_CONFIG_PATH = "local-nodes.properties";
38 | /**
39 | * NODE节点相关配置路径
40 | */
41 | public static final String CONFIG_NODES = "/myapp/config/nodes";
42 | /**
43 | * 公用配置信息路径
44 | */
45 | public static final String CONFIG_COMMON = "/myapp/config/commoncfg";
46 | /**
47 | * 节点注册路径
48 | */
49 | public static final String NODE_ROOT = "/myapp/nodes";
50 | /**
51 | * zookeeper服务器地址的properties参数名,在properties文件中设置
52 | */
53 | public static final String ZOOKEEPER_SERVERS_PRO = "zk.servers";
54 | /**
55 | * 所有配置所在zookeeper的根节点的 的properties参数名,在properties文件中设置
56 | */
57 | public static final String ZOOKEEPER_CONFIG_ROOT_PATH_PRO = "zk.config.root.path";
58 | /**
59 | * 项目配置数据的根节点
60 | */
61 | public static final String CONFIG_ROOT_PATH = "/myapp/config";
62 |
63 | public static final String DEFAULT_DATA_FILE_PATH = "Data";
64 | public static final int RANDOM_FILE_COUNT = 10;
65 | }
66 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/core/FileMsgSendInitializer.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.core;
4 |
5 | import com.anduo.filesync.codec.FileMsgDecoder;
6 | import com.anduo.filesync.codec.FileMsgEncoder;
7 | import com.anduo.filesync.handler.FileMsgSendHandler;
8 | import io.netty.channel.ChannelInitializer;
9 | import io.netty.channel.ChannelPipeline;
10 | import io.netty.channel.socket.SocketChannel;
11 | import io.netty.handler.stream.ChunkedWriteHandler;
12 | import io.netty.handler.timeout.IdleStateHandler;
13 |
14 | /**
15 | * ━━━━━━神兽出没━━━━━━
16 | * ┏┓ ┏┓
17 | * ┏┛┻━━━┛┻┓
18 | * ┃ ┃
19 | * ┃ ━ ┃
20 | * ┃ ┳┛ ┗┳ ┃
21 | * ┃ ┃
22 | * ┃ ┻ ┃
23 | * ┃ ┃
24 | * ┗━┓ ┏━┛
25 | * ┃ ┃神兽保佑, 永无BUG!
26 | * ┃ ┃Code is far away from bug with the animal protecting
27 | * ┃ ┗━━━┓
28 | * ┃ ┣┓
29 | * ┃ ┏┛
30 | * ┗┓┓┏━┳┓┏┛
31 | * ┃┫┫ ┃┫┫
32 | * ┗┻┛ ┗┻┛
33 | * ━━━━━━感觉萌萌哒━━━━━━
34 | * Summary: FileServerInitializer
35 | * Author : anduo@qq.com
36 | * Version: 1.0
37 | * Date : 15/7/5
38 | * time : 16:56
39 | */
40 | public class FileMsgSendInitializer extends ChannelInitializer {
41 |
42 | @Override
43 | public void initChannel(SocketChannel ch)
44 | throws Exception {
45 | // Create a default pipeline implementation.
46 | ChannelPipeline pipeline = ch.pipeline();
47 | pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
48 | pipeline.addLast("encod", new FileMsgEncoder());//编码
49 | pipeline.addLast("idle", new IdleStateHandler(3, 0, 0));//心跳
50 | pipeline.addLast("handle", new FileMsgSendHandler());//send file msg
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/core/FileMsgSender.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.core;
4 |
5 | import com.anduo.filesync.msg.FileMsg;
6 | import com.anduo.filesync.zk.ZKClient;
7 | import com.anduo.filesync.zk.ZKClientCache;
8 | import com.anduo.nodesyn.Constants;
9 | import com.anduo.nodesyn.util.NetUtil;
10 | import io.netty.bootstrap.Bootstrap;
11 | import io.netty.buffer.PooledByteBufAllocator;
12 | import io.netty.channel.AdaptiveRecvByteBufAllocator;
13 | import io.netty.channel.Channel;
14 | import io.netty.channel.ChannelOption;
15 | import io.netty.channel.EventLoopGroup;
16 | import io.netty.channel.nio.NioEventLoopGroup;
17 | import io.netty.channel.socket.nio.NioSocketChannel;
18 | import org.apache.curator.utils.ZKPaths;
19 | import org.slf4j.Logger;
20 | import org.slf4j.LoggerFactory;
21 |
22 | /**
23 | * ━━━━━━神兽出没━━━━━━
24 | * ┏┓ ┏┓
25 | * ┏┛┻━━━┛┻┓
26 | * ┃ ┃
27 | * ┃ ━ ┃
28 | * ┃ ┳┛ ┗┳ ┃
29 | * ┃ ┃
30 | * ┃ ┻ ┃
31 | * ┃ ┃
32 | * ┗━┓ ┏━┛
33 | * ┃ ┃神兽保佑, 永无BUG!
34 | * ┃ ┃Code is far away from bug with the animal protecting
35 | * ┃ ┗━━━┓
36 | * ┃ ┣┓
37 | * ┃ ┏┛
38 | * ┗┓┓┏━┳┓┏┛
39 | * ┃┫┫ ┃┫┫
40 | * ┗┻┛ ┗┻┛
41 | * ━━━━━━感觉萌萌哒━━━━━━
42 | * Summary: 客户端负责连接服务端发送数据报文到服务端
43 | * Author : anduo@qq.com
44 | * Version: 1.0
45 | * Date : 15/7/5
46 | * time : 17:37
47 | */
48 | public class FileMsgSender {
49 | private final static Logger LOGGER = LoggerFactory.getLogger(FileMsgSender.class);
50 |
51 | private final String zkNode;
52 |
53 | private final ZKClient zkClient;
54 |
55 | private volatile Channel channel;
56 |
57 | protected final Bootstrap bootstrap;
58 |
59 | private volatile boolean closed = false;
60 |
61 | private static final EventLoopGroup GROUP = new NioEventLoopGroup(1);
62 |
63 | public FileMsgSender(String zkAddrs, String zkNode) {
64 | this.zkNode = zkNode;
65 | this.zkClient = ZKClientCache.get(zkAddrs);
66 | this.bootstrap = new Bootstrap();
67 | bootstrap.group(GROUP);
68 | bootstrap.option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT);
69 | bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
70 | bootstrap.option(ChannelOption.TCP_NODELAY, true);
71 | bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
72 | bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000);
73 | bootstrap.channel(NioSocketChannel.class);
74 | bootstrap.handler(new FileMsgSendInitializer());
75 |
76 | }
77 |
78 | /**
79 | * 传输文件
80 | * @param msg
81 | */
82 | public void send(FileMsg msg) {
83 | if (isActive()) {
84 | LOGGER.error("sender is not active");
85 | return;
86 | }
87 | LOGGER.info("send msg to server");
88 | channel.writeAndFlush(msg);
89 | }
90 |
91 | public boolean isActive() {
92 | return channel != null && !closed && channel.isActive();
93 | }
94 |
95 | public void close() {
96 | this.closed = true;
97 | if (this.channel != null) {
98 | this.channel.close();
99 | }
100 | }
101 |
102 | public void destroy()
103 | throws Exception {
104 | close();
105 | bootstrap.group().shutdownGracefully();
106 | }
107 |
108 | public void connect()
109 | throws Exception {
110 | String clientAddr = zkClient.getPathValue(ZKPaths.makePath(Constants.NODE_ROOT, zkNode));
111 | bootstrap.connect(NetUtil.createSocketAddress(clientAddr));
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/core/FileMsgServer.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.core;
4 |
5 | import com.anduo.filesync.common.Constants;
6 | import com.anduo.filesync.util.NetUtil;
7 | import com.anduo.filesync.zk.ChangedEvent;
8 | import com.anduo.filesync.zk.ZKClient;
9 | import com.anduo.filesync.zk.ZKClientCache;
10 | import com.google.common.collect.ImmutableSet;
11 | import com.google.common.collect.Maps;
12 | import com.google.common.collect.Sets;
13 | import io.netty.bootstrap.ServerBootstrap;
14 | import io.netty.channel.nio.NioEventLoopGroup;
15 | import io.netty.channel.socket.nio.NioServerSocketChannel;
16 | import io.netty.handler.logging.LogLevel;
17 | import io.netty.handler.logging.LoggingHandler;
18 | import org.apache.commons.lang3.RandomUtils;
19 | import org.apache.curator.utils.ZKPaths;
20 | import org.slf4j.Logger;
21 | import org.slf4j.LoggerFactory;
22 |
23 | import java.io.File;
24 | import java.io.FileWriter;
25 | import java.io.IOException;
26 | import java.io.PrintWriter;
27 | import java.util.Map;
28 | import java.util.Set;
29 | import java.util.concurrent.ExecutorService;
30 | import java.util.concurrent.Executors;
31 |
32 | /**
33 | * ━━━━━━神兽出没━━━━━━
34 | * ┏┓ ┏┓
35 | * ┏┛┻━━━┛┻┓
36 | * ┃ ┃
37 | * ┃ ━ ┃
38 | * ┃ ┳┛ ┗┳ ┃
39 | * ┃ ┃
40 | * ┃ ┻ ┃
41 | * ┃ ┃
42 | * ┗━┓ ┏━┛
43 | * ┃ ┃神兽保佑, 永无BUG!
44 | * ┃ ┃Code is far away from bug with the animal protecting
45 | * ┃ ┗━━━┓
46 | * ┃ ┣┓
47 | * ┃ ┏┛
48 | * ┗┓┓┏━┳┓┏┛
49 | * ┃┫┫ ┃┫┫
50 | * ┗┻┛ ┗┻┛
51 | * ━━━━━━感觉萌萌哒━━━━━━
52 | * Summary: 服务端负责启动服务并且监听node节点的server,如果节点的id大于自己的id就建立一个client,并传输文件
53 | * Author : anduo@qq.com
54 | * Version: 1.0
55 | * Date : 15/7/5
56 | * time : 16:59
57 | */
58 | public class FileMsgServer {
59 |
60 | private static final Logger LOGGER = LoggerFactory.getLogger(FileMsgServer.class);
61 | static final int PORT = Integer.parseInt(System.getProperty("port", "1843"));
62 | private final ServerBootstrap bootstrap;
63 | private final String serverName;
64 | //NettyServer绑定端口号
65 | private final int bindPort;
66 | private final String zkAddrs;
67 | private final ZKClient zkClient;
68 | //当前服务所注册的zk节点名
69 | private volatile String zkNode;
70 | private Set lastNodes = Sets.newHashSet();
71 | Map clientMap = Maps.newConcurrentMap();
72 |
73 | //数据发送并发控制
74 | private final ExecutorService senderThreadPool;
75 |
76 | public FileMsgServer(String zkAddrs, String serverName, int bindPort) {
77 | this.zkAddrs = zkAddrs;
78 | this.zkClient = ZKClientCache.get(zkAddrs);
79 | this.serverName = serverName;
80 | this.bindPort = bindPort;
81 | this.senderThreadPool = Executors
82 | .newFixedThreadPool(5, runnable -> new Thread(runnable, serverName + "-send-thread"));
83 | NioEventLoopGroup boss = new NioEventLoopGroup(1);
84 | NioEventLoopGroup worker = new NioEventLoopGroup();
85 | this.bootstrap = new ServerBootstrap().group(boss, worker);
86 | this.bootstrap.channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.DEBUG));
87 | this.bootstrap.childHandler(new FileRecvInitializer());
88 | }
89 |
90 | public void start()
91 | throws InterruptedException {
92 | bootstrap.bind(bindPort).addListener(future -> register()).addListener(future -> initLocalFiles())
93 | .addListener(future -> addNodeWatchListenner()).sync().channel().closeFuture().sync();
94 | }
95 |
96 | //注册节点到zk
97 | private void register() {
98 | try {
99 | if (!zkClient.checkExist(Constants.NODE_ROOT)) {
100 | zkClient.addPersistentNode(Constants.NODE_ROOT);
101 | }
102 | String serverAddr = NetUtil.getLocalAddress().getHostAddress() + ":" + bindPort;
103 | String node = ZKPaths.makePath(Constants.NODE_ROOT, serverName);
104 | if (zkClient.checkExist(node)) {
105 | try {
106 | zkClient.deletePath(node);
107 | } catch (Exception e) {
108 | LOGGER.error("删除节点{}失败", node);
109 | }
110 | }
111 | //注册节点,并将节点的服务地址写入节点数据
112 | zkClient.addEphemeralNodeData(node, serverAddr);
113 | if (LOGGER.isDebugEnabled()) {
114 | String pathValue = zkClient.getPathValue(node);
115 | LOGGER.debug("ZK _node {} , value {}", node, pathValue);
116 | }
117 | this.zkNode = node;
118 | this.lastNodes.add(serverName);
119 | LOGGER.info("ZK 注册成功, _node {}", node);
120 | } catch (Exception e) {
121 | LOGGER.error("注册服务失败", e);
122 | }
123 | }
124 |
125 | private void initLocalFiles()
126 | throws IOException {
127 | LOGGER.info("{}开始生成随机文件", serverName);
128 | //随机在data目录下生成100个随机文本文件,内容长度随机控制在10K到10M,内容最后都为You are Best! 这些是待发送文件
129 | String dir = Constants.DEFAULT_DATA_FILE_PATH + "/source/" + serverName;
130 |
131 | ExecutorService threadPool = Executors.newFixedThreadPool(5);
132 | for (int i = 0; i < Constants.RANDOM_FILE_COUNT; i++) {
133 | final String fileName = dir + "/data-" + i + ".txt";
134 | createRandomFile(fileName);
135 | Runnable task = () -> {
136 | try {
137 | createRandomFile(fileName);
138 | } catch (IOException e) {
139 | e.printStackTrace();
140 | }
141 | };
142 | threadPool.submit(task);
143 | }
144 | threadPool.shutdown();
145 | LOGGER.info("{}生成随机文件结束,路径{}", serverName, dir);
146 | }
147 |
148 | private void createRandomFile(String filePath)
149 | throws IOException {
150 | String lastStr = "You are Best!";
151 | //自己补全字母和数字,这个字符数是作为随机取值的源
152 | String str = "012345678vasdjhklsadfqwiurewopt";
153 | File distFile = new File(filePath);
154 | if (!distFile.getParentFile().exists()) { distFile.getParentFile().mkdirs(); }
155 | PrintWriter pw = new PrintWriter(new FileWriter(filePath));
156 | int len = str.length();
157 | int size = RandomUtils.nextInt(1, 2);
158 | //每次写入10K,写入1024次就是 10M
159 | for (int i = 0; i < size; i++) {
160 | StringBuilder s = new StringBuilder();
161 | for (int j = 0; j < 10240; j++) {
162 | s.append(str.charAt((int) (Math.random() * len)));
163 | }
164 | pw.println(s.toString());
165 | }
166 |
167 | pw.write(lastStr);
168 | pw.close();
169 | }
170 |
171 | /***
172 | * 监听节点
173 | */
174 | private void addNodeWatchListenner() {
175 | try {
176 | zkClient.listenChildrenPath(Constants.NODE_ROOT, (sender, event) -> {
177 | ImmutableSet diffNodeServers = getDiffNodes();
178 | if (event.getType().equals(ChangedEvent.Type.CHILD_ADDED)) {
179 | LOGGER.info("{}监听到有新节点添加进来了!", serverName);
180 | sendFileMsgs(diffNodeServers);
181 | }
182 | }, true);
183 | } catch (Exception e) {
184 | LOGGER.error("{}添加监听器失败", serverName);
185 | }
186 | }
187 |
188 | private void sendFileMsgs(ImmutableSet diffNodes)
189 | throws Exception {
190 | for (String _node : diffNodes) {
191 | try {
192 | int currentNodeId = Integer.parseInt(serverName.split("-")[1]);
193 | int diffNodeId = Integer.parseInt(_node.split("-")[1]);
194 | if (currentNodeId > diffNodeId) {
195 | LOGGER.info("当前节点{}大于新添加的节点{},尝试连接!", serverName, _node);
196 | FileMsgSender sender = new FileMsgSender(zkAddrs, _node);
197 | }
198 | } catch (Exception e) {
199 | LOGGER.error("发送数据失败!");
200 | }
201 | }
202 | }
203 |
204 | private ImmutableSet getDiffNodes()
205 | throws Exception {
206 | Set currentNodes = Sets.newHashSet(zkClient.getChildren(Constants.NODE_ROOT));
207 | ImmutableSet diffNodes = Sets.difference(currentNodes, lastNodes).immutableCopy();
208 | lastNodes = currentNodes;
209 | return diffNodes;
210 | }
211 |
212 | public void destroy()
213 | throws Exception {
214 | if (zkNode != null) {
215 | zkClient.deletePath(zkNode);
216 | }
217 | Set clientNodes = clientMap.keySet();
218 | for (String clientNode : clientNodes) {
219 | clientMap.get(clientNode).destroy();
220 | clientMap.remove(clientNode);
221 | }
222 | senderThreadPool.shutdown();
223 | bootstrap.group().shutdownGracefully();
224 | bootstrap.childGroup().shutdownGracefully();
225 | }
226 |
227 | public static void main(String[] args)
228 | throws InterruptedException {
229 | LOGGER.info("Server set up on port: {}", PORT);
230 | new FileMsgServer("127.0.0.1:2181", "server-1", 8411).start();
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/core/FileRecvInitializer.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.core;
4 |
5 | import com.anduo.filesync.codec.FileMsgDecoder;
6 | import com.anduo.filesync.handler.FileMsgRecvHandler;
7 | import io.netty.channel.ChannelInitializer;
8 | import io.netty.channel.ChannelPipeline;
9 | import io.netty.channel.socket.SocketChannel;
10 | import io.netty.handler.stream.ChunkedWriteHandler;
11 | import io.netty.handler.timeout.IdleStateHandler;
12 |
13 | /**
14 | * ━━━━━━神兽出没━━━━━━
15 | * ┏┓ ┏┓
16 | * ┏┛┻━━━┛┻┓
17 | * ┃ ┃
18 | * ┃ ━ ┃
19 | * ┃ ┳┛ ┗┳ ┃
20 | * ┃ ┃
21 | * ┃ ┻ ┃
22 | * ┃ ┃
23 | * ┗━┓ ┏━┛
24 | * ┃ ┃神兽保佑, 永无BUG!
25 | * ┃ ┃Code is far away from bug with the animal protecting
26 | * ┃ ┗━━━┓
27 | * ┃ ┣┓
28 | * ┃ ┏┛
29 | * ┗┓┓┏━┳┓┏┛
30 | * ┃┫┫ ┃┫┫
31 | * ┗┻┛ ┗┻┛
32 | * ━━━━━━感觉萌萌哒━━━━━━
33 | * Summary: FileServerInitializer
34 | * Author : anduo@qq.com
35 | * Version: 1.0
36 | * Date : 15/7/5
37 | * time : 16:56
38 | */
39 | public class FileRecvInitializer extends ChannelInitializer {
40 |
41 | @Override
42 | public void initChannel(SocketChannel ch)
43 | throws Exception {
44 | // Create a default pipeline implementation.
45 | ChannelPipeline pipeline = ch.pipeline();
46 | pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
47 | pipeline.addLast("codec", new FileMsgDecoder());//解码
48 | pipeline.addLast("idle", new IdleStateHandler(3, 0, 0));//心跳
49 | pipeline.addLast("handler", new FileMsgRecvHandler());//recive file msg
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/core/SynServer.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.core;
4 |
5 | import com.anduo.filesync.common.Constants;
6 | import com.anduo.filesync.util.Threads;
7 | import com.anduo.filesync.zk.ZKClient;
8 | import com.anduo.filesync.zk.ZKClientCache;
9 | import com.google.common.base.Splitter;
10 | import com.google.common.collect.Maps;
11 | import org.apache.commons.lang3.StringUtils;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 | import org.springframework.beans.factory.DisposableBean;
15 | import org.springframework.beans.factory.InitializingBean;
16 | import org.springframework.beans.factory.annotation.Value;
17 | import org.springframework.stereotype.Component;
18 |
19 | import java.util.Map;
20 | import java.util.concurrent.TimeUnit;
21 |
22 | /**
23 | * ━━━━━━神兽出没━━━━━━
24 | * ┏┓ ┏┓
25 | * ┏┛┻━━━┛┻┓
26 | * ┃ ┃
27 | * ┃ ━ ┃
28 | * ┃ ┳┛ ┗┳ ┃
29 | * ┃ ┃
30 | * ┃ ┻ ┃
31 | * ┃ ┃
32 | * ┗━┓ ┏━┛
33 | * ┃ ┃神兽保佑, 永无BUG!
34 | * ┃ ┃Code is far away from bug with the animal protecting
35 | * ┃ ┗━━━┓
36 | * ┃ ┣┓
37 | * ┃ ┏┛
38 | * ┗┓┓┏━┳┓┏┛
39 | * ┃┫┫ ┃┫┫
40 | * ┗┻┛ ┗┻┛
41 | * ━━━━━━感觉萌萌哒━━━━━━
42 | * Summary: 服务启动器
43 | * Author : anduo@qq.com
44 | * Version: 1.0
45 | * Date : 15/7/4
46 | * time : 01:47
47 | */
48 | @Component
49 | public class SynServer implements DisposableBean, InitializingBean {
50 |
51 | private static final Logger LOGGER = LoggerFactory.getLogger(SynServer.class);
52 |
53 | @Value("${zk.config.nodes.path}")
54 | private String zkCfgNodesPath;
55 | @Value("${zk.config.commoncfg.path}")
56 | private String zkCfgCommoncfgPath;
57 | @Value("${zk.servers}")
58 | private String zkAddrs;
59 | private Map serverNodeMap = Maps.newConcurrentMap();
60 |
61 | /**
62 | * 容器销毁的时候做相关线程和进程的清理工作
63 | *
64 | * @throws Exception
65 | */
66 | @Override
67 | public void destroy()
68 | throws Exception {
69 | for (String server : serverNodeMap.keySet()) {
70 | serverNodeMap.get(server).destroy();
71 | }
72 | ZKClientCache.get(zkAddrs).close();
73 | }
74 |
75 | /**
76 | * 当spring容器加载完毕之后执行以下动作
77 | * @throws Exception
78 | */
79 | @Override
80 | public void afterPropertiesSet()
81 | throws Exception {
82 | //开始启动服务
83 | //1、从zk nodes配置文件的路径拿到相关配置信息
84 | Map serversCfg = getNodesCfg();
85 | if (serversCfg == null) { return; }
86 | for (String serverNode : serversCfg.keySet()) {
87 | Integer bindPort = Integer.parseInt(serversCfg.get(serverNode));
88 |
89 | FileMsgServer server = new FileMsgServer(zkAddrs, serverNode, bindPort);
90 | server.start();
91 | serverNodeMap.put(serverNode, server);
92 | //暂停10s再启动下一台机器
93 | Threads.sleep(1, TimeUnit.SECONDS);
94 | }
95 | //强行下线测试
96 | serverNodeMap.get("Leader-3").destroy();
97 | serverNodeMap.remove("Leader-3");
98 | }
99 |
100 | private Map getNodesCfg()
101 | throws Exception {
102 | ZKClient zkClient = ZKClientCache.get(zkAddrs);
103 | if (!zkClient.checkExist(zkCfgNodesPath)) {
104 | return null;
105 | }
106 | LOGGER.info("开始启动服务");
107 | String pathValue = zkClient.getPathValue(zkCfgNodesPath);
108 | if (StringUtils.isBlank(pathValue)) {
109 | return null;
110 | }
111 | //删除之前的节点注册信息
112 | if (zkClient.checkExist(Constants.NODE_ROOT)) {
113 | zkClient.deletAllPath(Constants.NODE_ROOT);
114 | }
115 | return Splitter.on(",").withKeyValueSeparator("=").split(StringUtils.remove(pathValue, " "));
116 | }
117 | }
118 |
119 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/handler/FileMsgRecvHandler.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.handler;
4 |
5 | import com.anduo.filesync.msg.FileMsg;
6 | import com.anduo.filesync.util.CleanUpUtil;
7 | import io.netty.channel.*;
8 | import io.netty.handler.timeout.IdleState;
9 | import io.netty.handler.timeout.IdleStateEvent;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import java.net.InetAddress;
14 |
15 | /**
16 | * ━━━━━━神兽出没━━━━━━
17 | * ┏┓ ┏┓
18 | * ┏┛┻━━━┛┻┓
19 | * ┃ ┃
20 | * ┃ ━ ┃
21 | * ┃ ┳┛ ┗┳ ┃
22 | * ┃ ┃
23 | * ┃ ┻ ┃
24 | * ┃ ┃
25 | * ┗━┓ ┏━┛
26 | * ┃ ┃神兽保佑, 永无BUG!
27 | * ┃ ┃Code is far away from bug with the animal protecting
28 | * ┃ ┗━━━┓
29 | * ┃ ┣┓
30 | * ┃ ┏┛
31 | * ┗┓┓┏━┳┓┏┛
32 | * ┃┫┫ ┃┫┫
33 | * ┗┻┛ ┗┻┛
34 | * ━━━━━━感觉萌萌哒━━━━━━
35 | * Summary: 文件接收
36 | * Author : anduo@qq.com
37 | * Version: 1.0
38 | * Date : 15/7/5
39 | * time : 16:55
40 | */
41 | public class FileMsgRecvHandler extends SimpleChannelInboundHandler {
42 |
43 | private static final Logger LOGGER = LoggerFactory.getLogger(FileMsgRecvHandler.class);
44 |
45 | @Override
46 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
47 | throws Exception {
48 | if (evt instanceof IdleStateEvent) {
49 | IdleStateEvent state = (IdleStateEvent) evt;
50 | LOGGER.info("Closing timeout connection : {}", ctx.channel().remoteAddress());
51 | if (state.state() == IdleState.READER_IDLE) {
52 | CleanUpUtil.closeOnFlush(ctx.channel());
53 | }
54 | }
55 | super.userEventTriggered(ctx, evt);
56 | }
57 |
58 | /**
59 | * 收到文件消息
60 | *
61 | * @param ctx
62 | * @param msg
63 | * @throws Exception
64 | */
65 | @Override
66 | protected void channelRead0(ChannelHandlerContext ctx, FileMsg msg)
67 | throws Exception {
68 | try {
69 |
70 | } catch (Exception e) {
71 | CleanUpUtil.closeOnFlush(ctx.channel());
72 | CleanUpUtil.closeOnFlush(ctx.channel().parent());
73 | }
74 | }
75 |
76 | /***
77 | * 覆盖 channelActive 方法 在channel被启用的时候触发 (在建立连接的时候)
78 | * channelActive 和 channelInActive 在后面的内容中讲述,这里先不做详细的描述
79 | *
80 | * @param ctx
81 | * @throws Exception
82 | */
83 | @Override
84 | public void channelActive(ChannelHandlerContext ctx)
85 | throws Exception {
86 | LOGGER.info("RamoteAddress : " + ctx.channel().remoteAddress() + " active !");
87 | ctx.writeAndFlush("Welcome to " + InetAddress.getLocalHost().getHostName() + " service!\n");
88 | super.channelActive(ctx);
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/handler/FileMsgSendHandler.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.handler;
4 |
5 | import io.netty.buffer.ByteBuf;
6 | import io.netty.channel.*;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | /**
11 | * ━━━━━━神兽出没━━━━━━
12 | * ┏┓ ┏┓
13 | * ┏┛┻━━━┛┻┓
14 | * ┃ ┃
15 | * ┃ ━ ┃
16 | * ┃ ┳┛ ┗┳ ┃
17 | * ┃ ┃
18 | * ┃ ┻ ┃
19 | * ┃ ┃
20 | * ┗━┓ ┏━┛
21 | * ┃ ┃神兽保佑, 永无BUG!
22 | * ┃ ┃Code is far away from bug with the animal protecting
23 | * ┃ ┗━━━┓
24 | * ┃ ┣┓
25 | * ┃ ┏┛
26 | * ┗┓┓┏━┳┓┏┛
27 | * ┃┫┫ ┃┫┫
28 | * ┗┻┛ ┗┻┛
29 | * ━━━━━━感觉萌萌哒━━━━━━
30 | * Summary: 文件接收方,处理器
31 | * Author : anduo@qq.com
32 | * Version: 1.0
33 | * Date : 15/7/5
34 | * time : 17:15
35 | */
36 | public class FileMsgSendHandler extends ChannelOutboundHandlerAdapter {
37 |
38 | private static final Logger LOGGER = LoggerFactory.getLogger(FileMsgSendHandler.class);
39 |
40 |
41 | @Override
42 | public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
43 | throws Exception {
44 | LOGGER.info("发送文件啦");
45 | ByteBuf buf = ctx.alloc().buffer();
46 | ctx.writeAndFlush(buf, promise);
47 | }
48 |
49 | @Override
50 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
51 | cause.printStackTrace();
52 | ctx.close();
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/msg/FileMsg.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.msg;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * ━━━━━━神兽出没━━━━━━
9 | * ┏┓ ┏┓
10 | * ┏┛┻━━━┛┻┓
11 | * ┃ ┃
12 | * ┃ ━ ┃
13 | * ┃ ┳┛ ┗┳ ┃
14 | * ┃ ┃
15 | * ┃ ┻ ┃
16 | * ┃ ┃
17 | * ┗━┓ ┏━┛
18 | * ┃ ┃神兽保佑, 永无BUG!
19 | * ┃ ┃Code is far away from bug with the animal protecting
20 | * ┃ ┗━━━┓
21 | * ┃ ┣┓
22 | * ┃ ┏┛
23 | * ┗┓┓┏━┳┓┏┛
24 | * ┃┫┫ ┃┫┫
25 | * ┗┻┛ ┗┻┛
26 | * ━━━━━━感觉萌萌哒━━━━━━
27 | * Summary: 文件传输对象
28 | * Author : anduo@qq.com
29 | * Version: 1.0
30 | * Date : 15/7/5
31 | * time : 17:20
32 | */
33 | public class FileMsg implements Serializable {
34 | private static final long serialVersionUID = 8953150675564212795L;
35 | /**
36 | * 总包数.
37 | */
38 | private long sumCountPackage;
39 | /**
40 | * 当前包数.
41 | */
42 | private long countPackage;
43 | /**
44 | * 文件名
45 | */
46 | private String fileName;
47 | /**
48 | * 文件来源数据节点
49 | */
50 | private String srcNode;
51 | /**
52 | * 文件md5值,防止文件在网路传输过程中对包
53 | */
54 | private String fileMd5;//
55 | /**
56 | * 文件内容字节数组
57 | */
58 | private byte[] bytes;//
59 |
60 | /**
61 | * @return the sumCountPackage
62 | */
63 | public long getSumCountPackage() {
64 | return sumCountPackage;
65 | }
66 |
67 | /**
68 | * @param sumCountPackage the sumCountPackage to set
69 | */
70 | public void setSumCountPackage(long sumCountPackage) {
71 | this.sumCountPackage = sumCountPackage;
72 | }
73 |
74 | /**
75 | * @return the countPackage
76 | */
77 | public long getCountPackage() {
78 | return countPackage;
79 | }
80 |
81 | public void setCountPackage(long countPackage) {
82 | this.countPackage = countPackage;
83 | }
84 |
85 | public byte[] getBytes() {
86 | return bytes;
87 | }
88 |
89 | public void setBytes(byte[] bytes) {
90 | this.bytes = bytes;
91 | }
92 |
93 | public String getFileName() {
94 | return fileName;
95 | }
96 |
97 | public void setFileName(String fileName) {
98 | this.fileName = fileName;
99 | }
100 |
101 | public String getSrcNode() {
102 | return srcNode;
103 | }
104 |
105 | public void setSrcNode(String srcNode) {
106 | this.srcNode = srcNode;
107 | }
108 |
109 | public String getFileMd5() {
110 | return fileMd5;
111 | }
112 |
113 | public void setFileMd5(String fileMd5) {
114 | this.fileMd5 = fileMd5;
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/msg/MsgType.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 meituan
2 | // All rights reserved
3 | package com.anduo.filesync.msg;
4 |
5 | /**
6 | * ━━━━━━神兽出没━━━━━━
7 | * ┏┓ ┏┓
8 | * ┏┛┻━━━┛┻┓
9 | * ┃ ┃
10 | * ┃ ━ ┃
11 | * ┃ ┳┛ ┗┳ ┃
12 | * ┃ ┃
13 | * ┃ ┻ ┃
14 | * ┃ ┃
15 | * ┗━┓ ┏━┛
16 | * ┃ ┃神兽保佑, 永无BUG!
17 | * ┃ ┃Code is far away from bug with the animal protecting
18 | * ┃ ┗━━━┓
19 | * ┃ ┣┓
20 | * ┃ ┏┛
21 | * ┗┓┓┏━┳┓┏┛
22 | * ┃┫┫ ┃┫┫
23 | * ┗┻┛ ┗┻┛
24 | * ━━━━━━感觉萌萌哒━━━━━━
25 | * Summary: msg的类型,目的是为了在传输过程中对文件进行相应的业务处理
26 | * Author : anduo@meituan.com
27 | * Version: 1.0
28 | * Date : 15/7/5
29 | * time : 22:34
30 | */
31 | public class MsgType {
32 | public static final byte HEADER = 0x01;
33 | public static final byte BODY = 0x02;
34 | public static final byte TAILER = 0x03;
35 | public static final byte COMMAND = 0x04;
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/util/CleanUpUtil.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.util;
4 |
5 | import com.anduo.filesync.core.FileMsgServer;
6 | import io.netty.buffer.Unpooled;
7 | import io.netty.channel.Channel;
8 | import io.netty.channel.ChannelFutureListener;
9 |
10 | import java.io.Closeable;
11 | import java.io.File;
12 | import java.io.IOException;
13 |
14 | /**
15 | * ━━━━━━神兽出没━━━━━━
16 | * ┏┓ ┏┓
17 | * ┏┛┻━━━┛┻┓
18 | * ┃ ┃
19 | * ┃ ━ ┃
20 | * ┃ ┳┛ ┗┳ ┃
21 | * ┃ ┃
22 | * ┃ ┻ ┃
23 | * ┃ ┃
24 | * ┗━┓ ┏━┛
25 | * ┃ ┃神兽保佑, 永无BUG!
26 | * ┃ ┃Code is far away from bug with the animal protecting
27 | * ┃ ┗━━━┓
28 | * ┃ ┣┓
29 | * ┃ ┏┛
30 | * ┗┓┓┏━┳┓┏┛
31 | * ┃┫┫ ┃┫┫
32 | * ┗┻┛ ┗┻┛
33 | * ━━━━━━感觉萌萌哒━━━━━━
34 | * Summary: TODO 描述信息
35 | * Author : anduo@qq.com
36 | * Version: 1.0
37 | * Date : 15/7/5
38 | * time : 17:00
39 | */
40 | public class CleanUpUtil {
41 |
42 | public static void closeOnFlush(Channel ch) {
43 | if (ch.isActive()) {
44 | ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
45 | }
46 | }
47 |
48 | public static void closeQuietly(Closeable c) {
49 | try {
50 | if (c != null)
51 | c.close();
52 | } catch (IOException ignored) {
53 | }
54 | }
55 |
56 | public static boolean deleteFile(String fileName) {
57 | File file = new File(FileMsgServer.POLICY_FILE);
58 | return file.exists() && file.delete();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/util/NetUtil.java:
--------------------------------------------------------------------------------
1 | package com.anduo.filesync.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.net.InetAddress;
7 | import java.net.InetSocketAddress;
8 | import java.net.NetworkInterface;
9 | import java.net.SocketAddress;
10 | import java.util.Enumeration;
11 | import java.util.regex.Pattern;
12 |
13 | /**
14 | * Date: 12/1/14
15 | * Time: 7:18 PM
16 | */
17 | public class NetUtil {
18 |
19 | private static final Logger LOGGER = LoggerFactory.getLogger(NetUtil.class);
20 |
21 | private static volatile InetAddress LOCAL_ADDRESS = null;
22 |
23 | public static InetAddress getLocalAddress() {
24 | if (LOCAL_ADDRESS != null) { return LOCAL_ADDRESS; }
25 | InetAddress localAddress = getLocalAddress0();
26 | LOCAL_ADDRESS = localAddress;
27 | return localAddress;
28 | }
29 |
30 | private static InetAddress getLocalAddress0() {
31 | InetAddress localAddress = null;
32 | try {
33 | localAddress = InetAddress.getLocalHost();
34 | if (isValidAddress(localAddress)) {
35 | return localAddress;
36 | }
37 | } catch (Throwable e) {
38 | LOGGER.warn("Failed to retriving ip address, " + e.getMessage(), e);
39 | }
40 | try {
41 | Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
42 | if (interfaces != null) {
43 | while (interfaces.hasMoreElements()) {
44 | try {
45 | NetworkInterface network = interfaces.nextElement();
46 | Enumeration addresses = network.getInetAddresses();
47 | if (addresses != null) {
48 | while (addresses.hasMoreElements()) {
49 | try {
50 | InetAddress address = addresses.nextElement();
51 | if (isValidAddress(address)) {
52 | return address;
53 | }
54 | } catch (Throwable e) {
55 | LOGGER.warn("Failed to retriving ip address, " + e.getMessage(), e);
56 | }
57 | }
58 | }
59 | } catch (Throwable e) {
60 | LOGGER.warn("Failed to retriving ip address, " + e.getMessage(), e);
61 | }
62 | }
63 | }
64 | } catch (Throwable e) {
65 | LOGGER.warn("Failed to retriving ip address, " + e.getMessage(), e);
66 | }
67 | LOGGER.error("Could not get local host ip address, will use 127.0.0.1 instead.");
68 | return localAddress;
69 | }
70 |
71 | private static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$");
72 |
73 | private static boolean isValidAddress(InetAddress address) {
74 | if (address == null || address.isLoopbackAddress()) { return false; }
75 | String name = address.getHostAddress();
76 | return (name != null && !ANYHOST.equals(name) && !LOCALHOST.equals(name) && IP_PATTERN.matcher(name).matches());
77 | }
78 |
79 | public static final String LOCALHOST = "127.0.0.1";
80 |
81 | public static final String ANYHOST = "0.0.0.0";
82 |
83 | public static SocketAddress createSocketAddress(String server) {
84 | String[] serverSplit = server.split(":");
85 | String hostname = serverSplit[0];
86 | int port = Integer.parseInt(serverSplit[1]);
87 | return new InetSocketAddress(hostname, port);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/util/PropertiesLoader.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.util;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.io.InputStreamReader;
12 | import java.util.Properties;
13 |
14 | /**
15 | * ━━━━━━神兽出没━━━━━━
16 | * ┏┓ ┏┓
17 | * ┏┛┻━━━┛┻┓
18 | * ┃ ┃
19 | * ┃ ━ ┃
20 | * ┃ ┳┛ ┗┳ ┃
21 | * ┃ ┃
22 | * ┃ ┻ ┃
23 | * ┃ ┃
24 | * ┗━┓ ┏━┛
25 | * ┃ ┃神兽保佑, 永无BUG!
26 | * ┃ ┃Code is far away from bug with the animal protecting
27 | * ┃ ┗━━━┓
28 | * ┃ ┣┓
29 | * ┃ ┏┛
30 | * ┗┓┓┏━┳┓┏┛
31 | * ┃┫┫ ┃┫┫
32 | * ┗┻┛ ┗┻┛
33 | * ━━━━━━感觉萌萌哒━━━━━━
34 | * Summary: TODO 描述信息
35 | * Author : anduo@qq.com
36 | * Version: 1.0
37 | * Date : 15/7/4
38 | * time : 00:50
39 | */
40 | public class PropertiesLoader {
41 |
42 | private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesLoader.class);
43 |
44 | public static Properties load(String fileName) {
45 | return load(fileName, null);
46 | }
47 |
48 | public static Properties load(String fileName, Properties parent) {
49 |
50 | InputStream is = PropertiesLoader.class.getClassLoader().getResourceAsStream(fileName);
51 | if (is == null) { return null; }
52 |
53 | try {
54 | BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
55 | Properties prop = new Properties(parent);
56 | prop.load(reader);
57 | return prop;
58 | } catch (IOException e) {
59 | throw new RuntimeException(e);
60 | } finally {
61 | try {
62 | if (is != null) { is.close(); }
63 | } catch (IOException e) {
64 | LOGGER.warn("资源关闭时出错");
65 | }
66 | }
67 |
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/util/Threads.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.filesync.util;
4 |
5 | import java.util.concurrent.TimeUnit;
6 |
7 | /**
8 | * ━━━━━━神兽出没━━━━━━
9 | * ┏┓ ┏┓
10 | * ┏┛┻━━━┛┻┓
11 | * ┃ ┃
12 | * ┃ ━ ┃
13 | * ┃ ┳┛ ┗┳ ┃
14 | * ┃ ┃
15 | * ┃ ┻ ┃
16 | * ┃ ┃
17 | * ┗━┓ ┏━┛
18 | * ┃ ┃神兽保佑, 永无BUG!
19 | * ┃ ┃Code is far away from bug with the animal protecting
20 | * ┃ ┗━━━┓
21 | * ┃ ┣┓
22 | * ┃ ┏┛
23 | * ┗┓┓┏━┳┓┏┛
24 | * ┃┫┫ ┃┫┫
25 | * ┗┻┛ ┗┻┛
26 | * ━━━━━━感觉萌萌哒━━━━━━
27 | * Summary: 线程工具类
28 | * Author : anduo@qq.com
29 | * Version: 1.0
30 | * Date : 15/7/4
31 | * time : 02:56
32 | */
33 | public class Threads {
34 |
35 | /**
36 | * sleep等待,单位为毫秒,忽略InterruptedException.
37 | */
38 | public static void sleep(long millis) {
39 | try {
40 | Thread.sleep(millis);
41 | } catch (InterruptedException e) {
42 | // Ignore.
43 | return;
44 | }
45 | }
46 |
47 | /**
48 | * sleep等待,忽略InterruptedException.
49 | */
50 | public static void sleep(long duration, TimeUnit unit) {
51 | try {
52 | Thread.sleep(unit.toMillis(duration));
53 | } catch (InterruptedException e) {
54 | // Ignore.
55 | return;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/zk/ChangedEvent.java:
--------------------------------------------------------------------------------
1 | package com.anduo.filesync.zk;
2 |
3 | /**
4 | *
5 | */
6 | public class ChangedEvent {
7 | public enum Type {
8 | CHILD_ADDED,
9 | CHILD_UPDATED,
10 | CHILD_REMOVED
11 | }
12 |
13 | private String path;
14 | private Type type;
15 |
16 | public ChangedEvent(String path, Type type) {
17 | this.path = path;
18 | this.type = type;
19 | }
20 |
21 | public String getPath() {
22 | return this.path;
23 | }
24 |
25 | public Type getType() {
26 | return type;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/zk/ConnectionState.java:
--------------------------------------------------------------------------------
1 | package com.anduo.filesync.zk;
2 |
3 | /**
4 | *
5 | */
6 | public enum ConnectionState {
7 | CONNECTED, SUSPENDED, RECONNECTED, LOST, READ_ONLY
8 | }
9 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/zk/ConnectionStateListener.java:
--------------------------------------------------------------------------------
1 | package com.anduo.filesync.zk;
2 |
3 | /**
4 | *
5 | */
6 | public interface ConnectionStateListener {
7 | void stateChanged(ZKClient sender, ConnectionState state);
8 | }
9 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/zk/NodeListener.java:
--------------------------------------------------------------------------------
1 | package com.anduo.filesync.zk;
2 |
3 | /**
4 | *
5 | */
6 | public interface NodeListener {
7 | void nodeChanged(ZKClient sender, ChangedEvent event) throws Exception;
8 | }
9 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/zk/ZKClient.java:
--------------------------------------------------------------------------------
1 | package com.anduo.filesync.zk;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | *
7 | */
8 | public interface ZKClient {
9 |
10 | /**
11 | * 使用分布式锁执行任务
12 | *
13 | * @param path
14 | * @param getLockTimeout 获取锁超时时间(单位ms)
15 | * @param task
16 | * @auth anduo 2015年5月8日
17 | */
18 | public void distributeLock(String path, int getLockTimeout, Runnable task);
19 |
20 | /**
21 | * 获取给定路径的子节点
22 | *
23 | * @param path
24 | * @return
25 | * @throws Exception
26 | */
27 | List getChildren(String path)
28 | throws Exception;
29 |
30 | /**
31 | * 监听给定路径子节点变化,并且获取子节点集合
32 | *
33 | * @param parent 父路径
34 | * @param listener 监听器
35 | * @param sync 该方法是否同步获取子节点,如果为true,
36 | * 则方法返回的时候一定获得最新子节点集合
37 | * @return
38 | * @throws Exception
39 | */
40 | List listenChildrenPath(final String parent, final NodeListener listener, final boolean sync)
41 | throws Exception;
42 |
43 | /**
44 | * 在给定路径下添加临时子节点
45 | *
46 | * @param parent
47 | * @param node
48 | * @return
49 | * @throws Exception
50 | */
51 | String addEphemeralNode(String parent, String node)
52 | throws Exception;
53 |
54 | /**
55 | * 添加临时节点
56 | *
57 | * @param path 临时节点全路径
58 | * @return
59 | * @throws Exception
60 | */
61 | String addEphemeralNode(String path)
62 | throws Exception;
63 |
64 | /**
65 | * 添加永久节点
66 | *
67 | * @param path 永久节点全路径
68 | * @throws Exception
69 | */
70 | void addPersistentNode(String path)
71 | throws Exception;
72 |
73 | /**
74 | * 是否已经连接上
75 | *
76 | * @return
77 | */
78 | boolean isConnected();
79 |
80 | /**
81 | * 注册连接状态监听器
82 | *
83 | * @param listener
84 | */
85 | void addConnectionChangeListenter(final ConnectionStateListener listener);
86 |
87 | /**
88 | * 删除给定路径
89 | *
90 | * @param path
91 | * @throws Exception
92 | */
93 | void deletePath(String path)
94 | throws Exception;
95 |
96 | //递归删除所有节点
97 | void deletAllPath(String path)
98 | throws Exception;
99 |
100 | /**
101 | * 判断给定路径是否存在
102 | *
103 | * @param path
104 | * @return
105 | */
106 | boolean checkExist(String path);
107 |
108 | /**
109 | * 添加临时节点数据
110 | * @param path
111 | * @param data
112 | * @throws Exception
113 | */
114 | void addEphemeralNodeData(String path, String data)
115 | throws Exception;
116 |
117 | /**
118 | *
119 | * @param path
120 | * @param data
121 | */
122 | void createPath(String path, String data);
123 |
124 | public void updatePathValue(String path, String data);
125 |
126 | String getPathValue(String path)
127 | throws Exception;
128 |
129 | /**
130 | * 关闭
131 | */
132 | void close();
133 | }
134 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/zk/ZKClientCache.java:
--------------------------------------------------------------------------------
1 | package com.anduo.filesync.zk;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | /**
10 | *
11 | */
12 | public class ZKClientCache {
13 |
14 | private static final Logger LOGGER = LoggerFactory.getLogger(ZKClientCache.class);
15 |
16 | private static final Map CACHE = new HashMap();
17 |
18 | public synchronized static ZKClient get(String address) {
19 | LOGGER.info("Get zkclient for {}", address);
20 | ZKClientImpl client = CACHE.get(address);
21 | if (client == null) {
22 | CACHE.put(address, new ZKClientImpl(address));
23 | }
24 | client = CACHE.get(address);
25 | client.incrementReference();
26 | return client;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/nz-client/src/main/java/com/anduo/filesync/zk/ZKClientImpl.java:
--------------------------------------------------------------------------------
1 | package com.anduo.filesync.zk;
2 |
3 | import com.google.common.util.concurrent.MoreExecutors;
4 | import org.apache.curator.RetryPolicy;
5 | import org.apache.curator.framework.CuratorFramework;
6 | import org.apache.curator.framework.CuratorFrameworkFactory;
7 | import org.apache.curator.framework.recipes.cache.ChildData;
8 | import org.apache.curator.framework.recipes.cache.PathChildrenCache;
9 | import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
10 | import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
11 | import org.apache.curator.framework.recipes.locks.InterProcessMutex;
12 | import org.apache.curator.retry.ExponentialBackoffRetry;
13 | import org.apache.curator.utils.DebugUtils;
14 | import org.apache.curator.utils.ThreadUtils;
15 | import org.apache.curator.utils.ZKPaths;
16 | import org.apache.zookeeper.CreateMode;
17 | import org.apache.zookeeper.KeeperException;
18 | import org.apache.zookeeper.data.Stat;
19 | import org.slf4j.Logger;
20 | import org.slf4j.LoggerFactory;
21 |
22 | import javax.annotation.PreDestroy;
23 | import java.util.ArrayList;
24 | import java.util.List;
25 | import java.util.concurrent.CountDownLatch;
26 | import java.util.concurrent.ExecutorService;
27 | import java.util.concurrent.Executors;
28 | import java.util.concurrent.TimeUnit;
29 | import java.util.concurrent.atomic.AtomicInteger;
30 | import java.util.concurrent.locks.Lock;
31 | import java.util.concurrent.locks.ReentrantLock;
32 |
33 | /**
34 | *
35 | */
36 | class ZKClientImpl implements ZKClient {
37 |
38 | private static final Logger LOGGER = LoggerFactory.getLogger(ZKClientImpl.class);
39 |
40 | public static final int MAX_RETRIES = 3000;
41 | public static final int BASE_SLEEP_TIMEMS = 3000;
42 |
43 | private final CuratorFramework client;
44 | private final ExecutorService EVENT_THREAD_POOL = Executors
45 | .newFixedThreadPool(1, ThreadUtils.newThreadFactory("PathChildrenCache"));
46 | private final ExecutorService SAME_EXECUTOR = MoreExecutors.sameThreadExecutor();
47 | private final AtomicInteger REFERENCE_COUNT = new AtomicInteger(0);
48 |
49 | private Lock _lock = new ReentrantLock(true);
50 |
51 | public ZKClientImpl(String adds) {
52 | System.setProperty(DebugUtils.PROPERTY_DONT_LOG_CONNECTION_ISSUES, "false");
53 | RetryPolicy retryPolicy = new ExponentialBackoffRetry(BASE_SLEEP_TIMEMS, MAX_RETRIES);
54 | this.client = CuratorFrameworkFactory.builder().connectString(adds).retryPolicy(retryPolicy)
55 | .connectionTimeoutMs(5000).build();
56 | waitUntilZkStart();
57 |
58 | }
59 |
60 | private void waitUntilZkStart() {
61 | CountDownLatch latch = new CountDownLatch(1);
62 | addConnectionChangeListenter(new ConnectionWatcher(latch));
63 | client.start();
64 | try {
65 | latch.await();
66 | } catch (InterruptedException e) {
67 | LOGGER.error("start zk latch.await() error", e);
68 | Thread.currentThread().interrupt();
69 | }
70 | }
71 |
72 | /**
73 | * 使用分布式锁执行任务
74 | *
75 | * @param path
76 | * @param getLockTimeout 获取锁超时时间(单位ms)
77 | * @param task
78 | * @auth anduo 2015年5月8日
79 | */
80 | public void distributeLock(String path, int getLockTimeout, Runnable task) {
81 | InterProcessMutex lock = new InterProcessMutex(client, path);
82 | try {
83 | LOGGER.debug("尝试获取锁。。。");
84 | if (lock.acquire(getLockTimeout, TimeUnit.MILLISECONDS)) {
85 | try {
86 | LOGGER.debug("获得锁,开始执行任务。。。");
87 | task.run();
88 | } finally {
89 | lock.release();
90 | LOGGER.debug("释放锁,path:" + path);
91 | }
92 | } else {
93 | LOGGER.info("任务执行失败,在时间:" + getLockTimeout + "ms内,未获得分布式锁!");
94 | }
95 | } catch (Exception e) {
96 | LOGGER.error("执行分布式锁任务异常。", e);
97 | }
98 |
99 | }
100 |
101 | @Override
102 | public List getChildren(String path)
103 | throws Exception {
104 | return client.getChildren().forPath(path);
105 | }
106 |
107 | @Override
108 | public List listenChildrenPath(final String parent, final NodeListener listener, final boolean sync)
109 | throws Exception {
110 | PathChildrenCache cache = new PathChildrenCache(client, parent, false, false, EVENT_THREAD_POOL);
111 | cache.getListenable().addListener(new PathChildrenCacheListener() {
112 | @Override
113 | public void childEvent(CuratorFramework c, PathChildrenCacheEvent e)
114 | throws Exception {
115 | if (e.getData() == null) { return; }
116 | switch (e.getType()) {
117 | case CHILD_ADDED:
118 | listener.nodeChanged(ZKClientImpl.this,
119 | new ChangedEvent(e.getData().getPath(), ChangedEvent.Type.CHILD_ADDED));
120 | break;
121 | case CHILD_REMOVED:
122 | listener.nodeChanged(ZKClientImpl.this,
123 | new ChangedEvent(e.getData().getPath(), ChangedEvent.Type.CHILD_REMOVED));
124 | break;
125 | case CHILD_UPDATED:
126 | listener.nodeChanged(ZKClientImpl.this,
127 | new ChangedEvent(e.getData().getPath(), ChangedEvent.Type.CHILD_UPDATED));
128 | break;
129 | }
130 | }
131 | }, SAME_EXECUTOR);
132 | PathChildrenCache.StartMode mode = sync ? PathChildrenCache.StartMode.BUILD_INITIAL_CACHE : PathChildrenCache.StartMode.NORMAL;
133 | cache.start(mode);
134 | List children = cache.getCurrentData();
135 | List result = new ArrayList();
136 | for (ChildData child : children) {
137 | result.add(child.getPath());
138 | }
139 | return result;
140 | }
141 |
142 | @Override
143 | public String addEphemeralNode(String parent, String node)
144 | throws Exception {
145 | return addEphemeralNode(ZKPaths.makePath(parent, node));
146 | }
147 |
148 | @Override
149 | public String addEphemeralNode(String path)
150 | throws Exception {
151 | return client.create().withMode(CreateMode.EPHEMERAL).forPath(path);
152 | }
153 |
154 | @Override
155 | public void addPersistentNode(String path)
156 | throws Exception {
157 | try {
158 | client.newNamespaceAwareEnsurePath(path).ensure(client.getZookeeperClient());
159 | client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path);
160 | } catch (KeeperException.NodeExistsException e) {
161 | LOGGER.warn("Node already exists: {}", path);
162 | } catch (Exception e) {
163 | throw new Exception("addPersistentNode error", e);
164 | }
165 | }
166 |
167 | @Override
168 | public void addEphemeralNodeData(String path, String data)
169 | throws Exception {
170 | try {
171 | client.newNamespaceAwareEnsurePath(path).ensure(client.getZookeeperClient());
172 | client.create().withMode(CreateMode.EPHEMERAL).forPath(path, data.getBytes());
173 | } catch (KeeperException.NodeExistsException e) {
174 | LOGGER.warn("Node already exists: {}", path);
175 | } catch (Exception e) {
176 | throw new Exception("addEphemeralNodeData error", e);
177 | }
178 | }
179 |
180 | /**
181 | * 创建 节点
182 | *
183 | * @param path
184 | * @param data
185 | * @auth anduo 2015年5月8日
186 | */
187 | @Override
188 | public void createPath(String path, String data) {
189 | try {
190 | client.newNamespaceAwareEnsurePath(path).ensure(client.getZookeeperClient());
191 | client.setData().forPath(path, data.getBytes());
192 | } catch (Exception ex) {
193 | LOGGER.error("创建节点异常,path:" + path + " , data:" + data, ex);
194 | }
195 | }
196 |
197 | /**
198 | * 设置节点值
199 | *
200 | * @param path
201 | * @param data
202 | * @auth anduo 2015年5月8日
203 | */
204 | @Override
205 | public void updatePathValue(String path, String data) {
206 | try {
207 | LOGGER.debug("设置结点值,path:" + path + ",data:" + data);
208 | this.client.setData().forPath(path, data.getBytes("UTF-8"));
209 | } catch (Exception e) {
210 | LOGGER.error("设置zookeeper节点值异常,path:" + path + ",data" + data, e);
211 | }
212 | }
213 |
214 | /**
215 | * 获取节点值
216 | *
217 | * @param path
218 | * @return
219 | * @throws Exception
220 | * @auth anduo 2015年5月7日
221 | */
222 | @Override
223 | public String getPathValue(String path)
224 | throws Exception {
225 | if (!checkExist(path)) {
226 | throw new RuntimeException("Path " + path + " does not exists.");
227 | }
228 | return new String(client.getData().forPath(path), "UTF-8");
229 | }
230 |
231 | @PreDestroy
232 | @Override
233 | public void close() {
234 | LOGGER.info("Call close of ZKClient, reference count is: {}", REFERENCE_COUNT.get());
235 | if (REFERENCE_COUNT.decrementAndGet() == 0) {
236 | client.close();
237 | LOGGER.info("ZKClient is closed");
238 | }
239 | }
240 |
241 | @Override
242 | public boolean isConnected() {
243 | return client.getZookeeperClient().isConnected();
244 | }
245 |
246 | /**
247 | * @param listener
248 | */
249 | @Override
250 | public void addConnectionChangeListenter(final ConnectionStateListener listener) {
251 | if (listener != null) {
252 | client.getConnectionStateListenable()
253 | .addListener((sender, state) -> listener.stateChanged(ZKClientImpl.this, convertTo(state)));
254 | }
255 | }
256 |
257 | private ConnectionState convertTo(org.apache.curator.framework.state.ConnectionState state) {
258 | switch (state) {
259 | case CONNECTED:
260 | return ConnectionState.CONNECTED;
261 | case SUSPENDED:
262 | return ConnectionState.SUSPENDED;
263 | case RECONNECTED:
264 | return ConnectionState.RECONNECTED;
265 | case LOST:
266 | return ConnectionState.LOST;
267 | default:
268 | return ConnectionState.READ_ONLY;
269 | }
270 | }
271 |
272 | /**
273 | * 删除一个znode,如果该znode下面有子节点则会抛异常
274 | *
275 | * @param path
276 | * @throws Exception
277 | */
278 | @Override
279 | public void deletePath(String path)
280 | throws Exception {
281 | client.delete().forPath(path);
282 | }
283 |
284 | @Override
285 | public void deletAllPath(String path)
286 | throws Exception {
287 | List children = client.getChildren().forPath(path);
288 | if (children == null || children.size() == 0) {
289 | deletePath(path);
290 | return;
291 | }
292 | for (String child : children) {
293 | deletAllPath(ZKPaths.makePath(path, child));
294 | }
295 |
296 | }
297 |
298 | private class ConnectionWatcher implements ConnectionStateListener {
299 | CountDownLatch latch;
300 |
301 | ConnectionWatcher(CountDownLatch latch) {
302 | this.latch = latch;
303 | }
304 |
305 | @Override
306 | public void stateChanged(ZKClient client, ConnectionState newState) {
307 | if (newState == newState.CONNECTED) {
308 | latch.countDown();
309 | }
310 | }
311 | }
312 |
313 | @Override
314 | public boolean checkExist(String path) {
315 | try {
316 | Stat stat = client.checkExists().forPath(path);
317 | return stat != null;
318 | } catch (Exception e) {
319 | LOGGER.error("check exist error", e);
320 | return false;
321 | }
322 | }
323 |
324 | protected void incrementReference() {
325 | REFERENCE_COUNT.incrementAndGet();
326 | }
327 |
328 | }
329 |
330 |
--------------------------------------------------------------------------------
/nz-client/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | zk.servers=127.0.0.1:2181
2 | zk.config.root.path=/myapp/config
3 | zk.config.nodes.path=/myapp/config/nodes
4 | zk.config.commoncfg.path=/myapp/config/commoncfg
5 |
6 | local.config.nodes.path=local-nodes.properties
7 | local.config.commoncfg.path=local-commoncfg.properties
8 |
--------------------------------------------------------------------------------
/nz-client/src/main/resources/applicationContext.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | classpath:application.properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/nz-client/src/main/resources/local-commoncfg.properties:
--------------------------------------------------------------------------------
1 | ### commoncfg ###
2 | random.file.count=100
3 | random.file.size.min=10K
4 | random.file.size.max=10M
5 | randmo.file.last=You are Best!
--------------------------------------------------------------------------------
/nz-client/src/main/resources/local-nodes.properties:
--------------------------------------------------------------------------------
1 | ### nodes ###
2 | ##name-port##
3 | Leader-1=8411
4 | Leader-2=8412
5 | Leader-3=8413
6 | Leader-4=8414
7 | Leader-5=8415
--------------------------------------------------------------------------------
/nz-client/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=info, stdout, R
2 |
3 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
4 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
5 |
6 | # Pattern to output the caller's file name and line number.
7 | log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
8 |
9 | log4j.appender.R=org.apache.log4j.RollingFileAppender
10 | log4j.appender.R.File=Logs/nz.log
11 |
12 | log4j.appender.R.MaxFileSize=100KB
13 | # Keep one backup file
14 | log4j.appender.R.MaxBackupIndex=1
15 |
16 | log4j.appender.R.layout=org.apache.log4j.PatternLayout
17 | log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
--------------------------------------------------------------------------------
/nz-client/src/main/resources/name.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duoan/codes-scratch-zookeeper-netty/f3e2988374ddb677bc6b10f6c3b45ee359771aea/nz-client/src/main/resources/name.properties
--------------------------------------------------------------------------------
/nz-client/src/test/java/com/anduo/log4j/LogTest.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.log4j;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | /**
9 | * ━━━━━━神兽出没━━━━━━
10 | * ┏┓ ┏┓
11 | * ┏┛┻━━━┛┻┓
12 | * ┃ ┃
13 | * ┃ ━ ┃
14 | * ┃ ┳┛ ┗┳ ┃
15 | * ┃ ┃
16 | * ┃ ┻ ┃
17 | * ┃ ┃
18 | * ┗━┓ ┏━┛
19 | * ┃ ┃神兽保佑, 永无BUG!
20 | * ┃ ┃Code is far away from bug with the animal protecting
21 | * ┃ ┗━━━┓
22 | * ┃ ┣┓
23 | * ┃ ┏┛
24 | * ┗┓┓┏━┳┓┏┛
25 | * ┃┫┫ ┃┫┫
26 | * ┗┻┛ ┗┻┛
27 | * ━━━━━━感觉萌萌哒━━━━━━
28 | * Summary: log4jtest
29 | * Author : anduo@qq.com
30 | * Version: 1.0
31 | * Date : 15/7/2
32 | * time : 22:26
33 | */
34 | public class LogTest {
35 | private static final Logger LOGGER = LoggerFactory.getLogger(LogTest.class);
36 |
37 | public static void main(String[] args) {
38 | LOGGER.info("Hello World");
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/nz-client/src/test/java/com/anduo/log4j/SampleAnt.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.log4j;
4 |
5 | import org.kohsuke.args4j.Argument;
6 | import org.kohsuke.args4j.CmdLineException;
7 | import org.kohsuke.args4j.CmdLineParser;
8 | import org.kohsuke.args4j.Option;
9 |
10 | import java.io.File;
11 | import java.io.IOException;
12 | import java.util.List;
13 | import java.util.TreeMap;
14 | import java.util.Vector;
15 |
16 | /**
17 | * ━━━━━━神兽出没━━━━━━
18 | * ┏┓ ┏┓
19 | * ┏┛┻━━━┛┻┓
20 | * ┃ ┃
21 | * ┃ ━ ┃
22 | * ┃ ┳┛ ┗┳ ┃
23 | * ┃ ┃
24 | * ┃ ┻ ┃
25 | * ┃ ┃
26 | * ┗━┓ ┏━┛
27 | * ┃ ┃神兽保佑, 永无BUG!
28 | * ┃ ┃Code is far away from bug with the animal protecting
29 | * ┃ ┗━━━┓
30 | * ┃ ┣┓
31 | * ┃ ┏┛
32 | * ┗┓┓┏━┳┓┏┛
33 | * ┃┫┫ ┃┫┫
34 | * ┗┻┛ ┗┻┛
35 | * ━━━━━━感觉萌萌哒━━━━━━
36 | * Summary: 命令行工具测试
37 | * Author : anduo@qq.com
38 | * Version: 1.0
39 | * Date : 15/7/3
40 | * time : 21:06
41 | */
42 | public class SampleAnt {
43 | // 'normal' use
44 | @Option(name = "-help", usage = "print this message")
45 | private boolean help = false;
46 |
47 | // Ant uses abbreviations - a second option to set the
48 | // same attribute. Because only one @Option is allowed per element,
49 | // we use a workaround: a setter gets the abbreviation
50 | // A 'usage' would duplicate the info message, but without the possibility
51 | // of '-h' is hidden.
52 | @Option(name = "-h")
53 | private void setHelp(boolean h) { help = h; }
54 |
55 | @Option(name = "-projecthelp", usage = "print project help information")
56 | private boolean projecthelp;
57 |
58 | @Option(name = "-p")
59 | private void setProjecthelp(boolean p) { projecthelp = p; }
60 |
61 | @Option(name = "-version", usage = "print the version information and exit")
62 | private boolean version;
63 |
64 | @Option(name = "-diagnostics", usage = "print information that might be helpful to\ndiagnose or report problems.")
65 | private boolean diagnostics;
66 |
67 | @Option(name = "-quiet", usage = "be extra quiet")
68 | private boolean quiet;
69 |
70 | @Option(name = "-q")
71 | private void setQuiet(boolean q) { quiet = q; }
72 |
73 | @Option(name = "-verbose", usage = "be extra verbose")
74 | private boolean verbose;
75 |
76 | @Option(name = "-v")
77 | private void setVerbose(boolean v) { verbose = v; }
78 |
79 | @Option(name = "-debug", usage = "print debugging information")
80 | private boolean debug;
81 |
82 | @Option(name = "-d")
83 | private void setDebug(boolean d) { debug = d; }
84 |
85 | @Option(name = "-emacs", usage = "produce logging information without adornments")
86 | private boolean emacs;
87 |
88 | @Option(name = "-e")
89 | private void setEmacs(boolean e) { emacs = e; }
90 |
91 | @Option(name = "-lib", usage = "specifies a path to search for jars and classes", metaVar = "")
92 | private void setLib(String s) {
93 | String[] files = s.split(System.getProperty("path.separator"));
94 | for (int i = 0; i < files.length; i++) {
95 | lib.add(new File(files[i]));
96 | }
97 | }
98 |
99 | private List lib = new Vector();
100 |
101 | @Option(name = "-logger", usage = "the class which is to perform logging", metaVar = "")
102 | private String logger;
103 |
104 | @Option(name = "-listener", usage = "the class which is to perform", metaVar = "")
105 | private String listener;
106 |
107 | @Option(name = "-noinput", usage = "do not allow interactive input")
108 | private boolean noinput;
109 |
110 | @Option(name = "-buildfile", usage = "use given buildfile", metaVar = "")
111 | private File buildfile;
112 |
113 | // Ant's original is
114 | // -buildfile use given buildfile
115 | // -file ''
116 | // -f ''
117 | // How to handle this? Args4J prints the arguments sorted alphabetically.
118 | @Option(name = "-file", usage = " ''", metaVar = "")
119 | private void setBuildfile1(File f) { buildfile = f; }
120 |
121 | @Option(name = "-f", usage = " ''", metaVar = "")
122 | private void setBuildfile2(File f) { buildfile = f; }
123 |
124 | //TODO: How to handle that?
125 | // -D= use value for given property
126 | private TreeMap props = new TreeMap();
127 |
128 | @Option(name = "-keep-going", usage = "execute all targets that do not depend\non failed target(s)")
129 | private boolean keepGoing;
130 |
131 | @Option(name = "-k")
132 | private void setKeepGoing(boolean kg) { keepGoing = kg; }
133 |
134 | @Option(name = "-propertyfile", usage = "load all properties from file with -D\nproperties taking precedence",
135 | metaVar = "")
136 | private File propertyfile;
137 |
138 | @Option(name = "-inputhandler", usage = "the class which will handle input requests", metaVar = "")
139 | private String inputhandler;
140 |
141 | //TODO: Another problem
142 | // -find (s)earch for buildfile towards the root of
143 | // -s the filesystem and use it
144 | //problem is: info text has two lines and there are two lines for different option strings
145 | @Option(name = "-find", usage = "(s)earch for buildfile towards the root of\nthe filesystem and use it",
146 | metaVar = "")
147 | private File file;
148 |
149 | @Option(name = "-s", metaVar = "")
150 | private void setFile(File f) { file = f; }
151 |
152 | @Option(name = "-nice",
153 | usage = "A niceness value for the main thread:\n1 (lowest) to 10 (highest); 5 is the default")
154 | private void setNice(int n) {
155 | if (n > 0 && n < 11) { nice = n; }
156 | }
157 |
158 | private int nice = 5;
159 |
160 | @Option(name = "-nouserlib", usage = "Run ant without using the jar files from\n${user.home}/.ant/lib")
161 | private boolean nouserlib;
162 |
163 | @Option(name = "-noclasspath", usage = "Run ant without using CLASSPATH")
164 | private boolean noclasspath;
165 |
166 | @Argument
167 | private List targets;
168 |
169 | public static void main(String[] args)
170 | throws IOException {
171 | SampleAnt bean = new SampleAnt();
172 | try {
173 | bean.parseArgs(args);
174 | bean.showResult();
175 | } catch (IOException ioe) {
176 | //no-op
177 | }
178 | }
179 |
180 | public void parseArgs(String[] args)
181 | throws IOException {
182 | CmdLineParser parser = new CmdLineParser(this);
183 | try {
184 | parser.parseArgument(args);
185 | } catch (CmdLineException e) {
186 | int start = e.getMessage().indexOf('"') + 1;
187 | int end = e.getMessage().lastIndexOf('"');
188 | String wrongArgument = e.getMessage().substring(start, end);
189 | System.err.println("Unknown argument: " + wrongArgument);
190 | System.err.println("ant [options] [target [target2 [target3] ...]]");
191 | parser.printUsage(System.err);
192 | System.err.println();
193 | throw new IOException();
194 | }
195 | }
196 |
197 | public void showResult() {
198 | System.out.println("SampleAnt was configured with...");
199 | System.out.println(" help : " + help);
200 | System.out.println(" projecthelp : " + projecthelp);
201 | System.out.println(" version : " + version);
202 | System.out.println(" diagnostics : " + diagnostics);
203 | System.out.println(" quiet : " + quiet);
204 | System.out.println(" verbose : " + verbose);
205 | System.out.println(" debug : " + debug);
206 | System.out.println(" emacs : " + emacs);
207 | System.out.println(" lib");
208 | for (File f : lib) {
209 | System.out.println(" - " + f);
210 | }
211 | System.out.println(" logger : " + logger);
212 | System.out.println(" listener : " + listener);
213 | System.out.println(" noinput : " + noinput);
214 | System.out.println(" buildfile : " + buildfile);
215 | System.out.println(" properties");
216 | for (String key : props.keySet()) {
217 | System.out.println(" - " + key + " = " + props.get(key));
218 | }
219 | System.out.println(" keepGoing : " + keepGoing);
220 | System.out.println(" propertyfile : " + propertyfile);
221 | System.out.println(" inputhandler : " + inputhandler);
222 | System.out.println(" buildfile : " + file);
223 | System.out.println(" nice : " + nice);
224 | System.out.println(" nouserlib : " + nouserlib);
225 | System.out.println(" noclasspath : " + noclasspath);
226 | System.out.println("");
227 | System.out.println(" targets");
228 | for (String t : targets) {
229 | System.out.println(" - " + t);
230 | }
231 | System.out.println("");
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/nz-client/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=debug, stdout
2 |
3 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
4 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
5 |
6 | # Pattern to output the caller's file name and line number.
7 | log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
8 |
--------------------------------------------------------------------------------
/nz-server/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | nz
7 | com.anduo
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | com.anduo.nz
13 | server
14 | jar
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | org.apache.curator
26 | curator-recipes
27 |
28 |
29 |
30 | org.apache.commons
31 | commons-lang3
32 |
33 |
34 |
35 |
36 | net.coobird
37 | thumbnailator
38 |
39 |
40 |
41 | com.alibaba
42 | fastjson
43 |
44 |
45 |
46 | io.netty
47 | netty-all
48 |
49 |
50 |
51 | log4j
52 | log4j
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/client/FileUploadClient.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.client;
4 |
5 | import java.io.File;
6 | import java.util.logging.Level;
7 | import java.util.logging.Logger;
8 |
9 | /**
10 | * Summary: TODO 描述信息
11 | * Author : anduo@qq.com
12 | * Version: 1.0
13 | * Date : 15/7/1
14 | * time : 23:57
15 | */
16 | public class FileUploadClient {
17 | public static final int CLIENT_COUNT = 100;
18 |
19 | public static void main(String args[]) {
20 |
21 | for (int i = 0; i < CLIENT_COUNT; i++) {
22 | new Thread(new Runnable() {
23 |
24 | @Override
25 | public void run() {
26 | try {
27 | uploadFile();
28 | } catch (Exception ex) {
29 | Logger.getLogger(FileUploadClient.class.getName()).log(Level.SEVERE, null, ex);
30 | }
31 | }
32 | }).start();
33 |
34 | }
35 |
36 | }
37 |
38 | private static void uploadFile()
39 | throws Exception {
40 | File file = new File("small.jpg");
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/common/ConfigFile.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.common;
4 |
5 | import io.netty.util.internal.StringUtil;
6 | import org.apache.commons.lang3.StringUtils;
7 | import org.apache.log4j.LogManager;
8 | import org.apache.log4j.Logger;
9 | import org.w3c.dom.Node;
10 |
11 | import java.util.ResourceBundle;
12 |
13 | /**
14 | * ━━━━━━神兽出没━━━━━━
15 | * ┏┓ ┏┓
16 | * ┏┛┻━━━┛┻┓
17 | * ┃ ┃
18 | * ┃ ━ ┃
19 | * ┃ ┳┛ ┗┳ ┃
20 | * ┃ ┃
21 | * ┃ ┻ ┃
22 | * ┃ ┃
23 | * ┗━┓ ┏━┛
24 | * ┃ ┃神兽保佑, 永无BUG!
25 | * ┃ ┃Code is far away from bug with the animal protecting
26 | * ┃ ┗━━━┓
27 | * ┃ ┣┓
28 | * ┃ ┏┛
29 | * ┗┓┓┏━┳┓┏┛
30 | * ┃┫┫ ┃┫┫
31 | * ┗┻┛ ┗┻┛
32 | * ━━━━━━感觉萌萌哒━━━━━━
33 | * Summary: TODO 描述信息
34 | * Author : anduo@qq.com
35 | * Version: 1.0
36 | * Date : 15/7/2
37 | * time : 00:57
38 | */
39 | public class ConfigFile {
40 |
41 | private static final Logger LOGGER = LogManager.getLogger(ConfigFile.class);
42 |
43 | private ResourceBundle rb = null;
44 | private static ConfigFile commonConfig = null;
45 | private static ConfigFile zkConfig = null;
46 |
47 | static {
48 | LOGGER.info("load commonConfig&zkConfig properities.");
49 | commonConfig = new ConfigFile(ResourceBundle.getBundle("commonConfig"));
50 | zkConfig = new ConfigFile(ResourceBundle.getBundle("zkConfig"));
51 | }
52 |
53 | public ConfigFile(ResourceBundle rb) {
54 | this.rb = rb;
55 | }
56 |
57 | public static ConfigFile commonConfig() {
58 | return commonConfig;
59 | }
60 |
61 | public static ConfigFile zkConfig() {return zkConfig;}
62 |
63 | public String getItem(String item, String defaultValue) {
64 | String value = null;
65 | if (this.rb != null) {
66 | try {
67 | value = this.rb.getString(item.trim());
68 | value = value.trim();
69 | } catch (Exception e) {
70 | value = defaultValue;
71 | }
72 | }
73 | if (StringUtils.isEmpty(value)) {
74 | value = defaultValue;
75 | }
76 | return value;
77 | }
78 |
79 | public int getIntItem(String item, String defaultValue) {
80 | int i = 0;
81 | String value = getItem(item, defaultValue);
82 | try {
83 | i = Integer.parseInt(value);
84 | } catch (NumberFormatException e) {
85 | LOGGER.info(e.getMessage());
86 | }
87 | return i;
88 | }
89 |
90 | public long getLongItem(String item, String defaultValue) {
91 | long i = 0;
92 | String value = getItem(item, defaultValue);
93 | try {
94 | i = Long.valueOf(value);
95 | } catch (NumberFormatException e) {
96 | LOGGER.info(e.getMessage());
97 | }
98 | return i;
99 | }
100 |
101 | public double getDoubleItem(String item, String defaultValue) {
102 | double i = 0;
103 | String value = getItem(item, defaultValue);
104 | try {
105 | i = Double.valueOf(value);
106 | } catch (NumberFormatException e) {
107 | LOGGER.info(e.getMessage());
108 | }
109 | return i;
110 | }
111 |
112 | public boolean getBooleanItem(String item, boolean defaultValue) {
113 | boolean b = false;
114 | String value = getItem(item, new Boolean(defaultValue).toString());
115 | if ((value != null) && (value.equalsIgnoreCase("true"))) {
116 | b = true;
117 | }
118 | return b;
119 | }
120 |
121 | protected String getNodeValue(Node _node) {
122 | if (_node == null) {
123 | return null;
124 | }
125 | Node _firstChild = _node.getFirstChild();
126 | if (_firstChild == null) {
127 | return null;
128 | }
129 | String _text = _firstChild.getNodeValue();
130 | if (_text != null) {
131 | _text = _text.trim();
132 | }
133 | return _text;
134 | }
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/common/Constants.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.common;
4 |
5 | /**
6 | * ━━━━━━神兽出没━━━━━━
7 | * ┏┓ ┏┓
8 | * ┏┛┻━━━┛┻┓
9 | * ┃ ┃
10 | * ┃ ━ ┃
11 | * ┃ ┳┛ ┗┳ ┃
12 | * ┃ ┃
13 | * ┃ ┻ ┃
14 | * ┃ ┃
15 | * ┗━┓ ┏━┛
16 | * ┃ ┃神兽保佑, 永无BUG!
17 | * ┃ ┃Code is far away from bug with the animal protecting
18 | * ┃ ┗━━━┓
19 | * ┃ ┣┓
20 | * ┃ ┏┛
21 | * ┗┓┓┏━┳┓┏┛
22 | * ┃┫┫ ┃┫┫
23 | * ┗┻┛ ┗┻┛
24 | * ━━━━━━感觉萌萌哒━━━━━━
25 | * Summary: 公共常量类
26 | * Author : anduo@qq.com
27 | * Version: 1.0
28 | * Date : 15/7/2
29 | * time : 00:54
30 | */
31 | public class Constants {
32 | /**
33 | * MODULE_TYPE Server
34 | */
35 | public static final String MODULE_TYPE_SERVER = "server";
36 | /**
37 | * MODULE_TYPE Client
38 | */
39 | public static final String MODULE_TYPE_CLIENT = "client";
40 | /**
41 | * MODULE_TYPE Server With Admin
42 | */
43 | public static final String MODULE_TYPE_SERVER_WITH_ADMIN = "serverWithAdmin";
44 |
45 | /**
46 | * MODULE_TYPE Client With Admin
47 | */
48 | public static final String MODULE_TYPE_CLIENT_WITH_ADMIN = "clientWithAdmin";
49 |
50 | /**
51 | * MODULE_TYPE Server With Monitor
52 | */
53 | public static final String MODULE_TYPE_SERVER_WITH_MONITOR = "serverWithMonitor";
54 |
55 | /**
56 | * zero mq 服务端 启动消费者 端口
57 | */
58 | public static final String ZMQ_SERVER_PORT;
59 |
60 | /**
61 | * NETTY 服务端 启动消费者 端口
62 | */
63 | public static final int NETTY_SERVER_PORT;
64 |
65 | /**
66 | * job type local:本地job
67 | */
68 | public static final String JOB_TYPE_LOCAL = "LOCAL";
69 | /**
70 | * job type remote:分布式job
71 | */
72 | public static final String JOB_TYPE_REMOTE = "REMOTE";
73 |
74 | /**
75 | * job status 1:初始化状态
76 | */
77 | public static final String JOB_STATUS_1 = "1";
78 | /**
79 | * job status 2:运行中状态
80 | */
81 | public static final String JOB_STATUS_2 = "2";
82 |
83 | /**
84 | * job status 3:结束状态
85 | */
86 | public static final String JOB_STATUS_3 = "3";
87 |
88 | public static final String ALIVE = "alive";
89 |
90 | public static final String ALIVE_STATUS_0 = "0";//死亡
91 | public static final String ALIVE_STATUS_1 = "1";//存活
92 |
93 | public static final long SERVER_DIFFER_MILLI_SECONDS; //服务端HeartBeat间隔时间2分钟
94 |
95 | public static final long CLIENT_DIFFER_MILLI_SECONDS; //客户端HeartBeat间隔时间2分钟
96 |
97 | public static final long MONITOR_DIFFER_MILLI_SECONDS; //monitor HeartBeat间隔时间2分钟
98 |
99 | public static final String TOPIC_CLOVER_SERVER = "TOPIC_CLOVER_SERVER";
100 | public static final String TOPIC_CLOVER_CLIENT = "TOPIC_CLOVER_CLIENT";
101 |
102 | public static final int port = 8888;//netty port
103 |
104 | public static final String DEFAULT_COMPANY_EMAIL;
105 | public static final String DEFAULT_PRIVATE_EMAIL;
106 | public static final String SYSTEM_ID_CLOVER = "clover";
107 |
108 | public static final String REMOTE_JOB_GROUP = "remote-jobs";
109 | public static final String SPLIT_CHARACTER_FALG = "_#_";
110 | public static final String SERVER_JOB_INFO = "serverJobInfo";
111 | public static final String CLIENT_JOB_INFO = "clientJobInfo";
112 | public static final String CLIENT_JOB_PATH = "clientJobPath";
113 |
114 | public static String ZK_CONNECT_STRING = null;
115 | public static String ZK_ROOT_PATH = null;
116 | public static String ZK_USER_NAME = null;
117 | public static String ZK_PASSWORD = null;
118 | public static int ZOO_KEEPER_TIMEOUT;
119 |
120 | public static long ZMQ_SLEEP_CLIENT_MILLIS; //zeromq消费者端 等待一分钟后启动
121 | public static long ZMQ_SLEEP_SERVER_MILLIS;//zeromq生产者端 等待一分钟后启动
122 |
123 | public static String token;
124 |
125 | public static String DISABLED_DB; //是否启动DB
126 | public static String TYPE_DB = "typeDB"; //DB类型
127 |
128 | public static int POOL_SIZE;
129 |
130 | public static int MAX_FAIL_TIMES; //max fail times
131 | public static double MAX_MEM_RATIO; //max mem ratio
132 | public static double MAX_CPU_RATIO; //max cpu ratio
133 | public static String SERVER_JOB_STRATEGY; //server job strategy
134 |
135 | public static String ID = "id";
136 | public static String JOB_CLASS = "jobClass";
137 | public static String PORT = "port";
138 | public static String IP = "ip";
139 | public static String TS = "ts";
140 | public static String MEM_RATIO = "memRatio";
141 | public static String CPU_RATIO = "cpuRatio";
142 | public static String TOTAL_THREAD = "totalThread";
143 |
144 | public static String SUCCESS = "success";
145 | public static String ERROR_CODE = "errorCode";
146 |
147 | public static String ERROR_CODE_101 = "101"; //serverInfo |clientInfo is null
148 | public static String ERROR_CODE_102 = "102"; //over max mem ratio
149 | public static String ERROR_CODE_103 = "103"; // other error
150 |
151 | static {
152 | ZMQ_SERVER_PORT = ConfigFile.commonConfig().getItem("zmqServerPort", "1688");
153 | NETTY_SERVER_PORT = ConfigFile.commonConfig().getIntItem("nettyServerPort", "8087");
154 | SERVER_DIFFER_MILLI_SECONDS = ConfigFile.commonConfig().getLongItem("serverDifferMilliSeconds", "2*60*1000");
155 | CLIENT_DIFFER_MILLI_SECONDS = ConfigFile.commonConfig().getLongItem("clientDifferMilliSeconds", "2*60*1000");
156 | MONITOR_DIFFER_MILLI_SECONDS = ConfigFile.commonConfig().getLongItem("monitorDifferMilliSeconds", "2*60*1000");
157 | DEFAULT_COMPANY_EMAIL = ConfigFile.commonConfig().getItem("defaultCompanyEmail", "xiaoxiangxu@yolo24.com");
158 | DEFAULT_PRIVATE_EMAIL = ConfigFile.commonConfig().getItem("defaultPrivateEmail", "zhutouzan@163.com");
159 | ZMQ_SLEEP_CLIENT_MILLIS = ConfigFile.commonConfig().getLongItem("zmqSleepClientMillis", "1000");
160 | ZMQ_SLEEP_SERVER_MILLIS = ConfigFile.commonConfig().getLongItem("zmqSleepServerMillis", "1000");
161 | token = ConfigFile.commonConfig().getItem("token", "6fb8535d703f2492704aefc212b7cd41");
162 | DISABLED_DB = ConfigFile.commonConfig().getItem("disabledDB", "disabledDB");
163 | POOL_SIZE = ConfigFile.commonConfig().getIntItem("poolSize", "100");
164 | MAX_FAIL_TIMES = ConfigFile.commonConfig().getIntItem("maxFailTimes", "5");
165 | MAX_MEM_RATIO = ConfigFile.commonConfig().getDoubleItem("maxMemRatio", "0.95");
166 | MAX_CPU_RATIO = ConfigFile.commonConfig().getDoubleItem("maxCpuRatio", "0.95");
167 | SERVER_JOB_STRATEGY = ConfigFile.commonConfig().getItem("serverJobStrategy", "SYSTEM_CAPACITY");
168 |
169 | ZK_CONNECT_STRING = ConfigFile.zkConfig().getItem("zkConnectString", "127.0.0.1:2181");
170 | ZK_ROOT_PATH = ConfigFile.zkConfig().getItem("rootPath", "/clover");
171 | ZK_USER_NAME = ConfigFile.zkConfig().getItem("userName", "cloverAdmin");
172 | ZK_PASSWORD = ConfigFile.zkConfig().getItem("password", "password");
173 | ZOO_KEEPER_TIMEOUT = ConfigFile.zkConfig().getIntItem("zkSessionTimeout", "60000000");
174 | }
175 |
176 | }
177 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/entity/EchoFile.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.entity;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * Summary: EchoFile
9 | * Author : anduo@qq.com
10 | * Version: 1.0
11 | * Date : 15/7/2
12 | * time : 00:18
13 | */
14 | public class EchoFile implements Serializable {
15 | private static final long serialVersionUID = 8953150675564212795L;
16 | /**
17 | * 总包数.
18 | */
19 | private int sumCountPackage;
20 | /**
21 | * 当前包数.
22 | */
23 | private int countPackage;
24 | /**
25 | * 文件名
26 | */
27 | private String file_md5;//
28 | /**
29 | * 文件内容字节数组
30 | */
31 | private byte[] bytes;//
32 |
33 | public EchoFile() {
34 | }
35 |
36 | public EchoFile(byte[] bytes) {
37 | this.bytes = bytes;
38 | }
39 |
40 | /**
41 | * @return the sumCountPackage
42 | */
43 | public int getSumCountPackage() {
44 | return sumCountPackage;
45 | }
46 |
47 | /**
48 | * @param sumCountPackage the sumCountPackage to set
49 | */
50 | public void setSumCountPackage(int sumCountPackage) {
51 | this.sumCountPackage = sumCountPackage;
52 | }
53 |
54 | /**
55 | * @return the countPackage
56 | */
57 | public int getCountPackage() {
58 | return countPackage;
59 | }
60 |
61 | public void setCountPackage(int countPackage) {
62 | this.countPackage = countPackage;
63 | }
64 |
65 | public byte[] getBytes() {
66 | return bytes;
67 | }
68 |
69 | public void setBytes(byte[] bytes) {
70 | this.bytes = bytes;
71 | }
72 |
73 | public String getFile_md5() {
74 | return file_md5;
75 | }
76 |
77 | public void setFile_md5(String file_md5) {
78 | this.file_md5 = file_md5;
79 | }
80 | }
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/netty/EchoClient.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty;
4 |
5 | import com.anduo.nz.netty.handler.EchoClientHandler;
6 | import io.netty.bootstrap.Bootstrap;
7 | import io.netty.channel.ChannelFuture;
8 | import io.netty.channel.ChannelInitializer;
9 | import io.netty.channel.ChannelOption;
10 | import io.netty.channel.EventLoopGroup;
11 | import io.netty.channel.nio.NioEventLoopGroup;
12 | import io.netty.channel.socket.SocketChannel;
13 | import io.netty.channel.socket.nio.NioSocketChannel;
14 | import io.netty.handler.codec.serialization.ClassResolvers;
15 | import io.netty.handler.codec.serialization.ObjectDecoder;
16 | import io.netty.handler.codec.serialization.ObjectEncoder;
17 |
18 | /**
19 | * Summary: TODO 描述信息
20 | * Author : anduo@qq.com
21 | * Version: 1.0
22 | * Date : 15/7/2
23 | * time : 00:40
24 | */
25 | public class EchoClient {
26 | public void connect(int port, String host, final String filePath) throws Exception {
27 | EventLoopGroup group = new NioEventLoopGroup();
28 | try {
29 | Bootstrap b = new Bootstrap();
30 | b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer() {
31 |
32 | @Override
33 | protected void initChannel(SocketChannel ch) throws Exception {
34 | // ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
35 | // ch.pipeline().addLast(new StringEncoder());
36 | // ch.pipeline().addLast(new FixedLengthFrameDecoder(100));
37 | // ch.pipeline().addLast(new ChunkedWriteHandler());
38 | // ch.pipeline().addLast(new StringDecoder());
39 | // ch.pipeline().addLast(new EchoClientHandler());
40 | // ch.pipeline().addLast(new
41 | // LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
42 | // ch.pipeline().addLast(new LengthFieldPrepender(4,false));
43 | ch.pipeline().addLast(new ObjectDecoder(ClassResolvers.weakCachingConcurrentResolver(null)));
44 | ch.pipeline().addLast(new ObjectEncoder());
45 | ch.pipeline().addLast(new EchoClientHandler(filePath));
46 | }
47 | });
48 | ChannelFuture f = b.connect(host, port).sync();
49 | f.channel().closeFuture().sync();
50 | } finally {
51 | group.shutdownGracefully();
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/netty/InitializerPipeline.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty;
4 |
5 | import com.anduo.nz.netty.handler.EchoServerHandler;
6 | import io.netty.channel.ChannelInitializer;
7 | import io.netty.channel.ChannelPipeline;
8 | import io.netty.channel.socket.SocketChannel;
9 | import io.netty.handler.codec.serialization.ClassResolvers;
10 | import io.netty.handler.codec.serialization.ObjectDecoder;
11 | import io.netty.handler.codec.serialization.ObjectEncoder;
12 |
13 | /**
14 | * Summary: 装载Netty处理链路.
15 | * Author : anduo@qq.com
16 | * Version: 1.0
17 | * Date : 15/7/2
18 | * time : 00:20
19 | */
20 | public class InitializerPipeline extends ChannelInitializer {
21 | @Override
22 | protected void initChannel(SocketChannel ch)
23 | throws Exception {
24 | //使用Netty实现的线程池
25 | // DefaultEventExecutorGroup e1=new DefaultEventExecutorGroup(16);
26 | ChannelPipeline pipeline = ch.pipeline();
27 | // pipeline.addLast("decoder", new MessageDecoder());
28 | // pipeline.addLast("encoder", new MessageEncoder());
29 | // pipeline.addLast(e1,"handler", new CommonHandler());
30 | ch.pipeline().addLast(new ObjectDecoder(ClassResolvers.weakCachingConcurrentResolver(null)));
31 | ch.pipeline().addLast(new ObjectEncoder());
32 | pipeline.addLast("handler", new EchoServerHandler());
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/netty/NettyProtoServer.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty;
4 |
5 | import io.netty.bootstrap.ServerBootstrap;
6 | import io.netty.channel.ChannelFuture;
7 | import io.netty.channel.ChannelOption;
8 | import io.netty.channel.EventLoopGroup;
9 | import io.netty.channel.nio.NioEventLoopGroup;
10 | import io.netty.channel.socket.nio.NioServerSocketChannel;
11 | import org.apache.logging.log4j.LogManager;
12 | import org.apache.logging.log4j.Logger;
13 |
14 | /**
15 | * Summary: NettyProtoServer
16 | * Author : anduo@qq.com
17 | * Version: 1.0
18 | * Date : 15/7/2
19 | * time : 00:21
20 | */
21 | public class NettyProtoServer {
22 |
23 | private static final Logger LOGGER = LogManager.getLogger(NettyProtoServer.class);
24 |
25 | /**
26 | * 服务端口.
27 | */
28 | public static final int PORT = 7766;
29 |
30 | public NettyProtoServer() {
31 | }
32 |
33 | /**
34 | * 启动Netty的方法.
35 | */
36 | public void initialize() {
37 | ServerBootstrap server = new ServerBootstrap();
38 | EventLoopGroup bossGroup = new NioEventLoopGroup();
39 | EventLoopGroup workerGroup = new NioEventLoopGroup();
40 | try {
41 | server.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
42 | .childHandler(new InitializerPipeline()).option(ChannelOption.SO_BACKLOG, 128)
43 | .childOption(ChannelOption.SO_KEEPALIVE, true).childOption(ChannelOption.TCP_NODELAY, true);
44 | ChannelFuture f = server.bind(PORT).sync();
45 | LOGGER.debug("服务端口为:" + PORT);
46 | f.channel().closeFuture().sync();
47 | } catch (InterruptedException e) {
48 | LOGGER.error("Netty启动异常:", e);
49 | } finally {
50 | workerGroup.shutdownGracefully();
51 | bossGroup.shutdownGracefully();
52 | }
53 | }
54 |
55 | /**
56 | * 应用程序入口.
57 | */
58 | public static void main(String[] args) {
59 | new NettyProtoServer().initialize();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/netty/codec/MessageDecoder.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty.codec;
4 |
5 | import io.netty.buffer.ByteBuf;
6 | import io.netty.buffer.ByteBufUtil;
7 | import io.netty.channel.ChannelHandlerContext;
8 | import io.netty.handler.codec.ByteToMessageDecoder;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | import java.util.List;
13 |
14 | /**
15 | * Summary: 自定义解码器(具体功能:可以解决TCP粘包分包问题).
16 | * Author : anduo@qq.com
17 | * Version: 1.0
18 | * Date : 15/7/2
19 | * time : 00:33
20 | */
21 | public class MessageDecoder extends ByteToMessageDecoder {
22 |
23 | private static final Logger LOGGER = LoggerFactory.getLogger(MessageDecoder.class);
24 |
25 | @Override
26 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out)
27 | throws Exception {
28 | // 防止不发报文就关闭连接出现的错误
29 | if (!in.isReadable()) {
30 | return;
31 | }
32 | LOGGER.info(String.format("[%s]收到的的报文:[%s]", ctx.channel().localAddress().toString(), ByteBufUtil.hexDump(in)));
33 | byte[] ss = new byte[in.readableBytes()];
34 | in.readBytes(ss);
35 | out.add(in);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/netty/codec/MessageEncoder.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty.codec;
4 |
5 | import io.netty.buffer.ByteBuf;
6 | import io.netty.buffer.ByteBufUtil;
7 | import io.netty.channel.ChannelHandlerContext;
8 | import io.netty.handler.codec.MessageToByteEncoder;
9 | import org.apache.logging.log4j.LogManager;
10 | import org.apache.logging.log4j.Logger;
11 |
12 | /**
13 | * Summary: 自定义编码器
14 | * Author : anduo@qq.com
15 | * Version: 1.0
16 | * Date : 15/7/2
17 | * time : 00:27
18 | */
19 | public class MessageEncoder extends MessageToByteEncoder {
20 |
21 | private static final Logger LOGGER = LogManager.getLogger(MessageEncoder.class);
22 |
23 | @Override
24 | protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out)
25 | throws Exception {
26 | LOGGER.info(String.format("[%s]发送出的报文:[%s]",
27 | ctx.channel().localAddress().toString(),
28 | ByteBufUtil.hexDump((ByteBuf) msg)));
29 | out.writeBytes((byte[]) msg);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/netty/handler/EchoClientHandler.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty.handler;
4 |
5 | import com.anduo.nz.entity.EchoFile;
6 | import io.netty.channel.ChannelHandlerContext;
7 | import io.netty.channel.ChannelInboundHandlerAdapter;
8 | import org.apache.logging.log4j.LogManager;
9 | import org.apache.logging.log4j.Logger;
10 |
11 | import java.io.File;
12 | import java.io.FileNotFoundException;
13 | import java.io.IOException;
14 | import java.io.RandomAccessFile;
15 |
16 | /**
17 | * Summary: TODO 描述信息
18 | * Author : anduo@qq.com
19 | * Version: 1.0
20 | * Date : 15/7/2
21 | * time : 00:41
22 | */
23 | public class EchoClientHandler extends ChannelInboundHandlerAdapter {
24 | private static final Logger LOGGER = LogManager.getLogger(EchoClientHandler.class);
25 | private int dataLength = 1024;
26 | public RandomAccessFile randomAccessFile;
27 | private int sumCountpackage = 0;
28 | private String filePath;
29 |
30 | public EchoClientHandler(String filePath) {
31 | this.filePath = filePath;
32 | }
33 |
34 | public void channelActive(ChannelHandlerContext ctx) {
35 | try {
36 | File file = new File(filePath);
37 |
38 | randomAccessFile = new RandomAccessFile(file, "r");
39 | randomAccessFile.seek(0);
40 |
41 | if ((randomAccessFile.length() % dataLength) == 0) {
42 | sumCountpackage = (int) (randomAccessFile.length() / dataLength);
43 | } else {
44 | sumCountpackage = (int) (randomAccessFile.length() / dataLength) + 1;
45 | }
46 | byte[] bytes = new byte[dataLength];
47 |
48 | LOGGER.debug("文件总长度:" + randomAccessFile.length());
49 | if (randomAccessFile.read(bytes) != -1) {
50 | EchoFile msgFile = new EchoFile();
51 | msgFile.setSumCountPackage(sumCountpackage);
52 | msgFile.setCountPackage(1);
53 | msgFile.setBytes(bytes);
54 | msgFile.setFile_md5(file.getName());
55 | ctx.writeAndFlush(msgFile);
56 |
57 | } else {
58 | System.out.println("文件已经读完");
59 | }
60 | } catch (FileNotFoundException e) {
61 | e.printStackTrace();
62 | } catch (IOException i) {
63 | i.printStackTrace();
64 | }
65 | }
66 |
67 | @Override
68 | public void channelRead(ChannelHandlerContext ctx, Object msg)
69 | throws Exception {
70 | if (msg instanceof EchoFile) {
71 | EchoFile msgEchoFile = (EchoFile) msg;
72 | int countPackage = msgEchoFile.getCountPackage();
73 | randomAccessFile.seek(countPackage * dataLength - dataLength);
74 | int byteLength = 0;
75 | // 剩余的文件长度
76 | long remainderFileCount = randomAccessFile.length() - randomAccessFile.getFilePointer();
77 | LOGGER.debug("剩余文件长度:" + remainderFileCount);
78 | if (remainderFileCount < dataLength) {
79 | LOGGER.debug("小于固定长度:" + remainderFileCount);
80 | byteLength = (int) remainderFileCount;
81 |
82 | } else {
83 | byteLength = dataLength;
84 | }
85 | byte[] bytes = new byte[byteLength];
86 | if (randomAccessFile.read(bytes) != -1 && remainderFileCount > 0) {
87 | msgEchoFile.setCountPackage(countPackage);
88 | msgEchoFile.setBytes(bytes);
89 | ctx.writeAndFlush(msgEchoFile);
90 | } else {
91 | randomAccessFile.close();
92 | ctx.close();
93 | LOGGER.debug("文件已经读完--------" + remainderFileCount);
94 | }
95 | }
96 |
97 | }
98 |
99 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
100 | cause.printStackTrace();
101 | try {
102 | randomAccessFile.close();
103 | } catch (IOException e) {
104 | e.printStackTrace();
105 | }
106 | ctx.close();
107 | }
108 |
109 | @Override
110 | public void channelInactive(ChannelHandlerContext ctx)
111 | throws Exception {
112 | LOGGER.debug("服务器断开连接");
113 | randomAccessFile.close();
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/netty/handler/EchoServerHandler.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty.handler;
4 |
5 | import com.anduo.nz.entity.EchoFile;
6 | import com.anduo.nz.netty.NettyProtoServer;
7 | import io.netty.channel.ChannelHandlerAdapter;
8 | import io.netty.channel.ChannelHandlerContext;
9 | import io.netty.channel.ChannelInboundHandlerAdapter;
10 | import io.netty.util.AttributeKey;
11 | import org.apache.logging.log4j.LogManager;
12 | import org.apache.logging.log4j.Logger;
13 |
14 | import java.io.File;
15 | import java.io.RandomAccessFile;
16 |
17 | /**
18 | * Summary: EchoServerHandler
19 | * Author : anduo@qq.com
20 | * Version: 1.0
21 | * Date : 15/7/2
22 | * time : 00:23
23 | */
24 | public class EchoServerHandler extends ChannelInboundHandlerAdapter {
25 |
26 | private static final Logger LOGGER = LogManager.getLogger(NettyProtoServer.class);
27 |
28 | private String file_dir = "D:";
29 | private int dataLength = 1024;
30 |
31 | @Override
32 | public void channelActive(ChannelHandlerContext ctx)
33 | throws Exception {
34 | LOGGER.debug(String.format("[%s]\n========打开连接=======", ctx.channel().localAddress().toString()));
35 | ctx.channel().attr(AttributeKey.valueOf("haha")).set("1");
36 | }
37 |
38 | @Override
39 | public void channelInactive(ChannelHandlerContext ctx)
40 | throws Exception {
41 | LOGGER.debug(String.format("[%s]\n========关闭连接=======", ctx.channel().localAddress().toString()));
42 | LOGGER.debug(ctx.channel().remoteAddress().toString());
43 | LOGGER.debug(ctx.channel().attr(AttributeKey.valueOf("haha")).get().toString());
44 | }
45 |
46 | @Override
47 | public void channelRead(ChannelHandlerContext ctx, Object msg)
48 | throws Exception {
49 | if (msg instanceof EchoFile) {
50 | EchoFile ef = (EchoFile) msg;
51 | int SumCountPackage = ef.getSumCountPackage();
52 | int countPackage = ef.getCountPackage();
53 | byte[] bytes = ef.getBytes();
54 | String md5 = ef.getFile_md5();//文件名
55 |
56 | String path = file_dir + File.separator + md5;
57 | File file = new File(path);
58 | RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
59 | randomAccessFile.seek(countPackage * dataLength - dataLength);
60 | randomAccessFile.write(bytes);
61 | LOGGER.debug("总包数:" + ef.getSumCountPackage());
62 | LOGGER.debug("收到第" + countPackage + "包");
63 | LOGGER.debug("本包字节数:" + bytes.length);
64 | countPackage = countPackage + 1;
65 |
66 | if (countPackage <= SumCountPackage) {
67 | ef.setCountPackage(countPackage);
68 | ctx.writeAndFlush(ef);
69 | randomAccessFile.close();
70 | } else {
71 | randomAccessFile.close();
72 | ctx.close();
73 | }
74 | }
75 | }
76 |
77 | @Override
78 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
79 | throws Exception {
80 | LOGGER.error("[" + ctx.channel().localAddress().toString() + "]" + "通讯异常:", cause);
81 | ctx.close();
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/server/HttpStaticFileServer.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.server;
4 |
5 | import io.netty.bootstrap.ServerBootstrap;
6 | import io.netty.channel.Channel;
7 | import io.netty.channel.EventLoopGroup;
8 | import io.netty.channel.nio.NioEventLoopGroup;
9 | import io.netty.channel.socket.nio.NioServerSocketChannel;
10 | import org.apache.logging.log4j.LogManager;
11 | import org.apache.logging.log4j.Logger;
12 |
13 | /**
14 | * Summary: HttpStaticFileServer
15 | * Author : anduo@qq.com
16 | * Version: 1.0
17 | * Date : 15/7/1
18 | * time : 23:39
19 | */
20 | public class HttpStaticFileServer {
21 |
22 | private static final Logger LOGGER = LogManager.getLogger(HttpStaticFileServer.class);
23 |
24 | private final int port;
25 |
26 | public HttpStaticFileServer(int port) {
27 | this.port = port;
28 | }
29 |
30 | public void run()
31 | throws Exception {
32 | EventLoopGroup bossGroup = new NioEventLoopGroup(1);
33 | EventLoopGroup workerGroup = new NioEventLoopGroup();
34 | try {
35 | ServerBootstrap b = new ServerBootstrap();
36 | b.group(bossGroup, workerGroup)
37 | .channel(NioServerSocketChannel.class)
38 | .childHandler(new HttpStaticFileServerInitializer());
39 |
40 | Channel ch = b.bind(port).sync().channel();
41 | LOGGER.info("File server started at port " + port + '.');
42 | ch.closeFuture().sync();
43 | } finally {
44 | bossGroup.shutdownGracefully();
45 | workerGroup.shutdownGracefully();
46 | }
47 | }
48 |
49 | public static void main(String[] args)
50 | throws Exception {
51 | int port;
52 | if (args.length > 0) {
53 | port = Integer.parseInt(args[0]);
54 | } else {
55 | port = 8080;
56 | }
57 | new HttpStaticFileServer(port).run();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/server/HttpStaticFileServerHandler.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.server;
4 |
5 | import com.alibaba.fastjson.JSONObject;
6 | import io.netty.buffer.Unpooled;
7 | import io.netty.channel.*;
8 | import io.netty.handler.codec.http.*;
9 | import io.netty.handler.codec.http.multipart.*;
10 | import io.netty.util.CharsetUtil;
11 | import net.coobird.thumbnailator.Thumbnails;
12 | import org.apache.logging.log4j.LogManager;
13 | import org.apache.logging.log4j.Logger;
14 | import org.apache.logging.log4j.Level;
15 |
16 | import javax.activation.MimetypesFileTypeMap;
17 | import java.awt.*;
18 | import java.awt.image.BufferedImage;
19 | import java.io.File;
20 | import java.io.FileNotFoundException;
21 | import java.io.IOException;
22 | import java.io.RandomAccessFile;
23 | import java.net.URI;
24 | import java.util.List;
25 | import java.util.Map;
26 | import java.util.UUID;
27 |
28 | import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;
29 | import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
30 | import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive;
31 | import static io.netty.handler.codec.http.HttpHeaders.setContentLength;
32 | import static io.netty.handler.codec.http.HttpResponseStatus.*;
33 | import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
34 |
35 | /**
36 | * Summary: HttpStaticFileServerHandler
37 | * Author : anduo@qq.com
38 | * Version: 1.0
39 | * Date : 15/7/1
40 | * time : 23:33
41 | */
42 | public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler {
43 |
44 | private static final Logger LOGGER = LogManager.getLogger(HttpStaticFileServerHandler.class);
45 |
46 | // where to store the files
47 | private static final String BASE_PATH = "uploads/";
48 |
49 | // query param used to download a file
50 | private static final String FILE_QUERY_PARAM = "file";
51 |
52 | private HttpPostRequestDecoder decoder;
53 | private static final HttpDataFactory factory = new DefaultHttpDataFactory(true);
54 |
55 | private boolean readingChunks;
56 |
57 | private static final int THUMB_MAX_WIDTH = 100;
58 | private static final int THUMB_MAX_HEIGHT = 100;
59 |
60 | @Override
61 | protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request)
62 | throws Exception {
63 | // get the URL
64 | URI uri = new URI(request.getUri());
65 | String uriStr = uri.getPath();
66 |
67 | System.out.println(request.getMethod() + " request received");
68 |
69 | if (request.getMethod() == HttpMethod.GET) {
70 | serveFile(ctx, request); // user requested a file, serve it
71 | } else if (request.getMethod() == HttpMethod.POST) {
72 | uploadFile(ctx, request); // user requested to upload file, handle request
73 | } else {
74 | // unknown request, send error message
75 | System.out.println(request.getMethod() + " request received, sending 405");
76 | sendError(ctx, HttpResponseStatus.METHOD_NOT_ALLOWED);
77 | }
78 |
79 | }
80 |
81 | //当绑定到服务端的时候触发
82 | @Override
83 | public void channelActive(ChannelHandlerContext ctx)
84 | throws Exception {
85 | System.out.println("hello this is server!");
86 | }
87 |
88 | private void serveFile(ChannelHandlerContext ctx, FullHttpRequest request) {
89 |
90 | // decode the query string
91 | QueryStringDecoder decoderQuery = new QueryStringDecoder(request.getUri());
92 | Map> uriAttributes = decoderQuery.parameters();
93 |
94 | // get the requested file name
95 | String fileName = "";
96 | try {
97 | fileName = uriAttributes.get(FILE_QUERY_PARAM).get(0);
98 | } catch (Exception e) {
99 | sendError(ctx, HttpResponseStatus.BAD_REQUEST, FILE_QUERY_PARAM + " query param not found");
100 | return;
101 | }
102 |
103 | // start serving the requested file
104 | sendFile(ctx, fileName, request);
105 | }
106 |
107 | /**
108 | * This method reads the requested file from disk and sends it as response.
109 | * It also sets proper content-type of the response header
110 | *
111 | * @param fileName name of the requested file
112 | */
113 | private void sendFile(ChannelHandlerContext ctx, String fileName, FullHttpRequest request) {
114 | File file = new File(BASE_PATH + fileName);
115 | if (file.isDirectory() || file.isHidden() || !file.exists()) {
116 | sendError(ctx, NOT_FOUND);
117 | return;
118 | }
119 |
120 | if (!file.isFile()) {
121 | sendError(ctx, FORBIDDEN);
122 | return;
123 | }
124 |
125 | RandomAccessFile raf;
126 |
127 | try {
128 | raf = new RandomAccessFile(file, "r");
129 | } catch (FileNotFoundException fnfe) {
130 | sendError(ctx, NOT_FOUND);
131 | return;
132 | }
133 |
134 | long fileLength = 0;
135 | try {
136 | fileLength = raf.length();
137 | } catch (IOException ex) {
138 | LOGGER.log(Level.ERROR, "fileLength error", ex);
139 | }
140 |
141 | HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
142 | setContentLength(response, fileLength);
143 | setContentTypeHeader(response, file);
144 |
145 | //setDateAndCacheHeaders(response, file);
146 | if (isKeepAlive(request)) {
147 | response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
148 | }
149 |
150 | // Write the initial line and the header.
151 | ctx.write(response);
152 |
153 | // Write the content.
154 | ChannelFuture sendFileFuture;
155 | DefaultFileRegion defaultRegion = new DefaultFileRegion(raf.getChannel(), 0, fileLength);
156 | sendFileFuture = ctx.write(defaultRegion);
157 |
158 | // Write the end marker
159 | ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
160 |
161 | // Decide whether to close the connection or not.
162 | if (!isKeepAlive(request)) {
163 | // Close the connection when the whole content is written out.
164 | lastContentFuture.addListener(ChannelFutureListener.CLOSE);
165 | }
166 | }
167 |
168 | /**
169 | * This will set the content types of files. If you want to support any
170 | * files add the content type and corresponding file extension here.
171 | *
172 | * @param response
173 | * @param file
174 | */
175 | private static void setContentTypeHeader(HttpResponse response, File file) {
176 | MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
177 | mimeTypesMap.addMimeTypes("image png tif jpg jpeg bmp");
178 | mimeTypesMap.addMimeTypes("text/plain txt");
179 | mimeTypesMap.addMimeTypes("application/pdf pdf");
180 |
181 | String mimeType = mimeTypesMap.getContentType(file);
182 |
183 | response.headers().set(CONTENT_TYPE, mimeType);
184 | }
185 |
186 | private void uploadFile(ChannelHandlerContext ctx, FullHttpRequest request) {
187 |
188 | // test comment
189 | try {
190 | decoder = new HttpPostRequestDecoder(factory, request);
191 | //System.out.println("decoder created");
192 | } catch (HttpPostRequestDecoder.ErrorDataDecoderException e1) {
193 | e1.printStackTrace();
194 | sendError(ctx, HttpResponseStatus.BAD_REQUEST, "Failed to decode file data");
195 | return;
196 | }
197 |
198 | readingChunks = HttpHeaders.isTransferEncodingChunked(request);
199 |
200 | if (decoder != null) {
201 | if (request instanceof HttpContent) {
202 |
203 | // New chunk is received
204 | HttpContent chunk = (HttpContent) request;
205 | try {
206 | decoder.offer(chunk);
207 | } catch (HttpPostRequestDecoder.ErrorDataDecoderException e1) {
208 | e1.printStackTrace();
209 | sendError(ctx, HttpResponseStatus.BAD_REQUEST, "Failed to decode file data");
210 | return;
211 | }
212 |
213 | readHttpDataChunkByChunk(ctx);
214 | // example of reading only if at the end
215 | if (chunk instanceof LastHttpContent) {
216 | readingChunks = false;
217 | reset();
218 | }
219 | } else {
220 | sendError(ctx, HttpResponseStatus.BAD_REQUEST, "Not a http request");
221 | }
222 | } else {
223 | sendError(ctx, HttpResponseStatus.BAD_REQUEST, "Failed to decode file data");
224 | }
225 |
226 | }
227 |
228 | private void sendOptionsRequestResponse(ChannelHandlerContext ctx) {
229 | HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
230 | ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
231 | }
232 |
233 | private void sendResponse(ChannelHandlerContext ctx, String responseString, String contentType,
234 | HttpResponseStatus status) {
235 | FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
236 | status,
237 | Unpooled.copiedBuffer(responseString,
238 | CharsetUtil.UTF_8));
239 |
240 | response.headers().set(CONTENT_TYPE, contentType);
241 | response.headers().add("Access-Control-Allow-Origin", "*");
242 |
243 | // Close the connection as soon as the error message is sent.
244 | ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
245 | }
246 |
247 | private void sendUploadedFileName(JSONObject fileName, ChannelHandlerContext ctx) {
248 | JSONObject jsonObj = new JSONObject();
249 |
250 | String msg = "Unexpected error occurred";
251 | String contentType = "application/json; charset=UTF-8";
252 | HttpResponseStatus status = HttpResponseStatus.OK;
253 |
254 | if (fileName != null) {
255 | msg = fileName.toString();
256 | } else {
257 | LOGGER.error("uploaded file names are blank");
258 | status = HttpResponseStatus.BAD_REQUEST;
259 | contentType = "text/plain; charset=UTF-8";
260 | }
261 |
262 | sendResponse(ctx, msg, contentType, status);
263 |
264 | }
265 |
266 | private void reset() {
267 | //request = null;
268 |
269 | // destroy the decoder to release all resources
270 | decoder.destroy();
271 | decoder = null;
272 | }
273 |
274 | /**
275 | * Example of reading request by chunk and getting values from chunk to
276 | * chunk
277 | */
278 | private void readHttpDataChunkByChunk(ChannelHandlerContext ctx) {
279 | //decoder.isMultipart();
280 | if (decoder.isMultipart()) {
281 | try {
282 | while (decoder.hasNext()) {
283 | //System.out.println("decoder has next");
284 | InterfaceHttpData data = decoder.next();
285 | if (data != null) {
286 | writeHttpData(data, ctx);
287 | data.release();
288 | }
289 | }
290 | } catch (Exception e) {
291 | //e.printStackTrace();
292 | }
293 | } else {
294 | sendError(ctx, HttpResponseStatus.BAD_REQUEST, "Not a multipart request");
295 | }
296 |
297 | //System.out.println("decoder has no next");
298 | }
299 |
300 | private void writeHttpData(InterfaceHttpData data, ChannelHandlerContext ctx) {
301 |
302 | if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {
303 | FileUpload fileUpload = (FileUpload) data;
304 |
305 | if (fileUpload.isCompleted()) {
306 | JSONObject json = saveFileToDisk(fileUpload);
307 | sendUploadedFileName(json, ctx);
308 | } else {
309 | //responseContent.append("\tFile to be continued but should not!\r\n");
310 | sendError(ctx, HttpResponseStatus.BAD_REQUEST, "Unknown error occurred");
311 | }
312 | }
313 | }
314 |
315 | /**
316 | * generates and returns a unique string that'll be used to save an uploaded
317 | * file to disk
318 | *
319 | * @return generated unique string
320 | */
321 | private String getUniqueId() {
322 | UUID uniqueId = UUID.randomUUID();
323 |
324 | return uniqueId.toString();
325 | }
326 |
327 | /**
328 | * Saves the uploaded file to disk.
329 | *
330 | * @param fileUpload FileUpload object that'll be saved
331 | * @return name of the saved file. null if error occurred
332 | */
333 | private JSONObject saveFileToDisk(FileUpload fileUpload) {
334 |
335 | JSONObject responseJson = new JSONObject();
336 |
337 | String filePath = null; // full path of the new file to be saved
338 | String upoadedFileName = fileUpload.getFilename();
339 |
340 | // get the extension of the uploaded file
341 | String extension = "";
342 | int i = upoadedFileName.lastIndexOf('.');
343 | if (i > 0) {
344 | // get extension including the "."
345 | extension = upoadedFileName.substring(i);
346 | }
347 |
348 | String uniqueBaseName = getUniqueId();
349 | String fileName = uniqueBaseName + extension;
350 |
351 | try {
352 | filePath = BASE_PATH + fileName;
353 | fileUpload.renameTo(new File(filePath)); // enable to move into another
354 | responseJson.put("file", fileName);
355 | if (isImageExtension(extension)) {
356 | String thumbname = createThumbnail(filePath, uniqueBaseName, extension);
357 | responseJson.put("thumb", thumbname);
358 | }
359 | } catch (Exception ex) {
360 | LOGGER.error(ex);
361 | responseJson = null;
362 | }
363 |
364 | return responseJson;
365 | }
366 |
367 | /**
368 | * Creates a thumbnail of an image file
369 | *
370 | * @param fileFullPath full path of the source image
371 | * @param fileNameBase Base name of the file i.e without extension
372 | * @param extension extension of the file
373 | */
374 | private String createThumbnail(String fileFullPath, String fileNameBase, String extension) {
375 | String thumbImgName = fileNameBase + "_thumb" + extension; // thumbnail image base name
376 | String thumbImageFullPath = BASE_PATH + thumbImgName; // all thumbs are jpg files
377 |
378 | try {
379 | Thumbnails.of(new File(fileFullPath)).size(100, 100).toFile(new File(thumbImageFullPath));
380 | } catch (IOException ex) {
381 | LOGGER.error(ex);
382 | thumbImgName = "";
383 | }
384 | return thumbImgName;
385 |
386 | }
387 |
388 | private static boolean isImageExtension(String extension) {
389 | boolean isImageFile = false;
390 | String extensionInLowerCase = extension.toLowerCase();
391 | isImageFile |= extensionInLowerCase.equals(".jpg");
392 | isImageFile |= extensionInLowerCase.equals(".png");
393 | isImageFile |= extensionInLowerCase.equals(".jpeg");
394 | isImageFile |= extensionInLowerCase.equals(".gif");
395 | return isImageFile;
396 |
397 | }
398 |
399 | private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status, String msg) {
400 | FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
401 | status,
402 | Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
403 | response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
404 |
405 | // Close the connection as soon as the error message is sent.
406 | ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
407 | }
408 |
409 | private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
410 | sendError(ctx, status, "Failure: " + status.toString() + "\r\n");
411 | }
412 |
413 | private static BufferedImage resizeImage(BufferedImage originalImage, int type) {
414 |
415 | BufferedImage resizedImage = new BufferedImage(THUMB_MAX_WIDTH, THUMB_MAX_HEIGHT, type);
416 | Graphics2D g = resizedImage.createGraphics();
417 | g.drawImage(originalImage, 0, 0, THUMB_MAX_WIDTH, THUMB_MAX_HEIGHT, null);
418 | g.dispose();
419 |
420 | return resizedImage;
421 | }
422 |
423 | }
424 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/server/HttpStaticFileServerInitializer.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.server;
4 |
5 | import io.netty.channel.ChannelInitializer;
6 | import io.netty.channel.ChannelPipeline;
7 | import io.netty.channel.socket.SocketChannel;
8 | import io.netty.handler.codec.http.HttpObjectAggregator;
9 | import io.netty.handler.codec.http.HttpRequestDecoder;
10 | import io.netty.handler.codec.http.HttpResponseEncoder;
11 | import io.netty.handler.codec.http.cors.CorsConfig;
12 | import io.netty.handler.codec.http.cors.CorsHandler;
13 |
14 | import java.util.logging.SocketHandler;
15 |
16 | /**
17 | * Summary: HttpStaticFileServerInitializer
18 | * Author : anduo@qq.com
19 | * Version: 1.0
20 | * Date : 15/7/1
21 | * time : 23:31
22 | */
23 | public class HttpStaticFileServerInitializer extends ChannelInitializer {
24 |
25 | @Override
26 | protected void initChannel(SocketChannel ch)
27 | throws Exception {
28 | // Create a default pipeline implementation.
29 | CorsConfig corsConfig = CorsConfig.withAnyOrigin().build();
30 | ChannelPipeline pipeline = ch.pipeline();
31 | // Uncomment the following line if you want HTTPS
32 | //SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
33 | //engine.setUseClientMode(false);
34 | //pipeline.addLast("ssl", new SslHandler(engine));
35 |
36 | pipeline.addLast("encoder", new HttpResponseEncoder());
37 | pipeline.addLast("decoder", new HttpRequestDecoder());
38 | pipeline.addLast("aggregator", new HttpObjectAggregator(8388608)); // 8MB
39 | //pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
40 | pipeline.addLast("cors", new CorsHandler(corsConfig));
41 | pipeline.addLast("handler", new HttpStaticFileServerHandler());
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/zk/ClientDict.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.zk;
4 |
5 | import org.apache.log4j.LogManager;
6 | import org.apache.log4j.Logger;
7 |
8 | /**
9 | * ━━━━━━神兽出没━━━━━━
10 | * ┏┓ ┏┓
11 | * ┏┛┻━━━┛┻┓
12 | * ┃ ┃
13 | * ┃ ━ ┃
14 | * ┃ ┳┛ ┗┳ ┃
15 | * ┃ ┃
16 | * ┃ ┻ ┃
17 | * ┃ ┃
18 | * ┗━┓ ┏━┛
19 | * ┃ ┃神兽保佑, 永无BUG!
20 | * ┃ ┃Code is far away from bug with the animal protecting
21 | * ┃ ┗━━━┓
22 | * ┃ ┣┓
23 | * ┃ ┏┛
24 | * ┗┓┓┏━┳┓┏┛
25 | * ┃┫┫ ┃┫┫
26 | * ┗┻┛ ┗┻┛
27 | * ━━━━━━感觉萌萌哒━━━━━━
28 | * Summary: TODO 描述信息
29 | * Author : anduo@qq.com
30 | * Version: 1.0
31 | * Date : 15/7/2
32 | * time : 01:07
33 | */
34 | public class ClientDict {
35 | public static ClientDict self = null;
36 | protected static Logger logger = LogManager.getLogger(ClientDict.class);
37 | protected ZKConnect ZKConnect = null;
38 | public ClientListener clientListener = null;
39 |
40 | static {
41 | self = new ClientDict();
42 | }
43 |
44 | public ClientDict() {
45 | init();
46 | }
47 |
48 | public boolean init() {
49 | logger.info("ClientDict init zookeeper...");
50 | this.ZKConnect = new ZKConnect();
51 | if ((this.ZKConnect == null) || (!this.ZKConnect.start())) {
52 | return false;
53 | }
54 | this.clientListener = new ClientListener(CommonConstants.ZK_ROOT_PATH + "/client", this.ZKConnect);
55 | this.ZKConnect.addClientListener(this.clientListener);
56 | this.clientListener.reload();
57 | return true;
58 | }
59 |
60 | public CuratorFramework getZK() {
61 | return this.ZKConnect.instance;
62 | }
63 |
64 | public BasicDBObject hashClient(String jobClass, String hashKey) {
65 | return this.clientListener.clientNodes.hashClient(jobClass, hashKey);
66 | }
67 |
68 | /**
69 | * hashClient4S
70 | * @param jobClass
71 | * @param hashKey
72 | * @return
73 | */
74 | public Map hashClient4S(String jobClass, String hashKey) {
75 | return this.clientListener.clientNodes.hashClient4S(jobClass, hashKey);
76 | }
77 |
78 | public BasicDBObject hashClientByFixedClientIps(String jobClass,String[] fixedClientIps) {
79 | return this.clientListener.clientNodes.hashClientByFixedClientIps(jobClass, fixedClientIps);
80 | }
81 |
82 | /**
83 | * hashClientByFixedClientIps升级版本(4S==For Super)
84 | * @param jobClass
85 | * @param fixedClientIps
86 | * @return
87 | */
88 | public Map hashClient4SByFixedClientIps(String jobClass,String[] fixedClientIps) {
89 | return this.clientListener.clientNodes.hashClient4SByFixedClientIps(jobClass, fixedClientIps);
90 | }
91 |
92 | public BasicDBObject hashClientBySystemCapacity(String jobClass) {
93 | return this.clientListener.clientNodes.hashClientBySystemCapacity(jobClass);
94 | }
95 |
96 | /**
97 | * hashClientBySystemCapacity升级版本(4S==For Super)
98 | * @param jobClass
99 | * @return
100 | */
101 | public Map hashClient4SBySystemCapacity(String jobClass) {
102 | return this.clientListener.clientNodes.hashClient4SBySystemCapacity(jobClass);
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/zk/ClientListener.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.zk;
4 |
5 | import org.apache.log4j.LogManager;
6 | import org.apache.log4j.Logger;
7 | import org.apache.zookeeper.WatchedEvent;
8 | import org.apache.zookeeper.Watcher;
9 |
10 | /**
11 | * ━━━━━━神兽出没━━━━━━
12 | * ┏┓ ┏┓
13 | * ┏┛┻━━━┛┻┓
14 | * ┃ ┃
15 | * ┃ ━ ┃
16 | * ┃ ┳┛ ┗┳ ┃
17 | * ┃ ┃
18 | * ┃ ┻ ┃
19 | * ┃ ┃
20 | * ┗━┓ ┏━┛
21 | * ┃ ┃神兽保佑, 永无BUG!
22 | * ┃ ┃Code is far away from bug with the animal protecting
23 | * ┃ ┗━━━┓
24 | * ┃ ┣┓
25 | * ┃ ┏┛
26 | * ┗┓┓┏━┳┓┏┛
27 | * ┃┫┫ ┃┫┫
28 | * ┗┻┛ ┗┻┛
29 | * ━━━━━━感觉萌萌哒━━━━━━
30 | * Summary: TODO 描述信息
31 | * Author : anduo@qq.com
32 | * Version: 1.0
33 | * Date : 15/7/2
34 | * time : 01:08
35 | */
36 | public class ClientListener implements Watcher {
37 | protected static Logger logger = LogManager.getLogger(ClientListener.class);
38 | protected String prefixPath = "";
39 | protected ClientNodes clientNodes = new ClientNodes();
40 | protected ZKConnect ZKConnect = null;
41 | protected Integer LOCK = Integer.valueOf(0);
42 |
43 | public ClientListener(String prefixPath, ZKConnect ZKConnect) {
44 | this.prefixPath = prefixPath;
45 | this.ZKConnect = ZKConnect;
46 | }
47 |
48 | public BasicDBList records() {
49 | return this.clientNodes.records;
50 | }
51 |
52 | public BasicDBObject hashClient(String jobClass, String hashKey) {
53 | return this.clientNodes.hashClient(jobClass, hashKey);
54 | }
55 |
56 | public void removeRecord(String id) {
57 | this.clientNodes.remove(id);
58 | }
59 |
60 | public void addRecord(String id) {
61 | if (!this.ZKConnect.checkAlive())
62 | return;
63 | try {
64 | String c = this.ZKConnect.getData(this.prefixPath + "/" + id);
65 | if (c == null) {
66 | return;
67 | }
68 | BasicDBObject record = (BasicDBObject) JSON.parse(c);
69 | this.clientNodes.add(record);
70 | } catch (Exception e) {
71 | logger.error("ClientListener-->>ServerNodeListener error ", e);
72 | }
73 | }
74 |
75 | public void reload() {
76 | if (!this.ZKConnect.checkAlive()) {
77 | return;
78 | }
79 | if (!this.ZKConnect.exists(this.prefixPath))
80 | return;
81 | try {
82 | String timeStamp = DateUtil.currentDateTime();
83 | List items = this.ZKConnect.getChildrens(this.prefixPath);
84 | for (int i = 0; (items != null) && (i < items.size()); i++) {
85 | String id = (String) items.get(i);
86 | String c = this.ZKConnect.getData(this.prefixPath + "/" + id);
87 | if (c == null) {
88 | continue;
89 | }
90 | BasicDBObject record = (BasicDBObject) JSON.parse(c);
91 | record.put("timeStamp", timeStamp);
92 | this.clientNodes.add(record);
93 | }
94 | int index = 0;
95 | while (index < this.clientNodes.records.size()) {
96 | BasicDBObject record = (BasicDBObject) this.clientNodes.records.get(index);
97 | if (record.getString("timeStamp").equalsIgnoreCase(timeStamp)) {
98 | index++;
99 | } else if (!this.clientNodes.remove(record.getString("id"))) {
100 | index++;
101 | }
102 | }
103 | } catch (Exception e) {
104 | logger.error("ServerListener-->>reload() error.", e);
105 | }
106 | }
107 |
108 | public void process(WatchedEvent event) {
109 | if (event == null) {
110 | return;
111 | }
112 | String path = event.getPath();
113 | if ((path == null) || (!path.startsWith(this.prefixPath))) {
114 | return;
115 | }
116 | synchronized (this.LOCK) {
117 | try {
118 | String[] values = StringUtil.split(path, '/');
119 | String id = values.length >= 2 ? values[1] : "";
120 | BasicDBObject oServer = null;
121 | if (event.getType() == Event.EventType.NodeCreated) {
122 | addRecord(id);
123 | } else if (event.getType() == Event.EventType.NodeDeleted) {
124 | removeRecord(id);
125 | } else if (event.getType() == Event.EventType.NodeDataChanged) {
126 | addRecord(id);
127 | } else if (event.getType() == Event.EventType.NodeChildrenChanged) {
128 | reload();
129 | }
130 | } catch (Exception e) {
131 | logger.error("ServerListener-->>process(" + com.alibaba.fastjson.JSON.toJSONString(event) + ") error.", e);
132 | }
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/zk/ClientNodes.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.zk;
4 |
5 | import org.apache.commons.lang3.StringUtils;
6 |
7 | import java.util.HashMap;
8 | import java.util.HashSet;
9 | import java.util.Iterator;
10 |
11 | /**
12 | * ━━━━━━神兽出没━━━━━━
13 | * ┏┓ ┏┓
14 | * ┏┛┻━━━┛┻┓
15 | * ┃ ┃
16 | * ┃ ━ ┃
17 | * ┃ ┳┛ ┗┳ ┃
18 | * ┃ ┃
19 | * ┃ ┻ ┃
20 | * ┃ ┃
21 | * ┗━┓ ┏━┛
22 | * ┃ ┃神兽保佑, 永无BUG!
23 | * ┃ ┃Code is far away from bug with the animal protecting
24 | * ┃ ┗━━━┓
25 | * ┃ ┣┓
26 | * ┃ ┏┛
27 | * ┗┓┓┏━┳┓┏┛
28 | * ┃┫┫ ┃┫┫
29 | * ┗┻┛ ┗┻┛
30 | * ━━━━━━感觉萌萌哒━━━━━━
31 | * Summary: TODO 描述信息
32 | * Author : anduo@qq.com
33 | * Version: 1.0
34 | * Date : 15/7/2
35 | * time : 01:11
36 | */
37 | public class ClientNodes extends CommonNodes{
38 | protected static Logger logger = LoggerFactory.getLogger(ServerNodes.class);
39 | protected HashMap recordsById = new HashMap();
40 | protected HashMap recordsByJobClass = new HashMap();
41 | protected BasicDBList records = new BasicDBList();
42 | protected HashSet jobClassSet = new HashSet();
43 |
44 | public BasicDBObject hashClient(String jobClass, String hashKey) {
45 | BasicDBList items = getRecordsByJobClass(jobClass);
46 | if ((items == null) || (items.size() == 0)) {
47 | return null;
48 | }
49 | if (StringUtils.isEmpty(hashKey)) {
50 | hashKey = allocateNo();
51 | }
52 | int index = HashTimes.use33(hashKey) % items.size();
53 | return (BasicDBObject) items.get(index);
54 | }
55 |
56 | /**
57 | * hashClient升级版本(4S==For Super)
58 | * @param jobClass
59 | * @param hashKey
60 | * @return
61 | */
62 | public Map hashClient4S(String jobClass, String hashKey) {
63 | Map map = new HashMap();
64 | BasicDBList items = getRecordsByJobClass(jobClass);
65 | if ((items == null) || (items.size() == 0)) {
66 | map.put(CommonConstants.SUCCESS, false);
67 | map.put(CommonConstants.ERROR_CODE, CommonConstants.ERROR_CODE_101);
68 | return map;
69 | }
70 | if (StringUtil.isEmpty(hashKey)) {
71 | hashKey = allocateNo();
72 | }
73 | int index = HashTimes.use33(hashKey) % items.size();
74 | map.put(CommonConstants.SUCCESS, true);
75 | map.put(CommonConstants.CLIENT_JOB_INFO, items.get(index));
76 | return map;
77 | }
78 |
79 | public BasicDBObject hashClientByFixedClientIps(String jobClass, String[] fixedClientIps) {
80 | BasicDBList items = getRecordsByJobClass(jobClass);
81 | if ((items == null) || (items.size() == 0)) {
82 | return null;
83 | }
84 | int index = -1;
85 | for (String fixedClientIp : fixedClientIps) {
86 | index = findIndexByIp(fixedClientIp, items);
87 | if (index == -1) continue;
88 | }
89 | if (index == -1) {
90 | return null;
91 | }
92 | return (BasicDBObject) items.get(index);
93 | }
94 |
95 | /**
96 | * hashClientByFixedClientIps升级版本(4S==For Super)
97 | * @param jobClass
98 | * @param fixedClientIps
99 | * @return
100 | */
101 | public Map hashClient4SByFixedClientIps(String jobClass, String[] fixedClientIps) {
102 | Map map = new HashMap();
103 | BasicDBList items = getRecordsByJobClass(jobClass);
104 | if ((items == null) || (items.size() == 0)) {
105 | map.put(CommonConstants.SUCCESS, false);
106 | map.put(CommonConstants.ERROR_CODE, CommonConstants.ERROR_CODE_101);
107 | }
108 | int index = -1;
109 | for (String fixedClientIp : fixedClientIps) {
110 | index = findIndexByIp(fixedClientIp, items);
111 | if (index == -1) continue;
112 | }
113 | if (index == -1) {
114 | map.put(CommonConstants.SUCCESS, false);
115 | map.put(CommonConstants.ERROR_CODE, CommonConstants.ERROR_CODE_101);
116 | }
117 | map.put(CommonConstants.SUCCESS, true);
118 | map.put(CommonConstants.CLIENT_JOB_INFO, items.get(index));
119 | return map;
120 | }
121 |
122 | public BasicDBObject hashClientBySystemCapacity(String jobClass) {
123 | BasicDBList items = getRecordsByJobClass(jobClass);
124 | int itemLen;
125 | if ((items == null) || ((itemLen = items.size()) == 0)) {
126 | return null;
127 | } else if (1 == itemLen) {
128 | BasicDBObject item = (BasicDBObject) items.get(0);
129 | double memRatio = Double.valueOf(String.valueOf(item.get(CommonConstants.MEM_RATIO)));
130 | double cpuRatio = Double.valueOf(String.valueOf(item.get(CommonConstants.CPU_RATIO)));
131 | if (memRatio > CommonConstants.MAX_MEM_RATIO || cpuRatio > CommonConstants.MAX_CPU_RATIO ) {
132 | logger.error("ClientNodes-->>hashClientBySystemCapacity(" + jobClass + ") the memRatio(" + memRatio + ")" +
133 | " over max mem ratio("+CommonConstants.MAX_MEM_RATIO+") or the cpuRatio("+cpuRatio+") " +
134 | "over max cpu ratio("+CommonConstants.MAX_CPU_RATIO+") ");
135 | return null;
136 | } else {
137 | return item;
138 | }
139 | } else if (itemLen > 1) {
140 | BasicDBObject tempItem = (BasicDBObject) items.get(0);
141 | int minMemRatioIndex = 0;
142 | double minMemRatioValue = Double.valueOf(String.valueOf(tempItem.get(CommonConstants.MEM_RATIO)));
143 | double minCpuRatioValue = Double.valueOf(String.valueOf(tempItem.get(CommonConstants.CPU_RATIO)));
144 | int minTotalThreadValue = Integer.valueOf(String.valueOf(tempItem.get(CommonConstants.TOTAL_THREAD)));
145 | double minTotalValue = minMemRatioValue + minCpuRatioValue + minTotalThreadValue;
146 | for (int i = 1; i < itemLen; i++) {
147 | tempItem = (BasicDBObject) items.get(i);
148 | double tempMemRatioValue = Double.valueOf(String.valueOf(tempItem.get(CommonConstants.MEM_RATIO)));
149 | double tempCpuRatioValue = Double.valueOf(String.valueOf(tempItem.get(CommonConstants.CPU_RATIO)));
150 | int tempTotalThreadValue = Integer.valueOf(String.valueOf(tempItem.get(CommonConstants.TOTAL_THREAD)));
151 | double tempTotalValue = tempMemRatioValue + tempCpuRatioValue + tempTotalThreadValue;
152 | if (tempTotalValue < minTotalValue) {
153 | minMemRatioValue = tempMemRatioValue;
154 | minCpuRatioValue = tempCpuRatioValue;
155 | minTotalThreadValue = tempTotalThreadValue;
156 | minTotalValue = minMemRatioValue + minCpuRatioValue + minTotalThreadValue;
157 | minMemRatioIndex = i;
158 | }
159 | }
160 | if (minMemRatioValue > CommonConstants.MAX_MEM_RATIO || minCpuRatioValue > CommonConstants.MAX_CPU_RATIO) {
161 | logger.error("ClientNodes-->>hashClientBySystemCapacity(" + jobClass + ") " +
162 | "the memRatio(" + minMemRatioValue + ") over max mem ratio(" + CommonConstants.MAX_MEM_RATIO + ")" +
163 | "or the cpuRatio("+minCpuRatioValue+") over max cpu ration ("+CommonConstants.MAX_CPU_RATIO+") ");
164 | return null;
165 | } else {
166 | return (BasicDBObject) items.get(minMemRatioIndex);
167 | }
168 | }
169 | return null;
170 | }
171 |
172 | /**
173 | * hashClientBySystemCapacity升级版本(4S==For Super)
174 | *
175 | * @param jobClass
176 | * @return
177 | */
178 | public Map hashClient4SBySystemCapacity(String jobClass) {
179 | Map map = new HashMap();
180 | BasicDBList items = getRecordsByJobClass(jobClass);
181 | int itemLen;
182 | if ((items == null) || ((itemLen = items.size()) == 0)) {
183 | map.put(CommonConstants.SUCCESS, false);
184 | map.put(CommonConstants.ERROR_CODE, CommonConstants.ERROR_CODE_101);
185 | return map;
186 | } else if (1 == itemLen) {
187 | BasicDBObject item = (BasicDBObject) items.get(0);
188 | double memRatio = Double.valueOf(String.valueOf(item.get(CommonConstants.MEM_RATIO)));
189 | double cpuRatio = Double.valueOf(String.valueOf(item.get(CommonConstants.CPU_RATIO)));
190 | if (memRatio > CommonConstants.MAX_MEM_RATIO || cpuRatio > CommonConstants.MAX_CPU_RATIO) {
191 | logger.error("ClientNodes-->>hashClient4SBySystemCapacity(" + jobClass + ") the memRatio(" + memRatio + ")" +
192 | " over max mem ratio(" + CommonConstants.MAX_MEM_RATIO + ") or the cpuRatio("+cpuRatio+")" +
193 | " over max cpu ratio("+CommonConstants.MAX_CPU_RATIO+") ");
194 | map.put(CommonConstants.SUCCESS, false);
195 | map.put(CommonConstants.ERROR_CODE, CommonConstants.ERROR_CODE_102);
196 | map.put(CommonConstants.MEM_RATIO, memRatio);
197 | map.put(CommonConstants.CPU_RATIO, cpuRatio);
198 | return map;
199 | } else {
200 | map.put(CommonConstants.SUCCESS, true);
201 | map.put(CommonConstants.CLIENT_JOB_INFO, item);
202 | return map;
203 | }
204 | } else if (itemLen > 1) {
205 | BasicDBObject tempItem = (BasicDBObject) items.get(0);
206 | int minMemRatioIndex = 0;
207 | double minMemRatioValue = Double.valueOf(String.valueOf(tempItem.get(CommonConstants.MEM_RATIO)));
208 | double minCpuRatioValue = Double.valueOf(String.valueOf(tempItem.get(CommonConstants.CPU_RATIO)));
209 | int minTotalThreadValue = Integer.valueOf(String.valueOf(tempItem.get(CommonConstants.TOTAL_THREAD)));
210 | double minTotalValue = minMemRatioValue + minCpuRatioValue + minTotalThreadValue;
211 | for (int i = 1; i < itemLen; i++) {
212 | tempItem = (BasicDBObject) items.get(i);
213 | double tempMemRatioValue = Double.valueOf(String.valueOf(tempItem.get(CommonConstants.MEM_RATIO)));
214 | double tempCpuRatioValue = Double.valueOf(String.valueOf(tempItem.get(CommonConstants.CPU_RATIO)));
215 | int tempTotalThreadValue = Integer.valueOf(String.valueOf(tempItem.get(CommonConstants.TOTAL_THREAD)));
216 | double tempTotalValue = tempMemRatioValue + tempCpuRatioValue + tempTotalThreadValue;
217 | if (tempTotalValue < minTotalValue) {
218 | minMemRatioValue = tempMemRatioValue;
219 | minCpuRatioValue = tempCpuRatioValue;
220 | minTotalThreadValue = tempTotalThreadValue;
221 | minTotalValue = minMemRatioValue + minCpuRatioValue + minTotalThreadValue;
222 | minMemRatioIndex = i;
223 | }
224 | }
225 | if (minMemRatioValue > CommonConstants.MAX_MEM_RATIO || minCpuRatioValue > CommonConstants.MAX_CPU_RATIO) {
226 | logger.error("ClientNodes-->>hashClient4SBySystemCapacity(" + jobClass + ") " +
227 | "the memRatio(" + minMemRatioValue + ") over max mem ratio(" + CommonConstants.MAX_MEM_RATIO + ")" +
228 | "or the cpuRatio("+minCpuRatioValue+") over max cpu ration ("+CommonConstants.MAX_CPU_RATIO+") ");
229 | map.put(CommonConstants.SUCCESS, false);
230 | map.put(CommonConstants.ERROR_CODE, CommonConstants.ERROR_CODE_102);
231 | map.put(CommonConstants.MEM_RATIO, minMemRatioValue);
232 | map.put(CommonConstants.CPU_RATIO, minCpuRatioValue);
233 | return map;
234 | } else {
235 | map.put(CommonConstants.SUCCESS, true);
236 | map.put(CommonConstants.CLIENT_JOB_INFO, items.get(minMemRatioIndex));
237 | return map;
238 | }
239 | }
240 | map.put(CommonConstants.SUCCESS, false);
241 | map.put(CommonConstants.ERROR_CODE, CommonConstants.ERROR_CODE_103);
242 | return map;
243 | }
244 |
245 | public boolean containsKey(String id) {
246 | return this.recordsById.containsKey(id);
247 | }
248 |
249 | public BasicDBList getRecordsByJobClass(String jobClass) {
250 | return this.recordsByJobClass.get(jobClass);
251 | }
252 |
253 | public BasicDBList findRecordsByIP(String ip) {
254 | BasicDBList basicDBList = new BasicDBList();
255 | for (int i = 0; i < this.records.size(); i++) {
256 | BasicDBObject oServer = (BasicDBObject) this.records.get(i);
257 | if (oServer.getString(CommonConstants.IP).equalsIgnoreCase(ip)) {
258 | basicDBList.add(oServer);
259 | }
260 | }
261 | return basicDBList;
262 | }
263 |
264 | public synchronized void add(BasicDBObject record) {
265 | String id = record.getString(CommonConstants.ID);
266 | int index = findIndexById(id, this.records);
267 | if (index == -1)
268 | this.records.add(record);
269 | else {
270 | this.records.set(index, record);
271 | }
272 | this.recordsById.put(id, record);
273 | if (!record.containsField(CommonConstants.JOB_CLASS)) {
274 | return;
275 | }
276 | BasicDBList jobClassList = (BasicDBList) record.get(CommonConstants.JOB_CLASS);
277 | for (int i = 0; (jobClassList != null) && (i < jobClassList.size()); i++) {
278 | String tempJobClass = jobClassList.get(i).toString();
279 | this.jobClassSet.add(tempJobClass);
280 | BasicDBList items = this.recordsByJobClass.get(tempJobClass);
281 | if (items == null) {
282 | items = new BasicDBList();
283 | this.recordsByJobClass.put(tempJobClass, items);
284 | }
285 | index = findIndexById(id, items);
286 | if (index == -1)
287 | items.add(record);
288 | else {
289 | items.set(index, record);
290 | }
291 | }
292 | }
293 |
294 | public synchronized boolean remove(String id) {
295 | this.recordsById.remove(id);
296 | int index = findIndexById(id, this.records);
297 | boolean flag = index != -1;
298 | if (flag) {
299 | this.records.remove(index);
300 | }
301 | for (Iterator i = this.recordsByJobClass.entrySet().iterator(); i.hasNext();) {
302 | Map.Entry entry = (Map.Entry) i.next();
303 | BasicDBList items = (BasicDBList) entry.getValue();
304 | index = findIndexById(id, items);
305 | if (index != -1) {
306 | items.remove(index);
307 | }
308 | if (items.size() == 0) {
309 | this.jobClassSet.remove(entry.getKey());
310 | }
311 | }
312 | return flag;
313 | }
314 |
315 | public void clear() {
316 | this.recordsById.clear();
317 | this.recordsByJobClass.clear();
318 | this.records.clear();
319 | this.jobClassSet.clear();
320 | }
321 |
322 | }
323 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/zk/CommonNodes.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.zk;
4 |
5 | import java.util.concurrent.atomic.AtomicLong;
6 |
7 | /**
8 | * ━━━━━━神兽出没━━━━━━
9 | * ┏┓ ┏┓
10 | * ┏┛┻━━━┛┻┓
11 | * ┃ ┃
12 | * ┃ ━ ┃
13 | * ┃ ┳┛ ┗┳ ┃
14 | * ┃ ┃
15 | * ┃ ┻ ┃
16 | * ┃ ┃
17 | * ┗━┓ ┏━┛
18 | * ┃ ┃神兽保佑, 永无BUG!
19 | * ┃ ┃Code is far away from bug with the animal protecting
20 | * ┃ ┗━━━┓
21 | * ┃ ┣┓
22 | * ┃ ┏┛
23 | * ┗┓┓┏━┳┓┏┛
24 | * ┃┫┫ ┃┫┫
25 | * ┗┻┛ ┗┻┛
26 | * ━━━━━━感觉萌萌哒━━━━━━
27 | * Summary: TODO 描述信息
28 | * Author : anduo@qq.com
29 | * Version: 1.0
30 | * Date : 15/7/2
31 | * time : 01:09
32 | */
33 | public class CommonNodes {
34 | public static String allocateNo() {
35 | AtomicLong count = new AtomicLong(0L);
36 | if (count.get() == 9223372036854775807L) {
37 | count.set(0L);
38 | }
39 | return String.valueOf(count.addAndGet(1L));
40 | }
41 |
42 | public static int findIndexById(String id, BasicDBList items) {
43 | int result = -1;
44 | if (null != items) {
45 | for (int i = 0; i < items.size(); i++) {
46 | BasicDBObject oItem = (BasicDBObject) items.get(i);
47 | if (oItem.getString("id").equalsIgnoreCase(id)) {
48 | result = i;
49 | }
50 | }
51 | }
52 | return result;
53 | }
54 |
55 | public static int findIndexByIp(String ip, BasicDBList items) {
56 | int result = -1;
57 | for (int i = 0; i < items.size(); i++) {
58 | BasicDBObject oItem = (BasicDBObject) items.get(i);
59 | if (oItem.getString("ip").equalsIgnoreCase(ip)) {
60 | result = i;
61 | }
62 | }
63 | return result;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/nz-server/src/main/java/com/anduo/nz/zk/ZKUtil.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.zk;
4 |
5 | import com.anduo.nz.common.Constants;
6 | import org.apache.commons.lang3.StringUtils;
7 | import org.apache.curator.framework.CuratorFramework;
8 | import org.apache.curator.framework.CuratorFrameworkFactory;
9 | import org.apache.curator.framework.api.ACLBackgroundPathAndBytesable;
10 | import org.apache.curator.framework.api.BackgroundPathable;
11 | import org.apache.curator.framework.api.CuratorWatcher;
12 | import org.apache.curator.retry.RetryNTimes;
13 | import org.apache.log4j.LogManager;
14 | import org.apache.log4j.Logger;
15 | import org.apache.zookeeper.CreateMode;
16 | import org.apache.zookeeper.ZooDefs;
17 | import org.apache.zookeeper.data.ACL;
18 | import org.apache.zookeeper.data.Id;
19 | import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
20 |
21 | import java.security.NoSuchAlgorithmException;
22 | import java.sql.Timestamp;
23 | import java.text.DateFormat;
24 | import java.text.SimpleDateFormat;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 |
28 | /**
29 | * ━━━━━━神兽出没━━━━━━
30 | * ┏┓ ┏┓
31 | * ┏┛┻━━━┛┻┓
32 | * ┃ ┃
33 | * ┃ ━ ┃
34 | * ┃ ┳┛ ┗┳ ┃
35 | * ┃ ┃
36 | * ┃ ┻ ┃
37 | * ┃ ┃
38 | * ┗━┓ ┏━┛
39 | * ┃ ┃神兽保佑, 永无BUG!
40 | * ┃ ┃Code is far away from bug with the animal protecting
41 | * ┃ ┗━━━┓
42 | * ┃ ┣┓
43 | * ┃ ┏┛
44 | * ┗┓┓┏━┳┓┏┛
45 | * ┃┫┫ ┃┫┫
46 | * ┗┻┛ ┗┻┛
47 | * ━━━━━━感觉萌萌哒━━━━━━
48 | * Summary: ZKUtil
49 | * Author : anduo@qq.com
50 | * Version: 1.0
51 | * Date : 15/7/2
52 | * time : 00:50
53 | */
54 | public class ZKUtil {
55 |
56 | private static final Logger LOGGER = LogManager.getLogger(ConfigFile.class);
57 |
58 | private static List acl = new ArrayList();
59 |
60 | public static CuratorFramework create() {
61 | RetryNTimes retryPolicy = new RetryNTimes(5, 5000);
62 | String authString = Constants.ZK_USER_NAME + ":" + Constants.ZK_PASSWORD;
63 | CuratorFramework client = CuratorFrameworkFactory.builder().connectString(Constants.ZK_CONNECT_STRING)
64 | .retryPolicy(retryPolicy)
65 | .connectionTimeoutMs(Constants.ZOO_KEEPER_TIMEOUT)
66 | .sessionTimeoutMs(Constants.ZOO_KEEPER_TIMEOUT * 3)
67 | .authorization("digest", authString.getBytes()).build();
68 | try {
69 | acl.clear();
70 | acl.add(new ACL(ZooDefs.Perms.ALL,
71 | new Id("digest", DigestAuthenticationProvider.generateDigest(authString))));
72 | acl.add(new ACL(ZooDefs.Perms.READ, ZooDefs.Ids.ANYONE_ID_UNSAFE));
73 | } catch (NoSuchAlgorithmException e) {
74 | e.printStackTrace();
75 | LOGGER.error("ZKUtil-->>create() error,", e);
76 | }
77 | return client;
78 | }
79 |
80 | public static boolean exists(CuratorFramework client, String path, CuratorWatcher watcher) {
81 | try {
82 | if (watcher != null) {
83 | return ((BackgroundPathable) client.checkExists().usingWatcher(watcher)).forPath(path) != null;
84 | }
85 | return client.checkExists().forPath(path) != null;
86 | } catch (Exception e) {
87 | LOGGER.error("ZKUtil-->>exists(CuratorFramework client, String path, CuratorWatcher watcher) error, ", e);
88 | }
89 | return false;
90 | }
91 |
92 | public static boolean exists(CuratorFramework client, String path) {
93 | return exists(client, path, null);
94 | }
95 |
96 | public static void createPath(CuratorFramework client, String path, String content, CreateMode mode) {
97 | try {
98 | ((ACLBackgroundPathAndBytesable) client.create().creatingParentsIfNeeded().withMode(mode))
99 | .forPath(path, List2StringUtil.toBytes(content));
100 | } catch (Exception e) {
101 | LOGGER.error("ZKUtil-->>createPath(CuratorFramework client, String path, String content, CreateMode mode) error,", e);
102 | }
103 | }
104 |
105 | public static void setPath(CuratorFramework client, String path, String content, CreateMode mode) {
106 | try {
107 | if (client.checkExists().forPath(path) == null) {
108 | ((ACLBackgroundPathAndBytesable) client.create().creatingParentsIfNeeded().withMode(mode))
109 | .forPath(path, List2StringUtil.toBytes(content));
110 | } else { client.setData().forPath(path, List2StringUtil.toBytes(content)); }
111 | } catch (Exception e) {
112 | LOGGER.error("ZKUtil-->>setPath(CuratorFramework client, String path, String content, CreateMode mode) error,", e);
113 | }
114 | }
115 |
116 | public static void updateServerTimestamp(long timestamp, String key) {
117 | if (timestamp == 0L) { return; }
118 | DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
119 | Timestamp startime = new Timestamp(timestamp);
120 | String startDate = format.format(startime);
121 | setPath(ServerDict.self.getZK(), key, String.valueOf(timestamp), CreateMode.PERSISTENT);
122 | logger.info("ZKUtil-->> update key[{}] timestamp[{}] ", new Object[] { key, startDate });
123 | }
124 |
125 | public static long readServerTimestamp(String key) {
126 | String c = getData(ServerDict.self.getZK(), key);
127 | if (StringUtils.isEmpty(c)) {
128 | return 0L;
129 | }
130 | return Long.parseLong(c);
131 | }
132 |
133 | public static String getData(CuratorFramework client, String path) {
134 | return getData(client, path, null);
135 | }
136 |
137 | public static String getData(CuratorFramework client, String path, CuratorWatcher watcher) {
138 | try {
139 | if (client.checkExists().forPath(path) == null) {
140 | return null;
141 | }
142 | if (watcher != null) {
143 | return List2StringUtil
144 | .toString((byte[]) ((BackgroundPathable) client.getData().usingWatcher(watcher)).forPath(path));
145 | }
146 | return List2StringUtil.toString((byte[]) client.getData().forPath(path));
147 | } catch (Exception e) {
148 | LOGGER.error("ZKUtil-->>getData(CuratorFramework client, String path, CuratorWatcher watcher) error ", e);
149 | }
150 | return null;
151 | }
152 |
153 | public static String createEphemeralSequential(CuratorFramework client, String path, byte[] payload) {
154 | try {
155 | return (String) ((ACLBackgroundPathAndBytesable) client.create().withProtection()
156 | .withMode(CreateMode.EPHEMERAL_SEQUENTIAL))
157 | .forPath(path, payload);
158 | } catch (Exception e) {
159 | LOGGER.error("ZKUtil-->>createEphemeralSequential", e);
160 | }
161 | return null;
162 | }
163 |
164 | public static void remove(CuratorFramework client, String path) {
165 | try {
166 | if (client.checkExists().forPath(path) == null) {
167 | LOGGER.info("ZKUtil-->>remove(CuratorFramework client, String path) this Path not exists");
168 | }
169 | client.delete().forPath(path);
170 | } catch (Exception e) {
171 | LOGGER.error("ZKUtil-->>remove(CuratorFramework client, String path) error,", e);
172 | }
173 | }
174 |
175 | public static void delete(CuratorFramework client, String path) {
176 | try {
177 | client.delete().guaranteed().forPath(path);
178 | } catch (Exception e) {
179 | LOGGER.error("ZKUtil-->>delete(CuratorFramework client, String path) error,", e);
180 | }
181 | }
182 |
183 | public static List getChilds(CuratorFramework client, String path) {
184 | return getChilds(client, path, null);
185 | }
186 |
187 | public static List getChilds(CuratorFramework client, String path, CuratorWatcher watcher) {
188 | try {
189 | if (watcher != null) {
190 | return (List) ((BackgroundPathable) client.getChildren().usingWatcher(watcher)).forPath(path);
191 | }
192 | return (List) client.getChildren().forPath(path);
193 | } catch (Exception e) {
194 | LOGGER.error("ZKUtil-->>getChilds(CuratorFramework client, String path, CuratorWatcher watcher) error,", e);
195 | }
196 | return null;
197 | }
198 |
199 | public static String getDataByParameter(String path, String qKey, String qValue, String resultValue) {
200 | CuratorFramework curatorFramework = ZKUtil.create();
201 | if (!curatorFramework.isStarted()) { curatorFramework.start(); }
202 | List nodeList = ZKUtil.getChilds(curatorFramework, path);
203 | for (int i = 0; (nodeList != null) && (i < nodeList.size()); i++) {
204 | String id = (String) nodeList.get(i);
205 | String c = ZKUtil.getData(curatorFramework, path + "/" + id);
206 | if (c == null) {
207 | continue;
208 | }
209 | BasicDBObject record = (BasicDBObject) com.mongodb.util.JSON.parse(c);
210 | String tempValue = (String) record.get(qKey);
211 | if (tempValue.equals(qValue)) {
212 | return (String) record.get(resultValue);
213 | } else {
214 | continue;
215 | }
216 | }
217 | return null;
218 | }
219 |
220 | public static BasicDBObject getDataByParameter(String path, String qKey, String qValue) {
221 | CuratorFramework curatorFramework = ZKUtil.create();
222 | List nodeList = ZKUtil.getChilds(curatorFramework, path);
223 | for (int i = 0; (nodeList != null) && (i < nodeList.size()); i++) {
224 | String id = (String) nodeList.get(i);
225 | String c = ZKUtil.getData(curatorFramework, path + "/" + id);
226 | if (c == null) {
227 | continue;
228 | }
229 | BasicDBObject record = (BasicDBObject) com.mongodb.util.JSON.parse(c);
230 | String tempValue = (String) record.get(qKey);
231 | if (tempValue.equals(qValue)) {
232 | return record;
233 | } else {
234 | continue;
235 | }
236 | }
237 | return null;
238 | }
239 |
240 | public static void main(String[] args) {
241 | ZKUtil.setPath(ClientDict.self.getZK(), "/test/wy/test1", "test2", CreateMode.EPHEMERAL);
242 |
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/nz-server/src/test/java/com/anduo/nz/netty/DiscardServer.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty;
4 |
5 | import io.netty.bootstrap.ServerBootstrap;
6 | import io.netty.channel.ChannelFuture;
7 | import io.netty.channel.ChannelInitializer;
8 | import io.netty.channel.ChannelOption;
9 | import io.netty.channel.EventLoopGroup;
10 | import io.netty.channel.nio.NioEventLoopGroup;
11 | import io.netty.channel.socket.SocketChannel;
12 | import io.netty.channel.socket.nio.NioServerSocketChannel;
13 |
14 | /**
15 | * Summary: netty测试
16 | * Author : anduo@qq.com
17 | * Version: 1.0
18 | * Date : 15/7/1
19 | * time : 22:34
20 | */
21 | public class DiscardServer {
22 | private int port;
23 |
24 | public DiscardServer(int port) {
25 | this.port = port;
26 | }
27 |
28 | public void run()
29 | throws Exception {
30 | EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
31 | EventLoopGroup workerGroup = new NioEventLoopGroup();
32 | try {
33 | ServerBootstrap b = new ServerBootstrap(); // (2)
34 | b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // (3)
35 | .childHandler(new ChannelInitializer() { // (4)
36 | @Override
37 | public void initChannel(SocketChannel ch)
38 | throws Exception {
39 | ch.pipeline().addLast(new DiscardServerHandler());
40 | }
41 | }).option(ChannelOption.SO_BACKLOG, 128) // (5)
42 | .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
43 |
44 | // Bind and start to accept incoming connections.
45 | ChannelFuture f = b.bind(port).sync(); // (7)
46 |
47 | // Wait until the server socket is closed.
48 | // In this example, this does not happen, but you can do that to gracefully
49 | // shut down your server.
50 | f.channel().closeFuture().sync();
51 | } finally {
52 | workerGroup.shutdownGracefully();
53 | bossGroup.shutdownGracefully();
54 | }
55 | }
56 |
57 | public static void main(String[] args)
58 | throws Exception {
59 | int port;
60 | if (args.length > 0) {
61 | port = Integer.parseInt(args[0]);
62 | } else {
63 | port = 8080;
64 | }
65 | new DiscardServer(port).run();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/nz-server/src/test/java/com/anduo/nz/netty/DiscardServerHandler.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty;
4 |
5 | /**
6 | * Summary: handler
7 | * Author : anduo@qq.com
8 | * Version: 1.0
9 | * Date : 15/7/1
10 | * time : 22:36
11 | */
12 |
13 | import io.netty.buffer.ByteBuf;
14 | import io.netty.channel.ChannelHandlerContext;
15 | import io.netty.channel.ChannelInboundHandlerAdapter;
16 | import io.netty.util.ReferenceCountUtil;
17 |
18 | /**
19 | * Handles a server-side channel.
20 | */
21 | public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1)
22 |
23 | @Override
24 | public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
25 | // Discard the received data silently.
26 | ((ByteBuf) msg).release(); // (3)
27 | ByteBuf in = (ByteBuf) msg;
28 | try {
29 | while (in.isReadable()) { // (1)
30 | System.out.print((char) in.readByte());
31 | System.out.flush();
32 | }
33 | } finally {
34 | ReferenceCountUtil.release(msg); // (2)
35 | }
36 | }
37 |
38 | @Override
39 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
40 | // Close the connection when an exception is raised.
41 | cause.printStackTrace();
42 | ctx.close();
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/nz-server/src/test/java/com/anduo/nz/netty/HelloWorldClient.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty;
4 |
5 | import io.netty.bootstrap.Bootstrap;
6 | import io.netty.channel.*;
7 | import io.netty.channel.nio.NioEventLoopGroup;
8 | import io.netty.channel.socket.SocketChannel;
9 | import io.netty.channel.socket.nio.NioSocketChannel;
10 | import io.netty.handler.codec.serialization.ClassResolvers;
11 | import io.netty.handler.codec.serialization.ObjectDecoder;
12 | import io.netty.handler.codec.serialization.ObjectEncoder;
13 | import io.netty.handler.ssl.SslContext;
14 | import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
15 |
16 | /**
17 | * Summary: HelloWorldClient
18 | * Author : anduo@qq.com
19 | * Version: 1.0
20 | * Date : 15/7/1
21 | * time : 23:15
22 | */
23 | public class HelloWorldClient {
24 | static final boolean SSL = System.getProperty("ssl") != null;
25 | static final String HOST = System.getProperty("host", "127.0.0.1");
26 | static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
27 |
28 | public static void main(String[] args)
29 | throws Exception {
30 | // Configure SSL.git
31 | final SslContext sslCtx;
32 | if (SSL) {
33 | sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
34 | } else {
35 | sslCtx = null;
36 | }
37 |
38 | // Configure the client.
39 | EventLoopGroup group = new NioEventLoopGroup();
40 | try {
41 | Bootstrap bootstrap = new Bootstrap();
42 | bootstrap.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)
43 | .handler(new ChannelInitializer() {
44 | @Override
45 | public void initChannel(SocketChannel ch)
46 | throws Exception {
47 | ChannelPipeline p = ch.pipeline();
48 | if (sslCtx != null) {
49 | p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
50 | }
51 | p.addLast(new ObjectEncoder(),
52 | new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
53 | new HelloWorldClientHandler());
54 | }
55 | });
56 |
57 | // Start the client.
58 | ChannelFuture channelFuture = bootstrap.connect(HOST, PORT).sync();
59 |
60 | // Wait until the connection is closed.
61 | channelFuture.channel().closeFuture().sync();
62 | } finally {
63 | // Shut down the event loop to terminate all threads.
64 | group.shutdownGracefully();
65 | }
66 | }
67 | }
68 |
69 | class HelloWorldClientHandler extends ChannelInboundHandlerAdapter {
70 |
71 | private final String msg = "hello java world";
72 |
73 | /**
74 | * Creates a client-side handler.
75 | */
76 | public HelloWorldClientHandler() {
77 | //TODO
78 | }
79 |
80 | @Override
81 | public void channelActive(ChannelHandlerContext ctx) {
82 | ctx.writeAndFlush(msg);
83 | }
84 |
85 | @Override
86 | public void channelRead(ChannelHandlerContext ctx, Object msg) {
87 | System.out.println(msg);
88 | }
89 |
90 | @Override
91 | public void channelReadComplete(ChannelHandlerContext ctx) {
92 | ctx.flush();
93 | }
94 |
95 | @Override
96 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
97 | // Close the connection when an exception is raised.
98 | cause.printStackTrace();
99 | ctx.close();
100 | }
101 |
102 | @Override
103 | public void channelInactive(ChannelHandlerContext ctx)
104 | throws Exception {
105 | System.out.println("hello this is client");
106 |
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/nz-server/src/test/java/com/anduo/nz/netty/HelloWorldServer.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty;
4 |
5 | import io.netty.bootstrap.ServerBootstrap;
6 | import io.netty.channel.*;
7 | import io.netty.channel.nio.NioEventLoopGroup;
8 | import io.netty.channel.socket.SocketChannel;
9 | import io.netty.channel.socket.nio.NioServerSocketChannel;
10 | import io.netty.handler.codec.serialization.ClassResolvers;
11 | import io.netty.handler.codec.serialization.ObjectDecoder;
12 | import io.netty.handler.codec.serialization.ObjectEncoder;
13 | import io.netty.handler.logging.LogLevel;
14 | import io.netty.handler.logging.LoggingHandler;
15 | import io.netty.handler.ssl.SslContext;
16 | import io.netty.handler.ssl.util.SelfSignedCertificate;
17 |
18 | /**
19 | * Summary: HelloWorldServer
20 | * Author : anduo@qq.com
21 | * Version: 1.0
22 | * Date : 15/7/1
23 | * time : 23:13
24 | */
25 | public class HelloWorldServer {
26 | static final boolean SSL = System.getProperty("ssl") != null;
27 | static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
28 |
29 | public static void main(String[] args)
30 | throws Exception {
31 | // Configure SSL.
32 | final SslContext sslCtx;
33 | if (SSL) {
34 | SelfSignedCertificate ssc = new SelfSignedCertificate();
35 | sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
36 | } else {
37 | sslCtx = null;
38 | }
39 |
40 | // Configure the server.
41 | EventLoopGroup bossGroup = new NioEventLoopGroup(1);
42 | EventLoopGroup workerGroup = new NioEventLoopGroup();
43 | try {
44 | ServerBootstrap server = new ServerBootstrap();
45 | server.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
46 | .option(ChannelOption.SO_BACKLOG, 100).handler(new LoggingHandler(LogLevel.INFO))
47 | .childHandler(new ChannelInitializer() {
48 | @Override
49 | public void initChannel(SocketChannel ch)
50 | throws Exception {
51 | ChannelPipeline p = ch.pipeline();
52 | if (sslCtx != null) {
53 | p.addLast(sslCtx.newHandler(ch.alloc()));
54 | }
55 | p.addLast(new LoggingHandler(LogLevel.INFO));
56 | p.addLast(new ObjectEncoder(),
57 | new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
58 | new HelloWorldServerHandler());
59 | }
60 | });
61 |
62 | // Start the server.
63 | ChannelFuture f = server.bind(PORT).sync();
64 |
65 | // Wait until the server socket is closed.
66 | f.channel().closeFuture().sync();
67 | } finally {
68 | // Shut down all event loops to terminate all threads.
69 | bossGroup.shutdownGracefully();
70 | workerGroup.shutdownGracefully();
71 | }
72 | }
73 | }
74 |
75 | class HelloWorldServerHandler extends ChannelInboundHandlerAdapter {
76 |
77 | @Override
78 | public void channelRead(ChannelHandlerContext ctx, Object msg) {
79 | ctx.write("server write msg:" + msg);
80 | }
81 |
82 | @Override
83 | public void channelReadComplete(ChannelHandlerContext ctx) {
84 | ctx.flush();
85 | }
86 |
87 | @Override
88 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
89 | // Close the connection when an exception is raised.
90 | cause.printStackTrace();
91 | ctx.close();
92 | }
93 |
94 | //当绑定到服务端的时候触发
95 | @Override
96 | public void channelActive(ChannelHandlerContext ctx)
97 | throws Exception {
98 | System.out.println("hello this is server!");
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/nz-server/src/test/java/com/anduo/nz/netty/TimeClient.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty;
4 |
5 | import io.netty.bootstrap.Bootstrap;
6 | import io.netty.channel.ChannelFuture;
7 | import io.netty.channel.ChannelInitializer;
8 | import io.netty.channel.ChannelOption;
9 | import io.netty.channel.EventLoopGroup;
10 | import io.netty.channel.nio.NioEventLoopGroup;
11 | import io.netty.channel.socket.SocketChannel;
12 | import io.netty.channel.socket.nio.NioSocketChannel;
13 |
14 | /**
15 | * Summary: TODO 描述信息
16 | * Author : anduo@qq.com
17 | * Version: 1.0
18 | * Date : 15/7/1
19 | * time : 22:40
20 | */
21 | public class TimeClient {
22 | public static void main(String[] args) throws Exception {
23 | String host = "127.0.0.1";//args[0];
24 | int port = 8080;//Integer.parseInt(args[1]);
25 | EventLoopGroup workerGroup = new NioEventLoopGroup();
26 |
27 | try {
28 | Bootstrap b = new Bootstrap(); // (1)
29 | b.group(workerGroup); // (2)
30 | b.channel(NioSocketChannel.class); // (3)
31 | b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
32 | b.handler(new ChannelInitializer() {
33 | @Override
34 | public void initChannel(SocketChannel ch)
35 | throws Exception {
36 | ch.pipeline().addLast(new TimeClientHandler());
37 | }
38 | });
39 |
40 | // Start the client.
41 | ChannelFuture f = b.connect(host, port).sync(); // (5)
42 |
43 | // Wait until the connection is closed.
44 | f.channel().closeFuture().sync();
45 | } finally {
46 | workerGroup.shutdownGracefully();
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/nz-server/src/test/java/com/anduo/nz/netty/TimeClientHandler.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty;
4 |
5 | import io.netty.buffer.ByteBuf;
6 | import io.netty.channel.ChannelHandlerContext;
7 | import io.netty.channel.ChannelInboundHandlerAdapter;
8 |
9 | import java.util.Date;
10 |
11 | /**
12 | * Summary: TODO 描述信息
13 | * Author : anduo@qq.com
14 | * Version: 1.0
15 | * Date : 15/7/1
16 | * time : 22:41
17 | */
18 | public class TimeClientHandler extends ChannelInboundHandlerAdapter {
19 | private ByteBuf buf;
20 |
21 | @Override
22 | public void handlerAdded(ChannelHandlerContext ctx) {
23 | buf = ctx.alloc().buffer(4); // (1)
24 | }
25 |
26 | @Override
27 | public void handlerRemoved(ChannelHandlerContext ctx) {
28 | buf.release(); // (1)
29 | buf = null;
30 | }
31 |
32 | @Override
33 | public void channelRead(ChannelHandlerContext ctx, Object msg) {
34 | ByteBuf m = (ByteBuf) msg;
35 | buf.writeBytes(m); // (2)
36 | m.release();
37 |
38 | if (buf.readableBytes() >= 4) { // (3)
39 | long currentTimeMillis = (buf.readUnsignedInt() - 2208988800L) * 1000L;
40 | System.out.println(new Date(currentTimeMillis));
41 | ctx.close();
42 | }
43 | }
44 |
45 | @Override
46 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
47 | cause.printStackTrace();
48 | ctx.close();
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/nz-server/src/test/java/com/anduo/nz/netty/TimeServerHandler.java:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2015 anduo
2 | // All rights reserved
3 | package com.anduo.nz.netty;
4 |
5 | import io.netty.buffer.ByteBuf;
6 | import io.netty.channel.ChannelFuture;
7 | import io.netty.channel.ChannelFutureListener;
8 | import io.netty.channel.ChannelHandlerContext;
9 | import io.netty.channel.ChannelInboundHandlerAdapter;
10 |
11 | /**
12 | * Summary: TimeServerHandler
13 | * Author : anduo@qq.com
14 | * Version: 1.0
15 | * Date : 15/7/1
16 | * time : 22:39
17 | */
18 | public class TimeServerHandler extends ChannelInboundHandlerAdapter {
19 | @Override
20 | public void channelActive(final ChannelHandlerContext ctx) { // (1)
21 | final ByteBuf time = ctx.alloc().buffer(4); // (2)
22 | time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L));
23 |
24 | final ChannelFuture f = ctx.writeAndFlush(time); // (3)
25 | f.addListener(new ChannelFutureListener() {
26 | @Override
27 | public void operationComplete(ChannelFuture future) {
28 | assert f == future;
29 | ctx.close();
30 | }
31 | }); // (4)
32 | }
33 |
34 | @Override
35 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
36 | cause.printStackTrace();
37 | ctx.close();
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.anduo
8 | nz
9 | pom
10 | 1.0-SNAPSHOT
11 |
12 | nz-server
13 | nz-client
14 |
15 |
16 |
17 | 3.7.0.Final
18 | 3.4.6
19 | 2.3
20 | 1.8
21 |
22 |
23 |
24 |
25 |
26 |
27 | io.netty
28 | netty-all
29 | 4.0.24.Final
30 |
31 |
32 | com.google.guava
33 | guava
34 | 18.0
35 |
36 |
37 |
38 | org.apache.curator
39 | curator-recipes
40 | 2.8.0
41 |
42 |
43 | slf4j-log4j12
44 | org.slf4j
45 |
46 |
47 | log4j
48 | log4j
49 |
50 |
51 | netty
52 | org.jboss.netty
53 |
54 |
55 |
56 |
57 |
58 |
59 | org.apache.commons
60 | commons-lang3
61 | 3.4
62 |
63 |
64 |
65 | com.alibaba
66 | fastjson
67 | 1.2.6
68 |
69 |
70 |
71 | net.coobird
72 | thumbnailator
73 | 0.4.8
74 |
75 |
76 |
77 | log4j
78 | log4j
79 | 1.2.17
80 |
81 |
82 | org.slf4j
83 | slf4j-log4j12
84 | 1.7.12
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------