├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── dictionaries
│ └── zhza4586.xml
├── encodings.xml
├── libraries
│ ├── Maven__aopalliance_aopalliance_1_0.xml
│ ├── Maven__ch_qos_logback_logback_classic_1_0_13.xml
│ ├── Maven__ch_qos_logback_logback_core_1_0_13.xml
│ ├── Maven__com_google_guava_guava_15_0.xml
│ ├── Maven__com_google_protobuf_protobuf_java_2_5_0.xml
│ ├── Maven__com_ning_async_http_client_1_9_0_BETA23.xml
│ ├── Maven__commons_logging_commons_logging_1_1_1.xml
│ ├── Maven__commons_pool_commons_pool_1_6.xml
│ ├── Maven__io_netty_netty_3_9_5_Final.xml
│ ├── Maven__io_netty_netty_all_4_0_23_Final.xml
│ ├── Maven__jline_jline_0_9_94.xml
│ ├── Maven__junit_junit_3_8_1.xml
│ ├── Maven__org_apache_commons_commons_lang3_3_2_1.xml
│ ├── Maven__org_apache_curator_curator_client_2_6_0.xml
│ ├── Maven__org_apache_curator_curator_framework_2_6_0.xml
│ ├── Maven__org_apache_curator_curator_recipes_2_6_0.xml
│ ├── Maven__org_apache_zookeeper_zookeeper_3_4_6.xml
│ ├── Maven__org_slf4j_jul_to_slf4j_1_5_11.xml
│ ├── Maven__org_slf4j_slf4j_api_1_7_5.xml
│ ├── Maven__org_springframework_spring_aop_4_0_0_RELEASE.xml
│ ├── Maven__org_springframework_spring_beans_4_0_0_RELEASE.xml
│ ├── Maven__org_springframework_spring_context_4_0_0_RELEASE.xml
│ ├── Maven__org_springframework_spring_core_4_0_0_RELEASE.xml
│ ├── Maven__org_springframework_spring_expression_4_0_0_RELEASE.xml
│ ├── Maven__org_yaml_snakeyaml_1_13.xml
│ └── Maven__redis_clients_jedis_2_2_1.xml
├── misc.xml
├── modules.xml
├── scopes
│ └── scope_settings.xml
├── uiDesigner.xml
├── vcs.xml
└── workspace.xml
├── NewIM.iml
├── README.md
├── demo
├── demo.iml
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── whosbean
│ │ │ ├── App.java
│ │ │ └── ChatClient.java
│ └── resources
│ │ └── logback.xml
│ └── test
│ └── java
│ └── com
│ └── whosbean
│ └── AppTest.java
├── newim-chat
├── bin
│ ├── copy.sh
│ ├── scpfile.sh
│ └── start.sh
├── newim-chat.iml
├── pom.xml
└── src
│ ├── main
│ ├── assembly
│ │ └── chatter.xml
│ ├── java
│ │ └── com
│ │ │ └── whosbean
│ │ │ └── newim
│ │ │ ├── ChatterMain.java
│ │ │ └── chatter
│ │ │ ├── ChatterConfig.java
│ │ │ ├── RouterServerNode.java
│ │ │ ├── exchange
│ │ │ ├── ExchangeClient.java
│ │ │ └── ExchangeClientManager.java
│ │ │ └── router
│ │ │ ├── BoxMsgListenThread.java
│ │ │ ├── ChatMessageListener.java
│ │ │ ├── NewMemberNotifyThread.java
│ │ │ └── NewMessageNotifyThread.java
│ └── resources
│ │ ├── chatter.yaml
│ │ ├── logback.xml
│ │ ├── redis.yaml
│ │ ├── spring-chatter.xml
│ │ └── zookeeper.yaml
│ └── test
│ └── java
│ └── com
│ └── whosbean
│ └── AppTest.java
├── newim-common
├── newim-common.iml
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── whosbean
│ │ │ └── newim
│ │ │ ├── common
│ │ │ └── AppContextHolder.java
│ │ │ ├── config
│ │ │ ├── AbstractConfig.java
│ │ │ └── ConfigYamlManager.java
│ │ │ ├── redis
│ │ │ ├── RedisBucket.java
│ │ │ ├── RedisConfig.java
│ │ │ └── RedisMessageService.java
│ │ │ ├── server
│ │ │ ├── ChatServerNode.java
│ │ │ ├── ServerNode.java
│ │ │ ├── ServerNodeRoles.java
│ │ │ └── ServerStarter.java
│ │ │ ├── service
│ │ │ ├── ChatMessageService.java
│ │ │ └── ChatMessageServiceFactory.java
│ │ │ └── zookeeper
│ │ │ ├── ZKPaths.java
│ │ │ └── ZookeeperConfig.java
│ └── resources
│ │ ├── redis.yaml
│ │ └── zookeeper.yaml
│ └── test
│ └── java
│ └── com
│ └── whosbean
│ └── AppTest.java
├── newim-gateway
├── bin
│ ├── copy.sh
│ ├── scpfile.sh
│ └── start.sh
├── newim-gateway.iml
├── pom.xml
└── src
│ ├── main
│ ├── assembly
│ │ └── gateway.xml
│ ├── java
│ │ └── com
│ │ │ └── whosbean
│ │ │ └── newim
│ │ │ ├── GatewayMain.java
│ │ │ └── gateway
│ │ │ ├── GatewayConfig.java
│ │ │ ├── GatewayServerNode.java
│ │ │ ├── connection
│ │ │ ├── ChannelsHolder.java
│ │ │ └── WebSession.java
│ │ │ ├── exchange
│ │ │ └── MessageExchangeHandler.java
│ │ │ └── handler
│ │ │ ├── ChannelAttributes.java
│ │ │ ├── HttpSessionHandler.java
│ │ │ ├── WsConnectedHandler.java
│ │ │ ├── WsMessageHandler.java
│ │ │ └── WsServerProtocolHandler.java
│ └── resources
│ │ ├── gateway.yaml
│ │ ├── logback.xml
│ │ ├── redis.yaml
│ │ ├── spring-gateway.xml
│ │ └── zookeeper.yaml
│ └── test
│ └── java
│ └── com
│ └── whosbean
│ └── AppTest.java
├── newim-pb
├── newim-pb.iml
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── whosbean
│ │ │ └── newim
│ │ │ └── entity
│ │ │ ├── ChatMessage.java
│ │ │ ├── ChatMessageOrBuilder.java
│ │ │ ├── ChatStatus.java
│ │ │ ├── ChatStatusOrBuilder.java
│ │ │ ├── EntitySchema.java
│ │ │ ├── ExchangeMessage.java
│ │ │ └── ExchangeMessageOrBuilder.java
│ ├── pb
│ │ ├── entity_schema.pb.cc
│ │ ├── entity_schema.pb.h
│ │ └── entity_schema.proto
│ └── resources
│ │ ├── redis.yaml
│ │ └── zookeeper.yaml
│ └── test
│ └── java
│ └── com
│ └── whosbean
│ └── AppTest.java
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── whosbean
│ └── App.java
└── test
└── java
└── com
└── whosbean
└── AppTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .gitignore support plugin (hsz.mobi)
2 | ### Java template
3 | *.class
4 |
5 | # Mobile Tools for Java (J2ME)
6 | .mtj.tmp/
7 |
8 | # Package Files #
9 | *.jar
10 | *.war
11 | *.ear
12 |
13 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
14 | hs_err_pid*
15 | logs
16 | target
17 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | NewIM
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/dictionaries/zhza4586.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__aopalliance_aopalliance_1_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_0_13.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__ch_qos_logback_logback_core_1_0_13.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__com_google_guava_guava_15_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__com_google_protobuf_protobuf_java_2_5_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__com_ning_async_http_client_1_9_0_BETA23.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__commons_logging_commons_logging_1_1_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__commons_pool_commons_pool_1_6.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__io_netty_netty_3_9_5_Final.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__io_netty_netty_all_4_0_23_Final.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__jline_jline_0_9_94.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__junit_junit_3_8_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_2_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_apache_curator_curator_client_2_6_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_apache_curator_curator_framework_2_6_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_apache_curator_curator_recipes_2_6_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_apache_zookeeper_zookeeper_3_4_6.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_5_11.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_aop_4_0_0_RELEASE.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_beans_4_0_0_RELEASE.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_context_4_0_0_RELEASE.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_core_4_0_0_RELEASE.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_expression_4_0_0_RELEASE.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_yaml_snakeyaml_1_13.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__redis_clients_jedis_2_2_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Abstraction issues
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 | -
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
92 |
93 |
94 | -
95 |
96 |
97 |
98 |
99 | -
100 |
101 |
102 | -
103 |
104 |
105 | -
106 |
107 |
108 | -
109 |
110 |
111 | -
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | -
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/NewIM.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | NewIM
2 | =====
3 |
4 | This is a simple NewIM, created for Mobile App.
5 | by using Netty + WebSocket, Zookeeper, Redis and Protobuf.
6 |
7 | ### Gateway
8 | this node receives connections from Mobile and holds them, receives message from Mobile and then deliver the message to Chat Node.
9 | It uses zookeeper to store connection info.
10 |
11 | ### Chat
12 | this node routes message to all those mobile client in P2P, P2G way.
13 | it uses Zookeeper to get connections on Gateway node.
14 |
15 | ### Zookeeper
16 | it is a No 1 component in NewIM. it can deliver updates to clients in less than a second and support HA.
17 | so it is a Keeper.
18 |
19 | ### Redis
20 | this is where message save when Gateway got those messages.
21 |
22 |
23 | ### Protobuf Definition
24 | App talks to Gateway with Protobuf, Gateway sends messages to App with Protobuf.
25 | Gateway talks to Chat Node with Protobuf.
26 |
27 | ```
28 | message ChatMessage {
29 | required string boxid = 1;
30 | required int32 group = 2 [default = 0];
31 | optional string uuid = 3;
32 | optional string sender = 4;
33 | optional string receiver = 5;
34 | optional string body = 6;
35 | enum MessageType {
36 | SmallText = 0;
37 | LongText = 1;
38 | AUDIO = 2;
39 | IMAGE = 3;
40 | VIDEO = 4;
41 | FILE = 5;
42 | LINK = 6;
43 | SYNC = 7;
44 | }
45 | required MessageType mtype = 7 [default = SYNC];
46 |
47 | enum ChatOp {
48 | JOIN = 0;
49 | QUIT = 1;
50 | CHAT = 2;
51 | ACK = 3;
52 | }
53 | required ChatOp op = 8 [default = ACK];
54 | }
55 |
56 | message ChatStatus {
57 | required string sender = 1;
58 | required int32 syncMark = 2;
59 | }
60 |
61 | message ExchangeMessage {
62 | required string messageId = 1;
63 | optional string message = 2;
64 | optional string chatPath = 3;
65 | optional string chatRoomId = 4;
66 | optional string msgPath = 5;
67 | repeated int32 channelId = 6;
68 | }
69 |
70 | ```
71 |
72 | ### TODO
73 | 1. receive image, audio, video file from clients
74 | 2. support node monitor
--------------------------------------------------------------------------------
/demo/demo.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/demo/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | newim
5 | com.whosbean
6 | 1.0-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | newim-demo
11 | jar
12 |
13 | newim-demo
14 | http://maven.apache.org
15 |
16 |
17 | UTF-8
18 |
19 |
20 |
21 |
22 | junit
23 | junit
24 | 3.8.1
25 | test
26 |
27 |
28 | com.ning
29 | async-http-client
30 | 1.9.0-BETA23
31 |
32 |
33 | com.whosbean
34 | newim-pb
35 | 1.0-SNAPSHOT
36 |
37 |
38 | com.google.protobuf
39 | protobuf-java
40 | 2.5.0
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/whosbean/App.java:
--------------------------------------------------------------------------------
1 | package com.whosbean;
2 |
3 | import com.whosbean.newim.entity.ChatMessage;
4 |
5 | /**
6 | * Hello world!
7 | *
8 | */
9 | public class App
10 | {
11 |
12 | public static final String BOXID = "123";
13 | private static ChatClient cc0;
14 | private static ChatClient cc1;
15 |
16 | public static void main( String[] args ) throws Exception {
17 | System.out.println( "Hello World!" );
18 |
19 | cc0 = new ChatClient("john-1", "ws://localhost:8180/websocket");
20 | cc0.start();
21 |
22 | cc1 = new ChatClient("john-2", "ws://localhost:8180/websocket");
23 | cc1.start();
24 |
25 | System.out.println("to join chat room: " + BOXID);
26 |
27 | cc0.join(BOXID);
28 | cc1.join(BOXID);
29 |
30 | System.out.println("to send message: " + BOXID);
31 |
32 | ChatMessage.Builder message = ChatMessage.newBuilder();
33 | message.setBoxid(BOXID);
34 | message.setBody("Chat Message Body");
35 | message.setSender("john-1");
36 | message.setReceiver("john-2");
37 | message.setGroup(0);
38 | message.setOp(ChatMessage.ChatOp.CHAT);
39 | message.setMtype(ChatMessage.MessageType.SmallText);
40 |
41 | cc0.send(message.build());
42 |
43 | Thread.sleep(30 * 1000);
44 |
45 | System.out.println("DONE OK.");
46 | }
47 |
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/whosbean/ChatClient.java:
--------------------------------------------------------------------------------
1 | package com.whosbean;
2 |
3 | import com.ning.http.client.AsyncHttpClient;
4 | import com.ning.http.client.AsyncHttpClientConfig;
5 | import com.ning.http.client.cookie.Cookie;
6 | import com.ning.http.client.websocket.WebSocket;
7 | import com.ning.http.client.websocket.WebSocketByteListener;
8 | import com.ning.http.client.websocket.WebSocketUpgradeHandler;
9 | import com.whosbean.newim.entity.ChatMessage;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import java.io.IOException;
14 | import java.util.concurrent.CountDownLatch;
15 | import java.util.concurrent.ExecutionException;
16 |
17 | /**
18 | * Created by Yaming on 2014/10/17.
19 | */
20 | public class ChatClient extends Thread {
21 |
22 | protected Logger logger = null;
23 |
24 | private String url;
25 | private String uname;
26 | private AsyncHttpClient c;
27 | private WebSocket connection;
28 |
29 | private CountDownLatch countDownLatch = null;
30 |
31 | public ChatClient(String name, String url) {
32 | this.uname = name;
33 | this.url = url;
34 | logger = LoggerFactory.getLogger(ChatClient.class.getName()+"."+name);
35 | AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder().build();
36 | c = new AsyncHttpClient(cf);
37 | }
38 |
39 | public void lostConnection(){
40 |
41 | }
42 |
43 | public void close(){
44 | if(connection.isOpen()){
45 | System.out.println("closing websocket");
46 | connection.close();
47 | connection = null;
48 | System.out.println("websocket closed");
49 | }
50 | }
51 |
52 | public void join(String boxid) throws Exception {
53 | if (countDownLatch != null){
54 | countDownLatch.await();
55 | }
56 |
57 | ChatMessage.Builder chatbox = ChatMessage.newBuilder();
58 | chatbox.setBoxid(boxid);
59 | chatbox.setOp(ChatMessage.ChatOp.JOIN);
60 | chatbox.setSender(this.uname);
61 | chatbox.setGroup(0);
62 | chatbox.setMtype(ChatMessage.MessageType.SYNC);
63 | connection.sendMessage(chatbox.build().toByteArray());
64 | }
65 |
66 | public void quit(String boxid) throws Exception {
67 | if (countDownLatch != null){
68 | countDownLatch.await();
69 | }
70 |
71 | ChatMessage.Builder chatbox = ChatMessage.newBuilder();
72 | chatbox.setBoxid(boxid);
73 | chatbox.setOp(ChatMessage.ChatOp.QUIT);
74 | chatbox.setSender(this.uname);
75 | chatbox.setMtype(ChatMessage.MessageType.SYNC);
76 | connection.sendMessage(chatbox.build().toByteArray());
77 | }
78 |
79 | public void send(ChatMessage chatMessage) throws Exception {
80 | if (countDownLatch != null){
81 | countDownLatch.await();
82 | }
83 | logger.info("to send message. msg=" + chatMessage);
84 | connection.sendMessage(chatMessage.toByteArray());
85 | }
86 |
87 | @Override
88 | public void run() {
89 | try {
90 |
91 | connect();
92 |
93 | logger.info("websocket connected.");
94 | while (true){
95 | Thread.sleep(1000);
96 | }
97 |
98 | } catch (InterruptedException e) {
99 | e.printStackTrace();
100 | } catch (ExecutionException e) {
101 | e.printStackTrace();
102 | } catch (IOException e) {
103 | e.printStackTrace();
104 | }
105 |
106 | }
107 |
108 | private final WebSocketByteListener webSocketByteListener = new WebSocketByteListener() {
109 |
110 | @Override
111 | public void onMessage(byte[] message) {
112 | try {
113 | ChatMessage chatMessage = ChatMessage.parseFrom(message);
114 | logger.info("onMessage: {}", chatMessage);
115 | } catch (IOException e) {
116 | e.printStackTrace();
117 | }
118 | }
119 |
120 | @Override
121 | public void onOpen(WebSocket websocket) {
122 | connection = websocket;
123 | countDownLatch.countDown();
124 | countDownLatch = null;
125 | //byte[] message = null;
126 | //websocket.sendMessage(message);
127 | logger.info("onOpen: {}", websocket);
128 | }
129 |
130 | @Override
131 | public void onClose(WebSocket websocket) {
132 | logger.info("onClose: {}", websocket);
133 | lostConnection();
134 | }
135 |
136 | @Override
137 | public void onError(Throwable t) {
138 | logger.error("onError: ", t);
139 | }
140 |
141 | };
142 |
143 | public void connect() throws InterruptedException, ExecutionException, IOException {
144 | countDownLatch = new CountDownLatch(1);
145 | Cookie cookie = Cookie.newValidCookie("sid", uname, "127.0.0.1", uname, "/", Integer.MAX_VALUE, 0, false, true);
146 | WebSocket websocket = c.prepareGet(this.url).addCookie(cookie)
147 | .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(
148 | webSocketByteListener).build()).get();
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/demo/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | utf-8
5 |
6 |
7 | %date [%thread] %-5level %logger{50} - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 | true
15 | UTF-8
16 |
17 |
18 | logs/demo.%d{yyyy-MM-dd}.log
19 |
20 |
21 | 30
22 |
23 |
24 | %d{HH:mm:ss} [%thread] %-5level %logger{80} - %msg%n
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/demo/src/test/java/com/whosbean/AppTest.java:
--------------------------------------------------------------------------------
1 | package com.whosbean;
2 |
3 | import junit.framework.Test;
4 | import junit.framework.TestCase;
5 | import junit.framework.TestSuite;
6 |
7 | /**
8 | * Unit test for simple App.
9 | */
10 | public class AppTest
11 | extends TestCase
12 | {
13 | /**
14 | * Create the test case
15 | *
16 | * @param testName name of the test case
17 | */
18 | public AppTest( String testName )
19 | {
20 | super( testName );
21 | }
22 |
23 | /**
24 | * @return the suite of tests being tested
25 | */
26 | public static Test suite()
27 | {
28 | return new TestSuite( AppTest.class );
29 | }
30 |
31 | /**
32 | * Rigourous Test :-)
33 | */
34 | public void testApp()
35 | {
36 | assertTrue( true );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/newim-chat/bin/copy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | source /etc/profile
4 | export LC_ALL=C
5 |
6 | folder="$1"
7 | name="$2"
8 | dest="$3"
9 |
10 | echo "$folder"
11 | echo "$name"
12 | echo "$dest"
13 |
14 | user="$4"
15 | host="$5"
16 |
17 | # e.g. /data/in/zhenai/t_fw_00005/20140918
18 | cd "$folder"
19 | scp -q "$name" "$user"@"$host":"$dest"
20 |
21 | # e.g. /data/in/zhenai/t_fw_00005/20140918
22 | # to /data/up/zhenai/t_fw_00005/20140918
23 | up="${folder/\/in\///up/}"
24 | echo "up=$up"
25 | mkdir -p "$up"
26 |
27 | touch "$name.check"
28 | check="${dest/\/in//check}"
29 | echo "check=$check"
30 | scp -q "$name.check" "$user"@"$host":"$check"
31 |
32 | rm -f "$name.check"
33 |
34 | mv "$name" "$up"
35 |
36 | echo "SUCCESS"
--------------------------------------------------------------------------------
/newim-chat/bin/scpfile.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | source /etc/profile
4 | export LC_ALL=zh_CN.utf8
5 |
6 | function scpfile()
7 | {
8 | local source_file="$1/$2"
9 | local source_name="$2"
10 | local target_dir="$3"
11 | local target_name="$4"
12 |
13 | #判断是否存在源文件,存在则建立check文件
14 | if [ -f "$source_file" ]; then
15 | touch "$source_file.check"
16 | if [ $? -eq 0 ]; then
17 | scp -q "$source_file" "$target_dir/in/$target_name"
18 | if [ $? -eq 0 ]; then
19 | scp -q "$source_file.check" "$target_dir/check/$target_name.check"
20 | rm "$source_file.check"
21 | [ $? -eq 0 ] && return 0 || return 1
22 | fi
23 | else
24 | return 1
25 | fi
26 | else
27 | return 1
28 | fi
29 | }
30 |
31 | #参数 source_file: 源文件目录
32 | #参数 source_name: 源文件名称
33 | #在上传成功后,把文件移动到上传成功目录
34 | function mvfile()
35 | {
36 | local source_file="$1"
37 | local source_name="$2"
38 |
39 | upfolder="${source_file/\/in\///up/}"
40 | mkdir -p "$upfolder"
41 |
42 | mv "$source_file/$source_name" "$upfolder"
43 |
44 | }
45 |
46 | function main()
47 | {
48 | local src_file="$1"
49 | local src_name="$2"
50 | local tar_dir="$3"
51 | local tar_name="$4"
52 | local user="$5"
53 | local tar_ip="$6"
54 |
55 | scpfile "$src_file" "$src_name" "$user@$tar_ip:$tar_dir" "$tar_name"
56 | ret=$?
57 | echo "$ret"
58 |
59 | if [ $ret -eq 0 ]; then
60 | mvfile "$src_file" "$src_name"
61 | echo "SUCCESS"
62 | else
63 | echo "FAILED"
64 | fi
65 |
66 | [ $ret -eq 0 ] && return 0 || return 1
67 | }
68 |
69 | main "$1" "$2" "$3" "$4" "$5" "$6"
70 |
--------------------------------------------------------------------------------
/newim-chat/bin/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #-------------------------------------------------------------------
4 | # Mb Bootstrap Script
5 | #-------------------------------------------------------------------
6 |
7 | # find Mb home.
8 | CURR_DIR=`pwd`
9 | RESV_HOME=`pwd`
10 |
11 | echo $CURR_DIR
12 | cd $CURR_DIR
13 |
14 | if [ -z "$RESV_HOME" ] ; then
15 | echo
16 | echo Must set RESV_HOME
17 | echo
18 | exit 1
19 | fi
20 |
21 |
22 | for i in $RESV_HOME/lib/*.jar; do
23 | CLASSPATH=$i:$CLASSPATH;
24 | done
25 |
26 | CLASSPATH=$RESV_HOME/classes:$CLASSPATH
27 |
28 | DEBUG_INFO=" -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n"
29 | DEBUG=""
30 |
31 | MAIN_CLASS="bin";
32 | DEFAULT_OPTS="-server -Xms8G -Xmx8G -Xmn1G -XX:PermSize=50M -XX:MaxPermSize=50M -Xss256k -Dio.netty.leakDetectionLevel=advanced" ;
33 |
34 |
35 | DEFAULT_OPTS="$DEFAULT_OPTS -XX:+DisableExplicitGC -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=80 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:gc.log -Dfile.encoding=UTF-8"
36 | DEFAULT_OPTS="$DEFAULT_OPTS -DMB.home=\"$RESV_HOME\""
37 |
38 | echo java $DEBUG $DEFAULT_OPTS -classpath $CLASSPATH $MAIN_CLASS
39 | java $DEBUG $DEFAULT_OPTS -classpath $CLASSPATH $MAIN_CLASS &
--------------------------------------------------------------------------------
/newim-chat/newim-chat.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/newim-chat/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | newim
5 | com.whosbean
6 | 1.0-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | newim-chat
11 | jar
12 |
13 | newim-chat
14 | http://maven.apache.org
15 |
16 |
17 | UTF-8
18 |
19 |
20 |
21 |
22 | junit
23 | junit
24 | 3.8.1
25 | test
26 |
27 |
28 | com.whosbean
29 | newim-common
30 | 1.0-SNAPSHOT
31 |
32 |
33 |
34 |
35 |
36 |
37 | maven-compiler-plugin
38 |
39 | 1.6
40 | 1.6
41 |
42 |
43 |
44 | maven-assembly-plugin
45 | 2.2-beta-5
46 |
47 |
48 | src/main/assembly/chatter.xml
49 |
50 |
55 |
56 |
57 |
58 | make-assembly
59 | package
60 |
61 | single
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/newim-chat/src/main/assembly/chatter.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | server
6 |
7 | zip
8 |
9 | false
10 |
11 |
12 | false
13 | runtime
14 | lib
15 |
16 | *:sources
17 | org.apache.hadoop:*
18 | org.apache.mahout:*
19 |
20 |
21 |
22 | true
23 |
24 | org.apache.mahout:*
25 |
26 |
27 |
28 |
29 |
30 | ${basedir}/target/classes
31 | /classes
32 |
33 | *.jar
34 |
35 |
36 |
37 | ${basedir}/bin
38 | /
39 |
40 | *.jar
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/newim-chat/src/main/java/com/whosbean/newim/ChatterMain.java:
--------------------------------------------------------------------------------
1 | package com.whosbean.newim;
2 |
3 | import com.whosbean.newim.chatter.ChatterConfig;
4 | import com.whosbean.newim.server.ServerStarter;
5 | import org.springframework.context.support.ClassPathXmlApplicationContext;
6 | import org.springframework.util.Assert;
7 |
8 | /**
9 | * Created by yaming_deng on 14-9-9.
10 | */
11 | public class ChatterMain implements ServerStarter {
12 |
13 | public class ServerThread extends Thread {
14 |
15 | @Override
16 | public void run() {
17 | while (true){
18 | try {
19 | Thread.sleep(600 * 1000);
20 | } catch (InterruptedException e) {
21 | e.printStackTrace();
22 | }
23 | }
24 | }
25 | }
26 |
27 | /**
28 | * 启动推送服务 8080端口
29 | */
30 | public void start() {
31 | ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-chatter.xml");
32 | ChatterConfig prop = context.getBean("chatterConfig", ChatterConfig.class);
33 | Assert.notNull(prop, "chatterConfig bean is NULL.");
34 | new ServerThread().start();
35 | System.out.println("Chatter Node start.");
36 | }
37 |
38 | /**
39 | * 入口
40 | *
41 | * @param args
42 | */
43 | public static void main(String[] args) {
44 | new ChatterMain().start();
45 | }
46 | }
--------------------------------------------------------------------------------
/newim-chat/src/main/java/com/whosbean/newim/chatter/ChatterConfig.java:
--------------------------------------------------------------------------------
1 | package com.whosbean.newim.chatter;
2 |
3 | import com.whosbean.newim.config.AbstractConfig;
4 | import org.springframework.stereotype.Component;
5 |
6 | import java.util.Map;
7 |
8 | /**
9 | * Created by yaming_deng on 2014/9/28.
10 | */
11 | @Component
12 | public class ChatterConfig extends AbstractConfig {
13 |
14 | public static ChatterConfig current = null;
15 |
16 | private String host;
17 | private Integer port;
18 | private String sig;
19 |
20 | @Override
21 | public void afterPropertiesSet() throws Exception {
22 | super.afterPropertiesSet();
23 | current = this;
24 | this.initGatewayInfo();
25 | }
26 |
27 | @Override
28 | public String getConfName() {
29 | return "chatter";
30 | }
31 |
32 | private void initGatewayInfo(){
33 | Map server = this.get(Map.class, "server");
34 | host = (String)server.get("ip");
35 | port = (Integer)server.get("port");
36 | sig = host+":"+ port;
37 | }
38 |
39 | public String getHost() {
40 | return host;
41 | }
42 |
43 | public Integer getPort() {
44 | return port;
45 | }
46 |
47 | public String getSig() {
48 | return sig;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/newim-chat/src/main/java/com/whosbean/newim/chatter/RouterServerNode.java:
--------------------------------------------------------------------------------
1 | package com.whosbean.newim.chatter;
2 |
3 | import com.whosbean.newim.server.ServerNode;
4 | import com.whosbean.newim.server.ServerNodeRoles;
5 | import org.springframework.stereotype.Component;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * Created by yaming_deng on 14-9-9.
11 | */
12 | @Component
13 | public class RouterServerNode extends ServerNode {
14 |
15 | public static RouterServerNode current = null;
16 |
17 | @Override
18 | public void afterPropertiesSet() throws Exception {
19 | super.afterPropertiesSet();
20 | current = this;
21 | }
22 |
23 | @Override
24 | protected String getRole() {
25 | return ServerNodeRoles.ROLE_ROUTER;
26 | }
27 |
28 | @Override
29 | protected String getName() {
30 | return ChatterConfig.current.getSig();
31 | }
32 |
33 | @Override
34 | protected String getConf() {
35 | return ChatterConfig.current.getSig();
36 | }
37 |
38 | public List getExchangeServer() throws Exception {
39 | return this.getServers(ServerNodeRoles.ROLE_EXCHANGE);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/newim-chat/src/main/java/com/whosbean/newim/chatter/exchange/ExchangeClient.java:
--------------------------------------------------------------------------------
1 | package com.whosbean.newim.chatter.exchange;
2 |
3 | import com.whosbean.newim.entity.ExchangeMessage;
4 | import io.netty.bootstrap.Bootstrap;
5 | import io.netty.buffer.ByteBuf;
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.LengthFieldBasedFrameDecoder;
11 | import io.netty.handler.codec.LengthFieldPrepender;
12 | import io.netty.handler.codec.bytes.ByteArrayDecoder;
13 | import io.netty.handler.codec.bytes.ByteArrayEncoder;
14 | import io.netty.util.concurrent.Future;
15 | import io.netty.util.concurrent.GenericFutureListener;
16 | import org.slf4j.Logger;
17 | import org.slf4j.LoggerFactory;
18 |
19 | /**
20 | * Created by yaming_deng on 14-9-9.
21 | */
22 | public class ExchangeClient {
23 |
24 | protected Logger logger = null;
25 |
26 | private volatile boolean enabled;
27 | private String host;
28 | private Integer port;
29 |
30 | private final Bootstrap b = new Bootstrap(); // (1)
31 | private NioEventLoopGroup workerGroup;
32 |
33 | public ExchangeClient(String host, Integer port) {
34 | this.host = host;
35 | this.port = port;
36 | this.logger = LoggerFactory.getLogger(this.getClass().getName()+"."+host+"."+port);
37 | this.enabled = true;
38 | }
39 |
40 | public boolean isEnabled() {
41 | return enabled;
42 | }
43 |
44 | public void setEnabled(boolean enabled) {
45 | this.enabled = enabled;
46 | }
47 |
48 | public class ClientConnectHandler extends ChannelInboundHandlerAdapter {
49 |
50 | @Override
51 | public void channelActive(ChannelHandlerContext ctx) throws Exception {
52 | logger.info("channelActive: " + ctx.channel());
53 |
54 | }
55 |
56 | @Override
57 | public void channelRead(ChannelHandlerContext ctx, Object msg) {
58 | String jsonString = new String((byte[])msg);
59 | logger.info("channelRead: " + ctx.channel() + " --> " + jsonString);
60 | ctx.fireChannelRead(msg);
61 | }
62 |
63 | @Override
64 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
65 | cause.printStackTrace();
66 | ctx.close();
67 |
68 | }
69 |
70 | @Override
71 | public void channelInactive(ChannelHandlerContext ctx) throws Exception {
72 | logger.info("channelInactive: " + ctx.channel() + ", ");
73 | //channelList.remove(ctx.channel());
74 | ctx.fireChannelInactive();
75 |
76 | }
77 |
78 | }
79 |
80 | public void start(){
81 |
82 | Thread thread = new Thread(new Runnable() {
83 | @Override
84 | public void run() {
85 | logger.info("Start Exchange Client. host=" + host+":"+port);
86 | startConnect();
87 | logger.info("DONE Start Exchange Client. host=" + host+":"+port);
88 | }
89 | });
90 |
91 | thread.start();
92 | }
93 |
94 | private void startConnect(){
95 | workerGroup = new NioEventLoopGroup();
96 | try {
97 | b.group(workerGroup); // (2)
98 | b.channel(NioSocketChannel.class); // (3)
99 | b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
100 | b.option(ChannelOption.TCP_NODELAY, true);
101 | b.handler(new ChannelInitializer() {
102 | @Override
103 | public void initChannel(SocketChannel ch) throws Exception {
104 | ChannelPipeline pipeline = ch.pipeline();
105 | pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
106 | pipeline.addLast("bytesDecoder",new ByteArrayDecoder());
107 |
108 | pipeline.addLast("frameEncoder", new LengthFieldPrepender(4, false));
109 | pipeline.addLast("bytesEncoder", new ByteArrayEncoder());
110 |
111 | pipeline.addLast("handler", new ClientConnectHandler());
112 | }
113 | });
114 |
115 | } catch (Exception e){
116 | e.printStackTrace();
117 | workerGroup.shutdownGracefully();
118 | }
119 | }
120 |
121 | public void send(final ExchangeMessage message) throws Exception {
122 | if (!this.enabled){
123 | throw new Exception("Exchange Client has been disabled. host=" + host + ":" + port);
124 | }
125 |
126 | postSent(message, message.toByteArray(), 3);
127 |
128 | }
129 |
130 | private void postSent(final ExchangeMessage message, final byte[] bytes, final int trylimit) {
131 | final ChannelFuture f = b.connect(host, port); // (5)
132 | f.addListener(new GenericFutureListener>() {
133 | @Override
134 | public void operationComplete(Future super Void> future) throws Exception {
135 | if(future.cause() != null){
136 | future.cause().printStackTrace();
137 | }else {
138 | final Channel c = f.channel();
139 | final ByteBuf data = c.config().getAllocator().buffer(bytes.length); // (2)
140 | data.writeBytes(bytes);
141 | ChannelFuture cf = c.writeAndFlush(data);
142 | cf.addListener(new GenericFutureListener>() {
143 | @Override
144 | public void operationComplete(Future future) throws Exception {
145 | if (future.cause() != null) {
146 | logger.error("发送消息错误. host=" + host + ":" + port + ", messageId=" + message.getMessageId(), future.cause());
147 | c.close();
148 | if (trylimit > 0){
149 | postSent(message, bytes, trylimit - 1);
150 | }
151 | }else{
152 | logger.info("发送消息成功. messageId=" + message.getMessageId());
153 | }
154 | }
155 | });
156 | }
157 | }
158 | });
159 |
160 | }
161 |
162 | public void stop(){
163 | workerGroup.shutdownGracefully();
164 | logger.info("Stop Exchange Client. host=" + host+":"+port);
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/newim-chat/src/main/java/com/whosbean/newim/chatter/exchange/ExchangeClientManager.java:
--------------------------------------------------------------------------------
1 | package com.whosbean.newim.chatter.exchange;
2 |
3 | import com.whosbean.newim.chatter.RouterServerNode;
4 | import com.whosbean.newim.zookeeper.ZKPaths;
5 | import org.apache.curator.framework.api.CuratorWatcher;
6 | import org.apache.zookeeper.WatchedEvent;
7 | import org.apache.zookeeper.Watcher;
8 | import org.apache.zookeeper.data.Stat;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.springframework.beans.factory.DisposableBean;
12 | import org.springframework.beans.factory.InitializingBean;
13 | import org.springframework.beans.factory.annotation.Autowired;
14 | import org.springframework.stereotype.Component;
15 |
16 | import java.nio.charset.Charset;
17 | import java.util.Iterator;
18 | import java.util.List;
19 | import java.util.concurrent.ConcurrentHashMap;
20 | import java.util.concurrent.ConcurrentSkipListSet;
21 |
22 | /**
23 | * http://blog.sina.com.cn/s/blog_616e189f01018axz.html
24 | * Created by yaming_deng on 14-9-9.
25 | */
26 | @Component
27 | public class ExchangeClientManager implements InitializingBean, DisposableBean {
28 |
29 | protected Logger logger = LoggerFactory.getLogger(this.getClass());
30 |
31 | public static ExchangeClientManager instance;
32 |
33 | @Autowired
34 | private RouterServerNode routerServerNode;
35 |
36 | private ConcurrentSkipListSet servers = new ConcurrentSkipListSet();
37 |
38 | private ConcurrentHashMap clients = new ConcurrentHashMap();
39 |
40 | @Override
41 | public void destroy() throws Exception {
42 | Iterator itor = clients.keySet().iterator();
43 | while (itor.hasNext()){
44 | String name = itor.next();
45 | ExchangeClient client = clients.get(name);
46 | if (client != null){
47 | client.stop();
48 | }
49 | }
50 | }
51 |
52 | public class ServerNodeWatcher implements CuratorWatcher {
53 |
54 | private final String path;
55 |
56 | public String getPath() {
57 | return path;
58 | }
59 |
60 | public ServerNodeWatcher(String path) {
61 | this.path = path;
62 | }
63 |
64 | @Override
65 | public void process(WatchedEvent event) throws Exception {
66 | logger.info("process Event: {}", event);
67 | if(event.getType() == Watcher.Event.EventType.NodeDataChanged){
68 | byte[] data = null;
69 | System.out.println(path+":"+new String(data, Charset.forName("utf-8")));
70 | }else if(event.getType() == Watcher.Event.EventType.NodeChildrenChanged){
71 | List list = routerServerNode.getExchangeServer();
72 | //compare
73 | for (String item : list){
74 | if (servers.contains(item)){
75 | continue;
76 | }
77 | logger.info("New Server Found. " + item);
78 | newExchangeClient(item);
79 | }
80 | for (String item : servers){
81 | if (list.contains(item)){
82 | continue;
83 | }
84 | logger.info("Server was Removed. " + item);
85 | removeExchangeClient(item);
86 | }
87 | servers.clear();
88 | servers.addAll(list);
89 | }
90 | }
91 |
92 | }
93 |
94 | public class ListenThread extends Thread{
95 |
96 | @Override
97 | public void run() {
98 | Stat stat = null;
99 | while (stat == null){
100 | try {
101 | String path = ZKPaths.NS_ROOT + ZKPaths.PATH_SERVERS;
102 | stat = routerServerNode.getZkClient()
103 | .checkExists()
104 | .usingWatcher(new ServerNodeWatcher(path))
105 | .forPath(path);
106 | if (stat != null){
107 | List list = routerServerNode.getExchangeServer();
108 | for (String host : list){
109 | newExchangeClient(host);
110 | }
111 | servers.addAll(list);
112 | break;
113 | }else{
114 | logger.info("wait for path. " + path);
115 | Thread.sleep(1 * 1000);
116 | }
117 | } catch (Exception e) {
118 | e.printStackTrace();
119 | }
120 | }
121 | }
122 | }
123 |
124 | protected void newExchangeClient(String host){
125 | String[] temp = host.split(":");
126 | ExchangeClient client = new ExchangeClient(temp[0], Integer.parseInt(temp[1]));
127 | client.start();
128 | logger.info("newExchangeClient. host=" + host);
129 | this.clients.put(host, client);
130 | }
131 |
132 | protected void removeExchangeClient(String host){
133 | ExchangeClient client = this.clients.get(host);
134 | if (client != null) {
135 | client.setEnabled(false);
136 | }
137 | this.clients.remove(host);
138 | }
139 |
140 | @Override
141 | public void afterPropertiesSet() throws Exception {
142 | instance = this;
143 | new ListenThread().start();
144 | logger.info("ExchangeClientManager start.");
145 | }
146 |
147 | public ExchangeClient find(String host){
148 | ExchangeClient client = this.clients.get(host);
149 | return client;
150 | }
151 |
152 | }
153 |
--------------------------------------------------------------------------------
/newim-chat/src/main/java/com/whosbean/newim/chatter/router/BoxMsgListenThread.java:
--------------------------------------------------------------------------------
1 | package com.whosbean.newim.chatter.router;
2 |
3 | import com.whosbean.newim.chatter.RouterServerNode;
4 | import com.whosbean.newim.zookeeper.ZKPaths;
5 | import org.apache.curator.framework.api.CuratorWatcher;
6 | import org.apache.zookeeper.CreateMode;
7 | import org.apache.zookeeper.WatchedEvent;
8 | import org.apache.zookeeper.Watcher;
9 | import org.apache.zookeeper.data.Stat;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
13 |
14 | import java.nio.charset.Charset;
15 | import java.util.List;
16 |
17 | /**
18 | * Created by Yaming on 2014/10/17.
19 | */
20 | public class BoxMsgListenThread extends Thread implements CuratorWatcher {
21 |
22 | protected Logger logger = null;
23 |
24 | private String boxid;
25 | private RouterServerNode routerServerNode;
26 | private ThreadPoolTaskExecutor executors;
27 | private String path;
28 |
29 | public BoxMsgListenThread(ThreadPoolTaskExecutor executors, String boxid) {
30 | this.boxid = boxid;
31 | this.routerServerNode = RouterServerNode.current;
32 | this.executors = executors;
33 | this.logger = LoggerFactory.getLogger(this.getClass().getName() + "." + boxid);
34 | }
35 |
36 | @Override
37 | public void run() {
38 | this.path = ZKPaths.NS_ROOT + ZKPaths.PATH_INBOX + "/" + boxid;
39 |
40 | try {
41 | hook(path);
42 | } catch (Exception e) {
43 | e.printStackTrace();
44 | }
45 |
46 |
47 | while (true){
48 | try {
49 | Thread.sleep(3600 * 1000);
50 | } catch (InterruptedException e) {
51 | e.printStackTrace();
52 | }
53 | }
54 | }
55 |
56 | private void hook(final String path) throws Exception {
57 | Stat stat = routerServerNode.getZkClient()
58 | .checkExists().forPath(path);
59 | if (stat == null){
60 | routerServerNode.getZkClient().create()
61 | .creatingParentsIfNeeded()
62 | .withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath(path);
63 | }
64 |
65 | routerServerNode.getZkClient()
66 | .getChildren().usingWatcher(this).forPath(path);
67 | }
68 |
69 | @Override
70 | public void process(WatchedEvent event) throws Exception {
71 | logger.info("process Event: {}", event);
72 | if(event.getType() == Watcher.Event.EventType.NodeDataChanged){
73 | String data = getData(event.getPath());
74 | logger.info(path + ":" + data);
75 | }else if(event.getType() == Watcher.Event.EventType.NodeChildrenChanged){
76 | List childs = routerServerNode.getZkClient()
77 | .getChildren().usingWatcher(this).forPath(path);
78 | logger.info("Found Message. total={}", childs.size());
79 | for(String seqid : childs){
80 | executors.submit(new NewMessageNotifyThread(routerServerNode, boxid, seqid));
81 | }
82 | }
83 | }
84 |
85 | public String getData(String path) throws Exception {
86 | byte[] bytes = routerServerNode.getZkClient().getData().forPath(path);
87 | return new String(bytes, Charset.forName("utf-8"));
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/newim-chat/src/main/java/com/whosbean/newim/chatter/router/ChatMessageListener.java:
--------------------------------------------------------------------------------
1 | package com.whosbean.newim.chatter.router;
2 |
3 | import com.whosbean.newim.chatter.RouterServerNode;
4 | import com.whosbean.newim.chatter.exchange.ExchangeClientManager;
5 | import com.whosbean.newim.zookeeper.ZKPaths;
6 | import org.apache.curator.framework.api.CuratorWatcher;
7 | import org.apache.zookeeper.CreateMode;
8 | import org.apache.zookeeper.KeeperException;
9 | import org.apache.zookeeper.WatchedEvent;
10 | import org.apache.zookeeper.Watcher;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 | import org.springframework.beans.factory.DisposableBean;
14 | import org.springframework.beans.factory.InitializingBean;
15 | import org.springframework.beans.factory.annotation.Autowired;
16 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
17 | import org.springframework.stereotype.Component;
18 |
19 | import java.nio.charset.Charset;
20 | import java.util.List;
21 | import java.util.concurrent.ConcurrentHashMap;
22 |
23 | /**
24 | * Created by Yaming on 2014/10/14.
25 | */
26 | @Component
27 | public class ChatMessageListener implements InitializingBean, DisposableBean {
28 |
29 | protected Logger logger = LoggerFactory.getLogger(this.getClass());
30 |
31 | public static ChatMessageListener current;
32 |
33 | @Autowired
34 | private RouterServerNode routerServerNode;
35 |
36 | @Autowired
37 | private ExchangeClientManager exchangeClientManager;
38 |
39 | private ThreadPoolTaskExecutor executors = null;
40 | private ConcurrentHashMap boxMap = new ConcurrentHashMap();
41 |
42 | private volatile boolean stopped = false;
43 |
44 | @Override
45 | public void destroy() throws Exception {
46 | stopped = true;
47 | }
48 |
49 | @Override
50 | public void afterPropertiesSet() throws Exception {
51 | int limit = Runtime.getRuntime().availableProcessors() * 2;
52 | executors = new ThreadPoolTaskExecutor();
53 | executors.setCorePoolSize(limit/5);
54 | executors.setMaxPoolSize(limit);
55 | executors.setWaitForTasksToCompleteOnShutdown(true);
56 | executors.afterPropertiesSet();
57 | new ChatListenThread().start();
58 | current = this;
59 | logger.info("ChatMessageListner start.");
60 | }
61 |
62 | public String getData(String path) throws Exception {
63 | byte[] bytes = routerServerNode.getZkClient().getData().forPath(path);
64 | return new String(bytes, Charset.forName("utf-8"));
65 | }
66 |
67 | public void remove(String boxid){
68 | boxMap.remove(boxid);
69 | logger.info("Box Listener quit. " + boxid);
70 | }
71 |
72 | public class NewMemberWatcher implements CuratorWatcher {
73 |
74 | private final String path;
75 |
76 | public String getPath() {
77 | return path;
78 | }
79 |
80 | public NewMemberWatcher(String path) {
81 | this.path = path;
82 | }
83 |
84 | @Override
85 | public void process(WatchedEvent event) throws Exception {
86 | logger.info("process Event: {}", event);
87 | if(event.getType() == Watcher.Event.EventType.NodeDataChanged){
88 | String data = getData(event.getPath());
89 | logger.info(path + ":" + data);
90 | }else if(event.getType() == Watcher.Event.EventType.NodeChildrenChanged){
91 | List childs = routerServerNode.getZkClient().getChildren().forPath(path);
92 | for(String boxid : childs){
93 | if (!boxMap.contains(boxid)){
94 | boxMap.put(boxid, 1);
95 | new BoxMsgListenThread(executors, boxid).start();
96 | }
97 | }
98 | }
99 | }
100 |
101 | }
102 |
103 | public class ChatListenThread extends Thread{
104 |
105 | @Override
106 | public void run() {
107 | String path = ZKPaths.NS_ROOT + ZKPaths.PATH_CHATS;
108 | List childs = null;
109 | while (childs == null){
110 | try {
111 | childs = routerServerNode.getZkClient()
112 | .getChildren()
113 | .usingWatcher(new NewMemberWatcher(path))
114 | .forPath(path);
115 | if (childs != null){
116 | logger.info("Found path. {}, size {}", path, childs.size());
117 | if (childs.size() > 0){
118 | //start boxMessageListen
119 | for(String boxid : childs){
120 | boxMap.put(boxid, 1);
121 | new BoxMsgListenThread(executors, boxid).start();
122 | }
123 | }
124 | break;
125 | }else{
126 | logger.info("Wait for path. " + path);
127 | Thread.sleep(1 * 1000);
128 | }
129 | } catch (Exception e) {
130 | if (e instanceof KeeperException){
131 | KeeperException ex = (KeeperException)e;
132 | if (ex.code().equals(KeeperException.Code.NONODE)){
133 | try {
134 | routerServerNode.getZkClient().create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path);
135 | } catch (Exception e1) {
136 | logger.error(e1.getMessage(), e1);
137 | }
138 | }
139 | }else {
140 | logger.error(e.getMessage(), e);
141 | }
142 | }
143 | }
144 | }
145 | }
146 |
147 | }
148 |
--------------------------------------------------------------------------------
/newim-chat/src/main/java/com/whosbean/newim/chatter/router/NewMemberNotifyThread.java:
--------------------------------------------------------------------------------
1 | package com.whosbean.newim.chatter.router;
2 |
3 | import com.whosbean.newim.chatter.RouterServerNode;
4 | import com.whosbean.newim.chatter.exchange.ExchangeClient;
5 | import com.whosbean.newim.chatter.exchange.ExchangeClientManager;
6 | import com.whosbean.newim.entity.ExchangeMessage;
7 | import com.whosbean.newim.zookeeper.ZKPaths;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * Created by Yaming on 2014/10/14.
15 | */
16 | public class NewMemberNotifyThread implements Runnable {
17 |
18 | protected Logger logger = LoggerFactory.getLogger(this.getClass());
19 |
20 | private RouterServerNode routerServerNode;
21 | private String boxid;
22 | private String[] data;
23 |
24 | public NewMemberNotifyThread(RouterServerNode routerServerNode, String boxid, String[] data) {
25 | this.routerServerNode = routerServerNode;
26 | this.boxid = boxid;
27 | this.data = data;
28 | }
29 |
30 | @Override
31 | public void run() {
32 | String path = ZKPaths.getMemberPath(boxid);
33 | String msgId = this.data[this.data.length-1];
34 | try {
35 | List members = this.routerServerNode.getZkClient().getChildren().forPath(path);
36 | //TODO:too many members then split
37 | ExchangeMessage.Builder message = ExchangeMessage.newBuilder();
38 | message.setChatRoomId(this.boxid);
39 | for(String host : members){
40 | ExchangeClient client = ExchangeClientManager.instance.find(host);
41 | message.setMessageId(msgId);
42 | List channels = this.routerServerNode.getZkClient().getChildren().forPath(path + "/" + host);
43 | for(String cid : channels){
44 | message.addChannelId(new Integer(cid));
45 | }
46 | message.setChatPath(path + "/" + host);
47 | logger.info("ExchangeClient send message. " + message);
48 | client.send(message.build());
49 | }
50 | } catch (Exception e) {
51 | e.printStackTrace();
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/newim-chat/src/main/java/com/whosbean/newim/chatter/router/NewMessageNotifyThread.java:
--------------------------------------------------------------------------------
1 | package com.whosbean.newim.chatter.router;
2 |
3 | import com.whosbean.newim.chatter.RouterServerNode;
4 | import com.whosbean.newim.chatter.exchange.ExchangeClient;
5 | import com.whosbean.newim.chatter.exchange.ExchangeClientManager;
6 | import com.whosbean.newim.entity.ExchangeMessage;
7 | import com.whosbean.newim.zookeeper.ZKPaths;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import java.nio.charset.Charset;
12 | import java.util.List;
13 |
14 | /**
15 | * Created by Yaming on 2014/10/14.
16 | */
17 | public class NewMessageNotifyThread implements Runnable {
18 |
19 | protected Logger logger = LoggerFactory.getLogger(this.getClass());
20 |
21 | private RouterServerNode routerServerNode;
22 | private String boxid;
23 | private String seqid;
24 |
25 |
26 | public NewMessageNotifyThread(RouterServerNode routerServerNode, String boxid, String seqid) {
27 | this.routerServerNode = routerServerNode;
28 | this.boxid = boxid;
29 | this.seqid = seqid;
30 | }
31 |
32 | @Override
33 | public void run() {
34 | String msgpath = ZKPaths.getInboxPath(boxid, seqid);
35 | String path = ZKPaths.getMemberPath(boxid);
36 | try {
37 | String msgid = this.getData(msgpath);
38 | List members = this.routerServerNode.getZkClient().getChildren().forPath(path);
39 | //TODO:too many members then split
40 | ExchangeMessage.Builder message = ExchangeMessage.newBuilder();
41 | message.setChatRoomId(this.boxid);
42 | message.setMsgPath(msgpath);
43 | for(String host : members){
44 | ExchangeClient client = ExchangeClientManager.instance.find(host);
45 | message.setMessageId(msgid);
46 | List channels = this.routerServerNode.getZkClient().getChildren().forPath(path + "/" + host);
47 | for(String cid : channels){
48 | message.addChannelId(new Integer(cid));
49 | }
50 | message.setChatPath(boxid + "/" + host);
51 | logger.info("ExchangeClient send message. " + message);
52 | client.send(message.build());
53 | }
54 | } catch (Exception e) {
55 | e.printStackTrace();
56 | }
57 | }
58 |
59 | public String getData(String path) throws Exception {
60 | byte[] bytes = routerServerNode.getZkClient().getData().forPath(path);
61 | return new String(bytes, Charset.forName("utf-8"));
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/newim-chat/src/main/resources/chatter.yaml:
--------------------------------------------------------------------------------
1 | server:
2 | ip: 127.0.0.1
3 | actors: 10
4 | workers: 10
5 | port: 8180
6 |
7 | bucket:
8 | engine: redis
--------------------------------------------------------------------------------
/newim-chat/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | utf-8
5 |
6 |
7 | %date [%thread] %-5level %logger{50} - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 | true
15 | UTF-8
16 |
17 |
18 | logs/chatter.%d{yyyy-MM-dd}.log
19 |
20 |
21 | 30
22 |
23 |
24 | %d{HH:mm:ss} [%thread] %-5level %logger{80} - %msg%n
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/newim-chat/src/main/resources/redis.yaml:
--------------------------------------------------------------------------------
1 | host: 127.0.0.1
2 | port: 6379
3 | maxActive: 50
4 | maxIdle: 10
5 | maxWait: 5000
--------------------------------------------------------------------------------
/newim-chat/src/main/resources/spring-chatter.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/newim-chat/src/main/resources/zookeeper.yaml:
--------------------------------------------------------------------------------
1 | servers: 127.0.0.1:2181 #,127.0.0.1:2182,127.0.0.l:2183
2 | retry:
3 | interval: 1000
4 | limit: 3
--------------------------------------------------------------------------------
/newim-chat/src/test/java/com/whosbean/AppTest.java:
--------------------------------------------------------------------------------
1 | package com.whosbean;
2 |
3 | import junit.framework.Test;
4 | import junit.framework.TestCase;
5 | import junit.framework.TestSuite;
6 |
7 | /**
8 | * Unit test for simple App.
9 | */
10 | public class AppTest
11 | extends TestCase
12 | {
13 | /**
14 | * Create the test case
15 | *
16 | * @param testName name of the test case
17 | */
18 | public AppTest( String testName )
19 | {
20 | super( testName );
21 | }
22 |
23 | /**
24 | * @return the suite of tests being tested
25 | */
26 | public static Test suite()
27 | {
28 | return new TestSuite( AppTest.class );
29 | }
30 |
31 | /**
32 | * Rigourous Test :-)
33 | */
34 | public void testApp()
35 | {
36 | assertTrue( true );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/newim-common/newim-common.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/newim-common/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | newim
5 | com.whosbean
6 | 1.0-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | newim-common
11 | jar
12 |
13 | newim-common
14 | http://maven.apache.org
15 |
16 |
17 | UTF-8
18 |
19 |
20 |
21 |
22 | junit
23 | junit
24 | 3.8.1
25 | test
26 |
27 |
28 | redis.clients
29 | jedis
30 | 2.2.1
31 |
32 |
33 | com.google.protobuf
34 | protobuf-java
35 | 2.5.0
36 |
37 |
38 | com.whosbean
39 | newim-pb
40 | 1.0-SNAPSHOT
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/newim-common/src/main/java/com/whosbean/newim/common/AppContextHolder.java:
--------------------------------------------------------------------------------
1 | package com.whosbean.newim.common;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.beans.factory.InitializingBean;
5 | import org.springframework.context.ApplicationContext;
6 | import org.springframework.context.ApplicationContextAware;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | * Created by yaming_deng on 14-9-11.
11 | */
12 | @Component
13 | public class AppContextHolder implements ApplicationContextAware, InitializingBean {
14 |
15 | public static AppContextHolder context;
16 |
17 | private ApplicationContext applicationContext;
18 |
19 | @Override
20 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
21 | this.applicationContext = applicationContext;
22 | }
23 |
24 |
25 | @Override
26 | public void afterPropertiesSet() throws Exception {
27 | context = this;
28 | }
29 |
30 | public T get(Class clazz, String name){
31 | return this.applicationContext.getBean(name, clazz);
32 | }
33 |
34 | public T get(Class clazz){
35 | return this.applicationContext.getBean(clazz);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/newim-common/src/main/java/com/whosbean/newim/config/AbstractConfig.java:
--------------------------------------------------------------------------------
1 | package com.whosbean.newim.config;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.beans.factory.InitializingBean;
6 | import org.springframework.util.Assert;
7 |
8 | import java.io.IOException;
9 | import java.util.*;
10 |
11 | /**
12 | * 配置规范如下:
13 | * /resources/$env/$sample.yaml
14 | * /resources/$env/$app/$sample.yaml
15 | * $env=dev,test,prod
16 | * $app=具体的业务, 如elasticsearch, db etc.
17 | * $sample=具体文件名
18 | * User: yamingdeng
19 | * Date: 13-11-25
20 | * Time: 下午9:58
21 | */
22 | public abstract class AbstractConfig implements InitializingBean{
23 | protected String cfgFile;
24 | protected Map cfg = null;
25 | protected Logger logger = null;
26 |
27 | protected Logger getLogger(){
28 | if (logger == null){
29 | logger = LoggerFactory.getLogger(this.getClass());
30 | }
31 | return logger;
32 | }
33 |
34 | @Override
35 | public void afterPropertiesSet() throws Exception {
36 | this.cfgFile = this.getConfName();
37 | Assert.notNull(this.cfgFile, "cfgFile should not be NULL.");
38 | this.load();
39 | }
40 |
41 | protected synchronized void load() throws IOException {
42 | this.cfgFile = String.format("%s.yaml", this.cfgFile);
43 | if (this.cfg != null){
44 | return;
45 | }
46 | this.cfg = ConfigYamlManager.load(this.cfgFile, this.getConfName());
47 | }
48 |
49 | public String getEnvName(){
50 | return "dev";
51 | }
52 |
53 | public abstract String getConfName();
54 |
55 | public boolean isEnabled(){
56 | return this.cfg != null;
57 | }
58 |
59 | public String getCfgFile() {
60 | return cfgFile;
61 | }
62 |
63 | public void setCfgFile(String cfgFile) {
64 | this.cfgFile = cfgFile;
65 | }
66 |
67 | public void setMap(Map map){
68 | if (map == null){
69 | return;
70 | }
71 | if (this.cfg == null){
72 | this.cfg = new HashMap();
73 | }
74 | for (String key : map.keySet()){
75 | this.cfg.put(key, map.get(key));
76 | }
77 | }
78 |
79 | @SuppressWarnings("unchecked")
80 | public T get(Class type, String key){
81 | Object temp = this.cfg.get(key);
82 | if(temp == null){
83 | return null;
84 | }
85 | return (T) temp;
86 | }
87 |
88 | public T get(Class type, String key, T defaultValue){
89 | Object temp = this.cfg.get(key);
90 | if(temp == null){
91 | return defaultValue;
92 | }
93 | return (T) temp;
94 | }
95 |
96 | public class KeyComparable implements Comparator