http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/NOTICE
----------------------------------------------------------------------
diff --git a/rocketmq-console-ng/NOTICE b/rocketmq-console-ng/NOTICE
new file mode 100644
index 0000000..fa6d59e
--- /dev/null
+++ b/rocketmq-console-ng/NOTICE
@@ -0,0 +1,5 @@
+Apache RocketMQ Console
+Copyright 2016-2017 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/README.md
----------------------------------------------------------------------
diff --git a/rocketmq-console-ng/README.md b/rocketmq-console-ng/README.md
new file mode 100644
index 0000000..ed8c567
--- /dev/null
+++ b/rocketmq-console-ng/README.md
@@ -0,0 +1,61 @@
+#RocketMQ-Console-Ng[![Build 
Status](https://travis-ci.org/rocketmq/rocketmq-console-ng.svg?branch=master)](https://travis-ci.org/rocketmq/rocketmq-console-ng)
 [![Coverage 
Status](https://coveralls.io/repos/github/rocketmq/rocketmq-console-ng/badge.svg?branch=master)](https://coveralls.io/github/rocketmq/rocketmq-console-ng?branch=master)
+[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
+#How To Install
+
+## With Docker
+
+* get docker image
+
+```
+mvn clean package -Dmaven.test.skip=true docker:build
+```
+
+or
+
+```
+docker pull styletang/rocketmq-console-ng
+```
+* run it (change namesvrAddr and port yourself)
+
+```
+docker run -e "JAVA_OPTS=-Drocketmq.namesrv.addr=127.0.0.1:9876 
-Dcom.rocketmq.sendMessageWithVIPChannel=false" -p 8080:8080 -t 
styletang/rocketmq-console-ng
+```
+
+## Without Docker
+require java 1.7
+```
+mvn spring-boot:run
+```
+or
+```
+mvn clean package -Dmaven.test.skip=true
+java -jar target/rocketmq-console-ng-1.0.0.jar
+```
+
+### Tips
+* if you download package slow,you can change maven's mirror(maven's 
settings.xml)
+  
+  ```
+  <mirrors>
+      <mirror>
+            <id>alimaven</id>
+            <name>aliyun maven</name>
+            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+            <mirrorOf>central</mirrorOf>        
+      </mirror>
+  </mirrors>
+  ```
+  
+* if you use the rocketmq < 3.5.8,please add 
-Dcom.rocketmq.sendMessageWithVIPChannel=false when you start 
rocketmq-console-ng(or you can change it in ops page)
+* change the rocketmq.config.namesrvAddr in 
resource/application.properties.(or you can change it in ops page)
+
+#UserGuide
+
+[English](https://github.com/rocketmq/rocketmq-console-ng/blob/master/doc/1_0_0/UserGuide_EN.md)
+
+[中文](https://github.com/rocketmq/rocketmq-console-ng/blob/master/doc/1_0_0/UserGuide_CN.md)
+
+#Communicate With Us
+* QQ Group:535273860
+* You can communicate with us use QQ.(or send us issue / pull request)
+* You can join us and make a contribute for rocketmq-console-ng.

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/doc/1_0_0/Milestone.md
----------------------------------------------------------------------
diff --git a/rocketmq-console-ng/doc/1_0_0/Milestone.md 
b/rocketmq-console-ng/doc/1_0_0/Milestone.md
new file mode 100644
index 0000000..6a345eb
--- /dev/null
+++ b/rocketmq-console-ng/doc/1_0_0/Milestone.md
@@ -0,0 +1,102 @@
+#Deploy Plan
+
+we will deploy the first rocketmq-console-ng use rocketmq-tools 3.5.8(or 
4.0.0),base on 
[rocket-console](https://github.com/didapinchegit/rocket-console),thanks 
didapinche.com
+
+## Framework
+* 0. we use spring-boot + bootstrap + angularjs
+
+## something to improve
+* 0. clean code (checkStyle codeStyle to be done)
+* 1. international
+* 2. compress fe'resource
+* 3. navigation bar can improve
+* 4. write operation need confirm,action show the detail result
+* 5. layout/UI should improve
+* 6. change to spring-boot
+
+
+## something to fix
+* query Message by topic and time is not accurate, will lost some message 
+* consumer can consume the message when topic has been deleted
+* can't show producerList,we can only query a online producer use topic and 
groupName,not easy to use.
+* resetOffset should be improve,online consumer can return the reset result 
but offline's can't
+* we can't set clusterName when create topic or consumer 
+* when create a new consumer,if not be consumed,can't be found in consumerList
+
+
+## something to add
+* 1. dashboard 
+
+# Roadmap
+
+## Improve
+- [x] clean code (checkStyle codeStyle to be done) -- StyleTang
+- [x] international -- Deploy by [tcrow](https://github.com/tcrow)
+- [x] layout/UI  -- Deploy by [tcrow](https://github.com/tcrow)
+       - [x] compress fe'resource 
+       - [x] navigation bar can improve
+       - [x] write operation need confirm,action show the detail result || 
already have
+       - [x] layout/UI should improve
+- [x] change to spring-boot  -- Deploy by syzjava
+- [x] change to bootstrap angularjs   -- Deploy by 
[tcrow](https://github.com/tcrow)
+- [x] improve search message --StyleTang
+
+## Fix
+- [x] query Message by topic and time is not accurate, will lost some 
message  -- StyleTang (need test)
+- [x] consumer can consume the message when topic has been deleted // offset 
be clear.if have problem,reopen it.
+- [ ] can't show producerList,we can only query a online producer use topic 
and groupName,not easy to use. [need this 
issues](https://issues.apache.org/jira/browse/ROCKETMQ-49)(next milestone)
+- [ ] resetOffset should be improve,online consumer can return the reset 
result but offline's can't //this version(3.5.8) may be can't fix (next 
milestone)
+- [x] we can't set clusterName when create topic or consumer  -- StyleTang
+- [x] when create a new consumer,if not be consumed,can't be found in 
consumerList //it Fixed,But this page is too slow,need improve --StyleTang
+- [x] message view page,resend message (version >=3.5.8) have bug   -- 
StyleTang
+
+## Add
+- [ ] DashboardController      -- Deploy by [tcrow](https://github.com/tcrow)
+    - [x] rocketmq topic tps 5m line chart
+    - [x] rocketmq topic top10 table
+    - [x] broker load 5m line chart
+    - [x] broker load top10 table
+    - [ ] topic exception table(next milestone)
+
+## Already Have (Deploy by StyleTang) But Can Improve 
+### Cluster
+- [x] ClusterController
+    - [x] Cluster OverView
+    - [x] Broker Status
+    - [x] Broker Config
+
+### Topic
+- [x] TopicController
+    - [x] TopicList
+    - [x] Topic Status
+    - [x] Topic Router
+    - [x] View Topic Config
+    - [x] Topci Add / Update
+    - [X] Send A Test Topic
+    - [x] Reset ConsumerGroup's Offset Under This Topic
+    - [x] Delete This Topic
+
+### Producer
+- [x] ProducerController
+    - [x] Producer Client Info
+
+
+### Consumer
+- [x] ConsumerController
+    - [x] ConsumerList
+    - [x] Consumer Client Info
+    - [x] Topic Consume Status Under This Consumer Group
+    - [x] View Consumer Config
+    - [x] Consumer Add / Update
+    - [x] Delete This Consumer
+
+### Message
+- [x] MessageController
+    - [x] Query By Topic And Time
+    - [x] Query By Topic And Key
+    - [x] Query By MessageId(OffsetMessageId)
+    - [x] A Nice Message Detail View
+    - [x] Message Consume Status
+    - [x] Resend Message To A Consume Group
+    
+    
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/doc/1_0_0/UserGuide_CN.md
----------------------------------------------------------------------
diff --git a/rocketmq-console-ng/doc/1_0_0/UserGuide_CN.md 
b/rocketmq-console-ng/doc/1_0_0/UserGuide_CN.md
new file mode 100644
index 0000000..d48333d
--- /dev/null
+++ b/rocketmq-console-ng/doc/1_0_0/UserGuide_CN.md
@@ -0,0 +1,64 @@
+# RocketMQ使用文档
+
+## 运维页面
+* 你可以修改这个服务使用的navesvr的地址
+* 你可以修改这个服务是否使用VIPChannel(如果你的mq 
server版本小于3.5.8,请设置不使用)
+
+## 驾驶舱
+* 查看broker的消息量(总量/5分钟图)
+* 查看单一主题的消息量(总量/趋势图)
+
+## 集群页面
+* 查看集群的分布情况
+    * cluster与broker关系
+    * broker
+* 查看broker具体信息/运行信息
+* 查看broker配置信息
+
+## 主题页面
+* 展示所有的主题,可以通过搜索框进行过滤
+* 筛选 普通/重试/死信 主题
+* 添加/更新主题
+    * clusterName 创建在哪几个cluster上
+    * brokerName 创建在哪几个broker上
+    * topicName 主题名
+    * writeQueueNums  写队列数量
+    * readQueueNums  读队列数量
+    * perm //2是写 4是读 6是读写
+* 状态 
查询消息投递状态(投递到哪些broker/哪些queue/多少量等)
+* 路由 查看消息的路由(现在你
发这个主题的消息会发往哪些broker,对应broker的queue信息)
+* CONSUMER管理(这个topic都被哪些group消费了,消费情
况何如)
+* topic配置(查看变更当前的配置)
+* 发送消息(向这个主题发送一个测试消息)
+* 重置消费位点(分为在线和不在线两种情
况,不过都需要检查重置是否成功)
+* 删除主题 (会删除掉所有broker以及namesvr上的主题é…
ç½®å’Œè·¯ç”±ä¿¡æ¯ï¼‰
+
+## 消费者页面
+* 展示所有的消费组,可以通过搜索框进行过滤
+* 刷新页面/每隔五秒定时刷新页面
+* 按照订阅组/数量/TPS/延迟 进行排序
+* 添加/更新消费组
+    * clusterName 创建咋哪几个集群上
+    * brokerName 创建在哪几个broker上
+    * groupName  消费组名字
+    * consumeEnable //是否可以消费 FALSE的话将无法进行消费
+    * consumeBroadcastEnable //是否可以广播消费
+    * retryQueueNums //重试队列的大小
+    * brokerId //正常情况从哪消费
+    * whichBrokerWhenConsumeSlowly//出问题了从哪消费
+* 终端 在线的消费客户端查看,包括版本订阅
信息和消费模式
+* 消费详情 对应消费组的消费明细查看,这个消费组订阅
的所有Topic的消费情况,每个queue对应的消费client查看(包
括Retry消息)
+* 配置 查看变更消费组的配置
+* 删除 在指定的broker上删除消费组
+
+## 发布管理页面
+* 通过Topic和Group查询在线的消息生产者客户端
+    * 信息包含客户端主机 版本
+    
+## 消息查询页面
+* 根据Topic和时间区间查询
+    *由于数据量大 做多只会展示2000条,多的会被忽略 
+* 根据Topic和Key进行查询
+    * 最多只会展示64条
+* 根据消息主题和消息Id进行消息的查询
+* 消息详情可以展示这条消息的详细信息,查看消息对应到å…
·ä½“消费组的消费情况(如果异常,可以查看å…
·ä½“的异常信息)。可以向指定的消费组重发消息。
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/doc/1_0_0/UserGuide_EN.md
----------------------------------------------------------------------
diff --git a/rocketmq-console-ng/doc/1_0_0/UserGuide_EN.md 
b/rocketmq-console-ng/doc/1_0_0/UserGuide_EN.md
new file mode 100644
index 0000000..f883f9e
--- /dev/null
+++ b/rocketmq-console-ng/doc/1_0_0/UserGuide_EN.md
@@ -0,0 +1,65 @@
+# RocketMQ User Guide
+
+## OPS Page
+* You can change console's namesvrAddr here
+* You can change the value of useVIPChannel  here (if you rocketMQ version < 
3.5.8,the value of useVIPChannel should be false)
+
+## DashBoard Page
+* broker's message count (broker total message count/5 min trend)
+* topic's message count(topic total message count/5 min trend)
+
+## Cluster Page
+* Cluster Detail
+    * relation between cluster and broker
+    * broker's master / salve node
+* broker'a detail info(runtime info)
+* broker's config
+
+## Topic Page
+* show all the topics,you can filter topic by search bar
+* filter (Normal/retry/dead) topic 
+* Add/Update Topic
+    * clusterName (create on which cluster)
+    * brokerName (create on which broker)
+    * topicName 
+    * writeQueueNums  
+    * readQueueNums  
+    * perm //2 for write 4 for read 6 for write and read
+* STATUS look over message send status(send to which broker/which queue/how 
many messages) 
+* ROUTER look update topic's router(this topic send to which broker,the 
broker's queue info)
+* CONSUMER MANAGE(this topic consume by which group,how about the consume 
state)
+* TOPIC CONFIG(check or change the topic's config)
+* SEND MESSAGE(send a test message)
+* Reset CONSUMER OFFSET (the consumer online or not online is different,you 
need check the reset result)
+* DELETE (will delete the topic on all broker and namesvr)
+
+## Consumer Page
+* show all the consumers,you can filter consumer by search bar
+* refresh page/refresh page per 5 seconds
+* order by SubscriptionGroup/Quantity/TPS/Delay
+* Add/Update Consumer
+    * clusterName (create on which cluster)
+    * brokerName (create on which broker)
+    * groupName  (consumer group name)
+    * consumeEnable (this group can't consume message if this is false)
+    * consumeBroadcastEnable (can't use broadcast is this is false)
+    * retryQueueNums 
+    * brokerId (consume form where when broker is normal)
+    * whichBrokerWhenConsumeSlowly(consume form where when broker has problem)
+* CLIENT (look over online consumer's client,include subscribe info and 
consume mode)
+* CONSUME DETAIL (look over this consumer's consume detail,broker offset and 
the consumer offset,queue consumed by which client)
+* CONFIG (check or change the consumer's config)
+* DELETE (delete the consumer group on selected group)
+
+## Producer Page
+* Query online producer client by topic and group
+    * show client's server / version
+    
+## Message Page
+* Query By Topic And Time
+    *Only Return 2000 Messages,the message more than 2000 will be hide
+* Query By Topic And Key
+    * Only Return 64 Messages
+* Query By Topic And MessageId
+* look over this message's detail info.you can see the message's consume 
state(each group has one line),show the exception message if has exception.
+you can send this message to the group you selected
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/pom.xml
----------------------------------------------------------------------
diff --git a/rocketmq-console-ng/pom.xml b/rocketmq-console-ng/pom.xml
new file mode 100644
index 0000000..f0f42e7
--- /dev/null
+++ b/rocketmq-console-ng/pom.xml
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>1.4.3.RELEASE</version>
+    </parent>
+    <groupId>org.apache</groupId>
+    <artifactId>rocketmq-console-ng</artifactId>
+    <packaging>jar</packaging>
+    <version>1.0.0</version>
+    <name>rocketmq-console-ng</name>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <java.version>1.7</java.version>
+        <guava.version>16.0.1</guava.version>
+        <commons-digester.version>2.1</commons-digester.version>
+        <commons-lang.version>2.6</commons-lang.version>
+        <commons-io.version>2.4</commons-io.version>
+        <commons-cli.version>1.2</commons-cli.version>
+        <rocketmq.version>4.0.0-incubating</rocketmq.version>
+        <surefire.version>2.19.1</surefire.version>
+        <aspectj.version>1.6.11</aspectj.version>
+        <main.basedir>${basedir}/../..</main.basedir>
+        <docker.image.prefix>styletang</docker.image.prefix>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+            <version>3.2.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.rocketmq</groupId>
+            <artifactId>rocketmq-tools</artifactId>
+            <version>${rocketmq.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.rocketmq</groupId>
+            <artifactId>rocketmq-namesrv</artifactId>
+            <version>${rocketmq.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.rocketmq</groupId>
+            <artifactId>rocketmq-broker</artifactId>
+            <version>${rocketmq.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>${guava.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjrt</artifactId>
+            <version>${aspectj.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjweaver</artifactId>
+            <version>${aspectj.version}</version>
+        </dependency>
+        <!-- Spring AOP + AspectJ -->
+        <dependency>
+            <groupId>cglib</groupId>
+            <artifactId>cglib</artifactId>
+            <version>2.2.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jooq</groupId>
+            <artifactId>joor</artifactId>
+            <version>0.9.6</version>
+        </dependency>
+
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>com.spotify</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <version>0.4.11</version>
+                <configuration>
+                    
<imageName>${docker.image.prefix}/${project.artifactId}</imageName>
+                    <dockerDirectory>src/main/docker</dockerDirectory>
+                    <resources>
+                        <resource>
+                            <targetPath>/</targetPath>
+                            <directory>${project.build.directory}</directory>
+                            <include>${project.build.finalName}.jar</include>
+                        </resource>
+                    </resources>
+                    <imageTags>
+                        <imageTag>${project.version}</imageTag>
+                        <imageTag>latest</imageTag>
+                    </imageTags>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-checkstyle-plugin</artifactId>
+                <version>2.17</version>
+                <executions>
+                    <execution>
+                        <id>validate</id>
+                        <phase>validate</phase>
+                        <configuration>
+                            <excludes>src/main/resources</excludes>
+                            
<configLocation>style/rmq_checkstyle.xml</configLocation>
+                            <encoding>UTF-8</encoding>
+                            <consoleOutput>true</consoleOutput>
+                            <failsOnError>true</failsOnError>
+                        </configuration>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>${surefire.version}</version>
+                <configuration>
+                    <excludes>
+                        <exclude>src/test/**</exclude>
+                    </excludes>
+                    <forkCount>1</forkCount>
+                    <reuseForks>true</reuseForks>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <version>2.19.1</version>
+                <configuration>
+                    <forkCount>1</forkCount>
+                    <reuseForks>true</reuseForks>
+                    <argLine>@{failsafeArgLine}</argLine>
+                    <includes>
+                        <include>src/test/**</include>
+                    </includes>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>integration-test</goal>
+                            <goal>verify</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-source-plugin</artifactId>
+                <version>3.0.1</version>
+                <executions>
+                    <execution>
+                        <id>attach-sources</id>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <!--<plugin>-->
+                <!--<artifactId>maven-javadoc-plugin</artifactId>-->
+                <!--<version>2.10.4</version>-->
+                <!--<configuration>-->
+                    <!--<charset>UTF-8</charset>-->
+                <!--</configuration>-->
+                <!--<executions>-->
+                    <!--<execution>-->
+                        <!--<id>attach-javadocs</id>-->
+                        <!--<goals>-->
+                            <!--<goal>jar</goal>-->
+                        <!--</goals>-->
+                    <!--</execution>-->
+                <!--</executions>-->
+            <!--</plugin>-->
+            <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <version>0.7.9</version>
+                <executions>
+                    <execution>
+                        <id>default-prepare-agent</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                        <configuration>
+                            
<destFile>${project.build.directory}/jacoco.exec</destFile>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>default-prepare-agent-integration</id>
+                        <phase>pre-integration-test</phase>
+                        <goals>
+                            <goal>prepare-agent-integration</goal>
+                        </goals>
+                        <configuration>
+                            
<destFile>${project.build.directory}/jacoco-it.exec</destFile>
+                            <propertyName>failsafeArgLine</propertyName>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>default-report</id>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>default-report-integration</id>
+                        <goals>
+                            <goal>report-integration</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>default-check</id>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <!-- implementation is needed only for Maven 2 
-->
+                                <rule 
implementation="org.jacoco.maven.RuleConfiguration">
+                                    <element>BUNDLE</element>
+                                    <limits>
+                                        <!-- implementation is needed only for 
Maven 2 -->
+                                        <limit 
implementation="org.jacoco.report.check.Limit">
+                                            <counter>COMPLEXITY</counter>
+                                            <value>COVEREDRATIO</value>
+                                            <minimum>0.20</minimum>
+                                        </limit>
+                                    </limits>
+                                </rule>
+                            </rules>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.eluder.coveralls</groupId>
+                <artifactId>coveralls-maven-plugin</artifactId>
+                <version>4.3.0</version>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>findbugs-maven-plugin</artifactId>
+                <version>3.0.4</version>
+            </plugin>
+
+            
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/docker/Dockerfile
----------------------------------------------------------------------
diff --git a/rocketmq-console-ng/src/main/docker/Dockerfile 
b/rocketmq-console-ng/src/main/docker/Dockerfile
new file mode 100644
index 0000000..46917b1
--- /dev/null
+++ b/rocketmq-console-ng/src/main/docker/Dockerfile
@@ -0,0 +1,6 @@
+FROM java:8
+VOLUME /tmp
+ADD rocketmq-console-ng-1.0.0.jar app.jar
+RUN sh -c 'touch /app.jar'
+ENV JAVA_OPTS=""
+ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -jar /app.jar" ]

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/App.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/App.java 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/App.java
new file mode 100644
index 0000000..6ed5831
--- /dev/null
+++ b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/App.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@EnableAutoConfiguration
+@SpringBootApplication
+public class App {
+
+    public static void main(String[] args) {
+        SpringApplication.run(App.class, args);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/aspect/admin/MQAdminAspect.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/aspect/admin/MQAdminAspect.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/aspect/admin/MQAdminAspect.java
new file mode 100644
index 0000000..8c7cf06
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/aspect/admin/MQAdminAspect.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.aspect.admin;
+
+import java.lang.reflect.Method;
+import 
org.apache.rocketmq.console.aspect.admin.annotation.MultiMQAdminCmdMethod;
+import org.apache.rocketmq.console.service.client.MQAdminInstance;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+@Aspect
+@Service
+public class MQAdminAspect {
+    private Logger logger = LoggerFactory.getLogger(MQAdminAspect.class);
+
+    public MQAdminAspect() {
+    }
+
+    @Pointcut("execution(* 
org.apache.rocketmq.console.service.client.MQAdminExtImpl..*(..))")
+    public void mQAdminMethodPointCut() {
+
+    }
+
+    
@Pointcut("@annotation(org.apache.rocketmq.console.aspect.admin.annotation.MultiMQAdminCmdMethod)")
+    public void multiMQAdminMethodPointCut() {
+
+    }
+
+    @Around(value = "mQAdminMethodPointCut() || multiMQAdminMethodPointCut()")
+    public Object aroundMQAdminMethod(ProceedingJoinPoint joinPoint) throws 
Throwable {
+        long start = System.currentTimeMillis();
+        Object obj = null;
+        try {
+            MethodSignature signature = 
(MethodSignature)joinPoint.getSignature();
+            Method method = signature.getMethod();
+            MultiMQAdminCmdMethod multiMQAdminCmdMethod = 
method.getAnnotation(MultiMQAdminCmdMethod.class);
+            if (multiMQAdminCmdMethod != null && 
multiMQAdminCmdMethod.timeoutMillis() > 0) {
+                
MQAdminInstance.initMQAdminInstance(multiMQAdminCmdMethod.timeoutMillis());
+            }
+            else {
+                MQAdminInstance.initMQAdminInstance(0);
+            }
+            obj = joinPoint.proceed();
+        }
+        finally {
+            MQAdminInstance.destroyMQAdminInstance();
+            logger.debug("op=look method={} cost={}", 
joinPoint.getSignature().getName(), System.currentTimeMillis() - start);
+        }
+        return obj;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/aspect/admin/annotation/MultiMQAdminCmdMethod.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/aspect/admin/annotation/MultiMQAdminCmdMethod.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/aspect/admin/annotation/MultiMQAdminCmdMethod.java
new file mode 100644
index 0000000..103e094
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/aspect/admin/annotation/MultiMQAdminCmdMethod.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.rocketmq.console.aspect.admin.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface MultiMQAdminCmdMethod {
+    long timeoutMillis() default 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/aspect/admin/annotation/OriginalControllerReturnValue.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/aspect/admin/annotation/OriginalControllerReturnValue.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/aspect/admin/annotation/OriginalControllerReturnValue.java
new file mode 100644
index 0000000..9a31bd3
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/aspect/admin/annotation/OriginalControllerReturnValue.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.rocketmq.console.aspect.admin.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface OriginalControllerReturnValue {
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/config/RMQConfigure.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/config/RMQConfigure.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/config/RMQConfigure.java
new file mode 100644
index 0000000..0d9457e
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/config/RMQConfigure.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.config;
+
+import java.io.File;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rocketmq.common.MixAll;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import static 
org.apache.rocketmq.client.ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY;
+
+@Configuration
+@ConfigurationProperties(prefix = "rocketmq.config")
+public class RMQConfigure {
+
+    private Logger logger = LoggerFactory.getLogger(RMQConfigure.class);
+    //use rocketmq.namesrv.addr first,if it is empty,than use system proerty 
or system env
+    private volatile String namesrvAddr = 
System.getProperty(MixAll.NAMESRV_ADDR_PROPERTY, 
System.getenv(MixAll.NAMESRV_ADDR_ENV));
+
+    private volatile String isVIPChannel = 
System.getProperty(SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "true");
+
+
+    private String dataPath;
+
+    private boolean enableDashBoardCollect;
+
+    public String getNamesrvAddr() {
+        return namesrvAddr;
+    }
+
+    public void setNamesrvAddr(String namesrvAddr) {
+        if (StringUtils.isNotBlank(namesrvAddr)) {
+            this.namesrvAddr = namesrvAddr;
+            System.setProperty(MixAll.NAMESRV_ADDR_PROPERTY, namesrvAddr);
+            logger.info("setNameSrvAddrByProperty nameSrvAddr={}", 
namesrvAddr);
+        }
+    }
+
+    public String getRocketMqConsoleDataPath() {
+        return dataPath;
+    }
+
+    public String getConsoleCollectData() {
+        return dataPath + File.separator + "dashboard";
+    }
+
+    public void setDataPath(String dataPath) {
+        this.dataPath = dataPath;
+    }
+
+    public String getIsVIPChannel() {
+        return isVIPChannel;
+    }
+
+    public void setIsVIPChannel(String isVIPChannel) {
+        if (StringUtils.isNotBlank(isVIPChannel)) {
+            this.isVIPChannel = isVIPChannel;
+            System.setProperty(SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, 
isVIPChannel);
+            logger.info("setIsVIPChannel isVIPChannel={}", isVIPChannel);
+        }
+    }
+
+    public boolean isEnableDashBoardCollect() {
+        return enableDashBoardCollect;
+    }
+
+    public void setEnableDashBoardCollect(String enableDashBoardCollect) {
+        this.enableDashBoardCollect = Boolean.valueOf(enableDashBoardCollect);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/ClusterController.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/ClusterController.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/ClusterController.java
new file mode 100644
index 0000000..718f75d
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/ClusterController.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.controller;
+
+import org.apache.rocketmq.console.service.ClusterService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.annotation.Resource;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping("/cluster")
+public class ClusterController {
+
+    @Resource
+    private ClusterService clusterService;
+
+    @RequestMapping(value = "/list.query", method = RequestMethod.GET)
+    @ResponseBody
+    public Object list() {
+        return clusterService.list();
+    }
+
+    @RequestMapping(value = "/brokerConfig.query", method = RequestMethod.GET)
+    @ResponseBody
+    public Object brokerConfig(@RequestParam String brokerAddr) {
+        return clusterService.getBrokerConfig(brokerAddr);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/ConsumerController.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/ConsumerController.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/ConsumerController.java
new file mode 100644
index 0000000..107e7c9
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/ConsumerController.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.controller;
+
+import com.google.common.base.Preconditions;
+import javax.annotation.Resource;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
+import org.apache.rocketmq.console.model.ConnectionInfo;
+import org.apache.rocketmq.console.model.request.ConsumerConfigInfo;
+import org.apache.rocketmq.console.model.request.DeleteSubGroupRequest;
+import org.apache.rocketmq.console.model.request.ResetOffsetRequest;
+import org.apache.rocketmq.console.service.ConsumerService;
+import org.apache.rocketmq.console.util.JsonUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping("/consumer")
+public class ConsumerController {
+    private Logger logger = LoggerFactory.getLogger(ConsumerController.class);
+
+    @Resource
+    private ConsumerService consumerService;
+
+    @RequestMapping(value = "/groupList.query")
+    @ResponseBody
+    public Object list() {
+        return consumerService.queryGroupList();
+    }
+
+    @RequestMapping(value = "/group.query")
+    @ResponseBody
+    public Object groupQuery(@RequestParam String consumerGroup) {
+        return consumerService.queryGroup(consumerGroup);
+    }
+
+    @RequestMapping(value = "/resetOffset.do", method = {RequestMethod.POST})
+    @ResponseBody
+    public Object resetOffset(@RequestBody ResetOffsetRequest 
resetOffsetRequest) {
+        logger.info("op=look resetOffsetRequest={}", 
JsonUtil.obj2String(resetOffsetRequest));
+        return consumerService.resetOffset(resetOffsetRequest);
+    }
+
+    @RequestMapping(value = "/examineSubscriptionGroupConfig.query")
+    @ResponseBody
+    public Object examineSubscriptionGroupConfig(@RequestParam String 
consumerGroup) {
+        return consumerService.examineSubscriptionGroupConfig(consumerGroup);
+    }
+
+    @RequestMapping(value = "/deleteSubGroup.do", method = 
{RequestMethod.POST})
+    @ResponseBody
+    public Object deleteSubGroup(@RequestBody DeleteSubGroupRequest 
deleteSubGroupRequest) {
+        return consumerService.deleteSubGroup(deleteSubGroupRequest);
+    }
+
+    @RequestMapping(value = "/createOrUpdate.do", method = 
{RequestMethod.POST})
+    @ResponseBody
+    public Object consumerCreateOrUpdateRequest(@RequestBody 
ConsumerConfigInfo consumerConfigInfo) {
+        
Preconditions.checkArgument(CollectionUtils.isNotEmpty(consumerConfigInfo.getBrokerNameList())
 || CollectionUtils.isNotEmpty(consumerConfigInfo.getClusterNameList()),
+            "clusterName or brokerName can not be all blank");
+        return 
consumerService.createAndUpdateSubscriptionGroupConfig(consumerConfigInfo);
+    }
+
+    @RequestMapping(value = "/fetchBrokerNameList.query", method = 
{RequestMethod.GET})
+    @ResponseBody
+    public Object fetchBrokerNameList(@RequestParam String consumerGroup) {
+        return 
consumerService.fetchBrokerNameSetBySubscriptionGroup(consumerGroup);
+    }
+
+    @RequestMapping(value = "/queryTopicByConsumer.query")
+    @ResponseBody
+    public Object queryConsumerByTopic(@RequestParam String consumerGroup) {
+        return consumerService.queryConsumeStatsListByGroupName(consumerGroup);
+    }
+
+    @RequestMapping(value = "/consumerConnection.query")
+    @ResponseBody
+    public Object consumerConnection(@RequestParam(required = false) String 
consumerGroup) {
+        ConsumerConnection consumerConnection = 
consumerService.getConsumerConnection(consumerGroup);
+        
consumerConnection.setConnectionSet(ConnectionInfo.buildConnectionInfoHashSet(consumerConnection.getConnectionSet()));
+        return consumerConnection;
+    }
+
+    @RequestMapping(value = "/consumerRunningInfo.query")
+    @ResponseBody
+    public Object getConsumerRunningInfo(@RequestParam String consumerGroup, 
@RequestParam String clientId,
+        @RequestParam boolean jstack) {
+        return consumerService.getConsumerRunningInfo(consumerGroup, clientId, 
jstack);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/DashboardController.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/DashboardController.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/DashboardController.java
new file mode 100644
index 0000000..985c028
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/DashboardController.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.console.controller;
+
+import javax.annotation.Resource;
+
+import com.google.common.base.Strings;
+import org.apache.rocketmq.console.service.DashboardService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping("/dashboard")
+public class DashboardController {
+
+    @Resource
+    DashboardService dashboardService;
+
+    @RequestMapping(value = "/broker.query", method = RequestMethod.GET)
+    @ResponseBody
+    public Object broker(@RequestParam String date) {
+        return dashboardService.queryBrokerData(date);
+    }
+
+    @RequestMapping(value = "/topic.query", method = RequestMethod.GET)
+    @ResponseBody
+    public Object topic(@RequestParam String date, String topicName) {
+        if (Strings.isNullOrEmpty(topicName)) {
+            return dashboardService.queryTopicData(date);
+        }
+        return dashboardService.queryTopicData(date,topicName);
+    }
+
+    @RequestMapping(value = "/topicCurrent", method = RequestMethod.GET)
+    @ResponseBody
+    public Object topicCurrent() {
+        return dashboardService.queryTopicCurrentData();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/MessageController.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/MessageController.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/MessageController.java
new file mode 100644
index 0000000..dd3cdb8
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/MessageController.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.controller;
+
+import org.apache.rocketmq.common.Pair;
+import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
+import org.apache.rocketmq.tools.admin.api.MessageTrack;
+import org.apache.rocketmq.console.model.MessageView;
+import org.apache.rocketmq.console.service.MessageService;
+import org.apache.rocketmq.console.util.JsonUtil;
+import com.google.common.collect.Maps;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping("/message")
+public class MessageController {
+    private Logger logger = LoggerFactory.getLogger(MessageController.class);
+    @Resource
+    private MessageService messageService;
+
+    @RequestMapping(value = "/viewMessage.query", method = RequestMethod.GET)
+    @ResponseBody
+    public Object viewMessage(@RequestParam(required = false) String topic, 
@RequestParam String msgId) {
+        Map<String, Object> messageViewMap = Maps.newHashMap();
+        Pair<MessageView, List<MessageTrack>> messageViewListPair = 
messageService.viewMessage(topic, msgId);
+        messageViewMap.put("messageView", messageViewListPair.getObject1());
+        messageViewMap.put("messageTrackList", 
messageViewListPair.getObject2());
+        return messageViewMap;
+    }
+
+    @RequestMapping(value = "/queryMessageByTopicAndKey.query", method = 
RequestMethod.GET)
+    @ResponseBody
+    public Object queryMessageByTopicAndKey(@RequestParam String topic, 
@RequestParam String key) {
+        return messageService.queryMessageByTopicAndKey(topic, key);
+    }
+
+    @RequestMapping(value = "/queryMessageByTopic.query", method = 
RequestMethod.GET)
+    @ResponseBody
+    public Object queryMessageByTopic(@RequestParam String topic, 
@RequestParam long begin,
+        @RequestParam long end) {
+        return messageService.queryMessageByTopic(topic, begin, end);
+    }
+
+    @RequestMapping(value = "/consumeMessageDirectly.do", method = 
RequestMethod.POST)
+    @ResponseBody
+    public Object consumeMessageDirectly(@RequestParam String topic, 
@RequestParam String consumerGroup,
+        @RequestParam String msgId,
+        @RequestParam(required = false) String clientId) {
+        logger.info("msgId={} consumerGroup={} clientId={}", msgId, 
consumerGroup, clientId);
+        ConsumeMessageDirectlyResult consumeMessageDirectlyResult = 
messageService.consumeMessageDirectly(topic, msgId, consumerGroup, clientId);
+        logger.info("consumeMessageDirectlyResult={}", 
JsonUtil.obj2String(consumeMessageDirectlyResult));
+        return consumeMessageDirectlyResult;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/MonitorController.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/MonitorController.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/MonitorController.java
new file mode 100644
index 0000000..8bc89e9
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/MonitorController.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.controller;
+
+import javax.annotation.Resource;
+import org.apache.rocketmq.console.model.ConsumerMonitorConfig;
+import org.apache.rocketmq.console.service.MonitorService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping("/monitor")
+public class MonitorController {
+
+    private Logger logger = LoggerFactory.getLogger(MonitorController.class);
+    @Resource
+    private MonitorService monitorService;
+
+    @RequestMapping(value = "/createOrUpdateConsumerMonitor.do", method = 
{RequestMethod.POST})
+    @ResponseBody
+    public Object createOrUpdateConsumerMonitor(@RequestParam String 
consumeGroupName, @RequestParam int minCount,
+        @RequestParam int maxDiffTotal) {
+        return monitorService.createOrUpdateConsumerMonitor(consumeGroupName, 
new ConsumerMonitorConfig(minCount, maxDiffTotal));
+    }
+
+    @RequestMapping(value = "/consumerMonitorConfig.query", method = 
{RequestMethod.GET})
+    @ResponseBody
+    public Object consumerMonitorConfig() {
+        return monitorService.queryConsumerMonitorConfig();
+    }
+
+    @RequestMapping(value = "/consumerMonitorConfigByGroupName.query", method 
= {RequestMethod.GET})
+    @ResponseBody
+    public Object consumerMonitorConfigByGroupName(@RequestParam String 
consumeGroupName) {
+        return 
monitorService.queryConsumerMonitorConfigByGroupName(consumeGroupName);
+    }
+
+    @RequestMapping(value = "/deleteConsumerMonitor.do", method = 
{RequestMethod.POST})
+    @ResponseBody
+    public Object deleteConsumerMonitor(@RequestParam String consumeGroupName) 
{
+        return monitorService.deleteConsumerMonitor(consumeGroupName);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/NamesvrController.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/NamesvrController.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/NamesvrController.java
new file mode 100644
index 0000000..ad6c25a
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/NamesvrController.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.controller;
+
+import javax.annotation.Resource;
+import 
org.apache.rocketmq.console.aspect.admin.annotation.OriginalControllerReturnValue;
+import org.apache.rocketmq.console.service.OpsService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping("/rocketmq")
+public class NamesvrController {
+    @Resource
+    private OpsService opsService;
+
+    @RequestMapping(value = "/nsaddr", method = RequestMethod.GET)
+    @ResponseBody
+    @OriginalControllerReturnValue
+    public Object nsaddr() {
+        return opsService.getNameSvrList();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/OpsController.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/OpsController.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/OpsController.java
new file mode 100644
index 0000000..d82862f
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/OpsController.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.controller;
+
+import javax.annotation.Resource;
+import org.apache.rocketmq.console.service.OpsService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping("/ops")
+public class OpsController {
+
+    @Resource
+    private OpsService opsService;
+
+    @RequestMapping(value = "/homePage.query", method = RequestMethod.GET)
+    @ResponseBody
+    public Object homePage() {
+        return opsService.homePageInfo();
+    }
+
+    @RequestMapping(value = "/updateNameSvrAddr.do", method = 
RequestMethod.POST)
+    @ResponseBody
+    public Object updateNameSvrAddr(@RequestParam String nameSvrAddrList) {
+        opsService.updateNameSvrAddrList(nameSvrAddrList);
+        return true;
+    }
+
+    @RequestMapping(value = "/updateIsVIPChannel.do", method = 
RequestMethod.POST)
+    @ResponseBody
+    public Object updateIsVIPChannel(@RequestParam String useVIPChannel) {
+        opsService.updateIsVIPChannel(useVIPChannel);
+        return true;
+    }
+
+
+    @RequestMapping(value = "/rocketMqStatus.query", method = 
RequestMethod.GET)
+    @ResponseBody
+    public Object clusterStatus() {
+        return opsService.rocketMqStatusCheck();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/ProducerController.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/ProducerController.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/ProducerController.java
new file mode 100644
index 0000000..1a69de5
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/ProducerController.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.controller;
+
+import javax.annotation.Resource;
+import org.apache.rocketmq.common.protocol.body.ProducerConnection;
+import org.apache.rocketmq.console.model.ConnectionInfo;
+import org.apache.rocketmq.console.service.ProducerService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping("/producer")
+public class ProducerController {
+
+    @Resource
+    private ProducerService producerService;
+
+    @RequestMapping(value = "/producerConnection.query", method = 
{RequestMethod.GET})
+    @ResponseBody
+    public Object producerConnection(@RequestParam String producerGroup, 
@RequestParam String topic) {
+        ProducerConnection producerConnection = 
producerService.getProducerConnection(producerGroup, topic);
+        
producerConnection.setConnectionSet(ConnectionInfo.buildConnectionInfoHashSet(producerConnection.getConnectionSet()));
+        return producerConnection;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/TestController.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/TestController.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/TestController.java
new file mode 100644
index 0000000..d7af1ad
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/TestController.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.controller;
+
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import 
org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.remoting.exception.RemotingException;
+import java.util.List;
+import javax.annotation.Resource;
+import org.apache.rocketmq.console.config.RMQConfigure;
+import org.apache.rocketmq.console.util.JsonUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping("/test")
+public class TestController {
+    private Logger logger = LoggerFactory.getLogger(TestController.class);
+    private String testTopic = "TestTopic";
+
+    @Resource
+    private RMQConfigure rMQConfigure;
+
+    @RequestMapping(value = "/runTask.do", method = RequestMethod.GET)
+    @ResponseBody
+    public Object list() throws MQClientException, RemotingException, 
InterruptedException {
+        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(testTopic + 
"Group");
+        consumer.setNamesrvAddr(rMQConfigure.getNamesrvAddr());
+        
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
+        consumer.subscribe(testTopic, "*");
+        consumer.registerMessageListener(new MessageListenerConcurrently() {
+
+            @Override
+            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> 
msgs,
+                ConsumeConcurrentlyContext context) {
+                logger.info("receiveMessage msgSize={}", msgs.size());
+                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+            }
+        });
+        consumer.start();
+        final DefaultMQProducer producer = new DefaultMQProducer(testTopic + 
"Group");
+        producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
+        producer.setNamesrvAddr(rMQConfigure.getNamesrvAddr());
+        producer.start();
+
+        new Thread(new Runnable() {
+
+            @Override public void run() {
+
+                int i = 0;
+                while (true) {
+                    try {
+                        Message msg = new Message(testTopic,
+                            "TagA" + i,
+                            "KEYS" + i,
+                            ("Hello RocketMQ " + i).getBytes()
+                        );
+                        Thread.sleep(1000L);
+                        SendResult sendResult = producer.send(msg);
+                        logger.info("sendMessage={}", 
JsonUtil.obj2String(sendResult));
+                    }
+                    catch (Exception e) {
+                        e.printStackTrace();
+                        try {
+                            Thread.sleep(1000);
+                        }
+                        catch (Exception ignore) {
+                        }
+                    }
+                }
+            }
+        }).start();
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/TopicController.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/TopicController.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/TopicController.java
new file mode 100644
index 0000000..90819af
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/controller/TopicController.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.controller;
+
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.remoting.exception.RemotingException;
+import org.apache.rocketmq.console.model.request.SendTopicMessageRequest;
+import org.apache.rocketmq.console.model.request.TopicConfigInfo;
+import org.apache.rocketmq.console.service.ConsumerService;
+import org.apache.rocketmq.console.service.TopicService;
+import org.apache.rocketmq.console.util.JsonUtil;
+import com.google.common.base.Preconditions;
+import org.apache.commons.collections.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.annotation.Resource;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping("/topic")
+public class TopicController {
+    private Logger logger = LoggerFactory.getLogger(TopicController.class);
+
+    @Resource
+    private TopicService topicService;
+
+    @Resource
+    private ConsumerService consumerService;
+
+    @RequestMapping(value = "/list.query", method = RequestMethod.GET)
+    @ResponseBody
+    public Object list() throws MQClientException, RemotingException, 
InterruptedException {
+        return topicService.fetchAllTopicList();
+    }
+
+    @RequestMapping(value = "/stats.query", method = RequestMethod.GET)
+    @ResponseBody
+    public Object stats(@RequestParam String topic) {
+        return topicService.stats(topic);
+    }
+
+    @RequestMapping(value = "/route.query", method = RequestMethod.GET)
+    @ResponseBody
+    public Object route(@RequestParam String topic) {
+        return topicService.route(topic);
+    }
+
+
+    @RequestMapping(value = "/createOrUpdate.do", method = { 
RequestMethod.POST})
+    @ResponseBody
+    public Object topicCreateOrUpdateRequest(@RequestBody TopicConfigInfo 
topicCreateOrUpdateRequest) {
+        
Preconditions.checkArgument(CollectionUtils.isNotEmpty(topicCreateOrUpdateRequest.getBrokerNameList())
 || CollectionUtils.isNotEmpty(topicCreateOrUpdateRequest.getClusterNameList()),
+            "clusterName or brokerName can not be all blank");
+        logger.info("op=look topicCreateOrUpdateRequest={}", 
JsonUtil.obj2String(topicCreateOrUpdateRequest));
+        topicService.createOrUpdate(topicCreateOrUpdateRequest);
+        return true;
+    }
+
+    @RequestMapping(value = "/queryConsumerByTopic.query")
+    @ResponseBody
+    public Object queryConsumerByTopic(@RequestParam String topic) {
+        return consumerService.queryConsumeStatsListByTopicName(topic);
+    }
+
+    @RequestMapping(value = "/queryTopicConsumerInfo.query")
+    @ResponseBody
+    public Object queryTopicConsumerInfo(@RequestParam String topic) {
+        return topicService.queryTopicConsumerInfo(topic);
+    }
+
+    @RequestMapping(value = "/examineTopicConfig.query")
+    @ResponseBody
+    public Object examineTopicConfig(@RequestParam String topic,
+        @RequestParam(required = false) String brokerName) throws 
RemotingException, MQClientException, InterruptedException {
+        return topicService.examineTopicConfig(topic);
+    }
+
+    @RequestMapping(value = "/sendTopicMessage.do", method = 
{RequestMethod.POST})
+    @ResponseBody
+    public Object sendTopicMessage(
+        @RequestBody SendTopicMessageRequest sendTopicMessageRequest) throws 
RemotingException, MQClientException, InterruptedException {
+        return topicService.sendTopicMessageRequest(sendTopicMessageRequest);
+    }
+
+    @RequestMapping(value = "/deleteTopic.do", method = {RequestMethod.POST})
+    @ResponseBody
+    public Object delete(@RequestParam(required = false) String clusterName, 
@RequestParam String topic) {
+        return topicService.deleteTopic(topic, clusterName);
+    }
+
+    @RequestMapping(value = "/deleteTopicByBroker.do", method = 
{RequestMethod.POST})
+    @ResponseBody
+    public Object deleteTopicByBroker(@RequestParam String brokerName, 
@RequestParam String topic) {
+        return topicService.deleteTopicInBroker(brokerName, topic);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/exception/ServiceException.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/exception/ServiceException.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/exception/ServiceException.java
new file mode 100644
index 0000000..7ad166b
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/exception/ServiceException.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.exception;
+
+public class ServiceException extends RuntimeException {
+    private static final long serialVersionUID = 9213584003139969215L;
+    private int code;
+
+    public ServiceException(int code, String message) {
+        super(message);
+        this.code = code;
+    }
+
+    public int getCode() {
+        return code;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/model/ConnectionInfo.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/model/ConnectionInfo.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/model/ConnectionInfo.java
new file mode 100644
index 0000000..6e8dd19
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/model/ConnectionInfo.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.model;
+
+import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.HashSet;
+import org.apache.rocketmq.common.MQVersion;
+import org.apache.rocketmq.common.protocol.body.Connection;
+
+public class ConnectionInfo extends Connection {
+    private String versionDesc;
+
+    public static ConnectionInfo buildConnectionInfo(Connection connection) {
+        ConnectionInfo connectionInfo = new ConnectionInfo();
+        connectionInfo.setClientId(connection.getClientId());
+        connectionInfo.setClientAddr(connection.getClientAddr());
+        connectionInfo.setLanguage(connection.getLanguage());
+        connectionInfo.setVersion(connection.getVersion());
+        
connectionInfo.setVersionDesc(MQVersion.getVersionDesc(connection.getVersion()));
+        return connectionInfo;
+    }
+
+    public static HashSet<Connection> 
buildConnectionInfoHashSet(Collection<Connection> connectionList) {
+        HashSet<Connection> connectionHashSet = Sets.newHashSet();
+        for (Connection connection : connectionList) {
+            connectionHashSet.add(buildConnectionInfo(connection));
+        }
+        return connectionHashSet;
+    }
+
+    public String getVersionDesc() {
+        return versionDesc;
+    }
+
+    public void setVersionDesc(String versionDesc) {
+        this.versionDesc = versionDesc;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/model/ConsumerGroupRollBackStat.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/model/ConsumerGroupRollBackStat.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/model/ConsumerGroupRollBackStat.java
new file mode 100644
index 0000000..3ddfe07
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/model/ConsumerGroupRollBackStat.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.model;
+
+import org.apache.rocketmq.common.admin.RollbackStats;
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+public class ConsumerGroupRollBackStat {
+    private boolean status;
+    private String errMsg;
+    private List<RollbackStats> rollbackStatsList = Lists.newArrayList();
+
+    public ConsumerGroupRollBackStat(boolean status) {
+        this.status = status;
+    }
+
+    public ConsumerGroupRollBackStat(boolean status, String errMsg) {
+        this.status = status;
+        this.errMsg = errMsg;
+    }
+
+    public String getErrMsg() {
+        return errMsg;
+    }
+
+    public void setErrMsg(String errMsg) {
+        this.errMsg = errMsg;
+    }
+
+    public boolean isStatus() {
+        return status;
+    }
+
+    public void setStatus(boolean status) {
+        this.status = status;
+    }
+
+    public List<RollbackStats> getRollbackStatsList() {
+        return rollbackStatsList;
+    }
+
+    public void setRollbackStatsList(List<RollbackStats> rollbackStatsList) {
+        this.rollbackStatsList = rollbackStatsList;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/4b8f1357/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/model/ConsumerMonitorConfig.java
----------------------------------------------------------------------
diff --git 
a/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/model/ConsumerMonitorConfig.java
 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/model/ConsumerMonitorConfig.java
new file mode 100644
index 0000000..9124f00
--- /dev/null
+++ 
b/rocketmq-console-ng/src/main/java/org/apache/rocketmq/console/model/ConsumerMonitorConfig.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.rocketmq.console.model;
+
+public class ConsumerMonitorConfig {
+    private int minCount;
+    private int maxDiffTotal;
+
+    public ConsumerMonitorConfig() {
+    }
+
+    public ConsumerMonitorConfig(int minCount, int maxDiffTotal) {
+        this.minCount = minCount;
+        this.maxDiffTotal = maxDiffTotal;
+    }
+
+    public int getMinCount() {
+        return minCount;
+    }
+
+    public void setMinCount(int minCount) {
+        this.minCount = minCount;
+    }
+
+    public int getMaxDiffTotal() {
+        return maxDiffTotal;
+    }
+
+    public void setMaxDiffTotal(int maxDiffTotal) {
+        this.maxDiffTotal = maxDiffTotal;
+    }
+}

Reply via email to