Repository: alibaba/fescar
Pull request #377 (2019-02-11 08:58:01)

release 0.1.4
<!-- Please make sure you have read and understood the contributing guidelines -->

### Ⅰ. Describe what this PR did
release 0.1.4

### Ⅱ. Does this pull request fix one issue?



### Ⅲ. Why don't you add test cases (unit test/integration test)? 


### Ⅳ. Describe how to verify it


### Ⅴ. Special notes for reviews



codecov-io: # [Codecov](https://codecov.io/gh/alibaba/fescar/pull/377?src=pr&el=h1) Report
> Merging [#377](https://codecov.io/gh/alibaba/fescar/pull/377?src=pr&el=desc) into [master](https://codecov.io/gh/alibaba/fescar/commit/cca20cd6f4faf357ccee11dec152592a2b7ed532?src=pr&el=desc) will **increase** coverage by `8.43%`.
> The diff coverage is `45.94%`.

[![Impacted file tree graph](https://codecov.io/gh/alibaba/fescar/pull/377/graphs/tree.svg?width=650&token=Hy9a6MCc4p&height=150&src=pr)](https://codecov.io/gh/alibaba/fescar/pull/377?src=pr&el=tree)

```diff
@@             Coverage Diff              @@
##             master     #377      +/-   ##
============================================
+ Coverage     20.63%   29.06%   +8.43%     
- Complexity        0      570     +570     
============================================
  Files           184      165      -19     
  Lines          6940     6588     -352     
  Branches        951      786     -165     
============================================
+ Hits           1432     1915     +483     
+ Misses         5358     4469     -889     
- Partials        150      204      +54
```


| [Impacted Files](https://codecov.io/gh/alibaba/fescar/pull/377?src=pr&el=tree) | Coverage Δ | Complexity Δ | |
|---|---|---|---|
| [...m/alibaba/fescar/tm/api/TransactionalTemplate.java](https://codecov.io/gh/alibaba/fescar/pull/377/diff?src=pr&el=tree#diff-dG0vc3JjL21haW4vamF2YS9jb20vYWxpYmFiYS9mZXNjYXIvdG0vYXBpL1RyYW5zYWN0aW9uYWxUZW1wbGF0ZS5qYXZh) | `68.42% <ø> (+68.42%)` | `2 <0> (+2)` | :arrow_up: |
| [...java/com/alibaba/fescar/core/protocol/Version.java](https://codecov.io/gh/alibaba/fescar/pull/377/diff?src=pr&el=tree#diff-Y29yZS9zcmMvbWFpbi9qYXZhL2NvbS9hbGliYWJhL2Zlc2Nhci9jb3JlL3Byb3RvY29sL1ZlcnNpb24uamF2YQ==) | `0% <ø> (ø)` | `0 <0> (ø)` | :arrow_down: |
| [...ibaba/fescar/core/rpc/netty/NettyServerConfig.java](https://codecov.io/gh/alibaba/fescar/pull/377/diff?src=pr&el=tree#diff-Y29yZS9zcmMvbWFpbi9qYXZhL2NvbS9hbGliYWJhL2Zlc2Nhci9jb3JlL3JwYy9uZXR0eS9OZXR0eVNlcnZlckNvbmZpZy5qYXZh) | `0% <ø> (ø)` | `0 <0> (ø)` | :arrow_down: |
| [...ar/rm/datasource/exec/AbstractDMLBaseExecutor.java](https://codecov.io/gh/alibaba/fescar/pull/377/diff?src=pr&el=tree#diff-cm0tZGF0YXNvdXJjZS9zcmMvbWFpbi9qYXZhL2NvbS9hbGliYWJhL2Zlc2Nhci9ybS9kYXRhc291cmNlL2V4ZWMvQWJzdHJhY3RETUxCYXNlRXhlY3V0b3IuamF2YQ==) | `0% <0%> (ø)` | `0 <0> (ø)` | :arrow_down: |
| [...ibaba/fescar/tm/api/DefaultFailureHandlerImpl.java](https://codecov.io/gh/alibaba/fescar/pull/377/diff?src=pr&el=tree#diff-dG0vc3JjL21haW4vamF2YS9jb20vYWxpYmFiYS9mZXNjYXIvdG0vYXBpL0RlZmF1bHRGYWlsdXJlSGFuZGxlckltcGwuamF2YQ==) | `0% <0%> (ø)` | `0 <0> (ø)` | :arrow_down: |
| [...rc/main/java/com/alibaba/fescar/server/Server.java](https://codecov.io/gh/alibaba/fescar/pull/377/diff?src=pr&el=tree#diff-c2VydmVyL3NyYy9tYWluL2phdmEvY29tL2FsaWJhYmEvZmVzY2FyL3NlcnZlci9TZXJ2ZXIuamF2YQ==) | `0% <0%> (ø)` | `0 <0> (ø)` | :arrow_down: |
| [...ar/rm/datasource/exec/SelectForUpdateExecutor.java](https://codecov.io/gh/alibaba/fescar/pull/377/diff?src=pr&el=tree#diff-cm0tZGF0YXNvdXJjZS9zcmMvbWFpbi9qYXZhL2NvbS9hbGliYWJhL2Zlc2Nhci9ybS9kYXRhc291cmNlL2V4ZWMvU2VsZWN0Rm9yVXBkYXRlRXhlY3V0b3IuamF2YQ==) | `0% <0%> (ø)` | `0 <0> (ø)` | :arrow_down: |
| [.../alibaba/fescar/rm/datasource/ConnectionProxy.java](https://codecov.io/gh/alibaba/fescar/pull/377/diff?src=pr&el=tree#diff-cm0tZGF0YXNvdXJjZS9zcmMvbWFpbi9qYXZhL2NvbS9hbGliYWJhL2Zlc2Nhci9ybS9kYXRhc291cmNlL0Nvbm5lY3Rpb25Qcm94eS5qYXZh) | `0% <0%> (ø)` | `0 <0> (ø)` | :arrow_down: |
| [.../rm/datasource/exec/BaseTransactionalExecutor.java](https://codecov.io/gh/alibaba/fescar/pull/377/diff?src=pr&el=tree#diff-cm0tZGF0YXNvdXJjZS9zcmMvbWFpbi9qYXZhL2NvbS9hbGliYWJhL2Zlc2Nhci9ybS9kYXRhc291cmNlL2V4ZWMvQmFzZVRyYW5zYWN0aW9uYWxFeGVjdXRvci5qYXZh) | `0% <0%> (ø)` | `0 <0> (ø)` | :arrow_down: |
| [...m/alibaba/fescar/tm/DefaultTransactionManager.java](https://codecov.io/gh/alibaba/fescar/pull/377/diff?src=pr&el=tree#diff-dG0vc3JjL21haW4vamF2YS9jb20vYWxpYmFiYS9mZXNjYXIvdG0vRGVmYXVsdFRyYW5zYWN0aW9uTWFuYWdlci5qYXZh) | `14.81% <100%> (-5.88%)` | `2 <1> (+2)` | |
| ... and [75 more](https://codecov.io/gh/alibaba/fescar/pull/377/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/alibaba/fescar/pull/377?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/alibaba/fescar/pull/377?src=pr&el=footer). Last update [cca20cd...2f8845b](https://codecov.io/gh/alibaba/fescar/pull/377?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/.travis.yml b/.travis.yml
index 23124712b..0223be4c4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,8 @@ language: java
 sudo: false # faster builds
 
 jdk:
-  - openjdk7
+  - openjdk11
+  - openjdk8
 
 cache:
   directories:
@@ -12,7 +13,6 @@ install: true
 
 script:
   - mvn clean package
-  - mvn cobertura:cobertura
 
 after_success:
   - bash <(curl -s https://codecov.io/bash)
\ No newline at end of file
diff --git a/README.md b/README.md
index 475aaf33e..b905b14d1 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,13 @@
-# FESCAR: Fast & Easy Commit And Rollback
+<img src="https://github.com/fescar-group/fescar-samples/blob/master/doc/img/fescar.png"  height="100" width="426">
+
+# Fescar: Fast & Easy Commit And Rollback
 
 [![Build Status](https://travis-ci.org/alibaba/fescar.svg?branch=develop)](https://travis-ci.org/alibaba/fescar)
 [![codecov](https://codecov.io/gh/alibaba/fescar/branch/develop/graph/badge.svg)](https://codecov.io/gh/alibaba/fescar)
 ![license](https://img.shields.io/github/license/alibaba/fescar.svg)
+![maven](https://img.shields.io/maven-central/v/com.alibaba.fescar/fescar-all.svg)
 
-## What is FESCAR?
+## What is Fescar?
 
 A **distributed transaction solution** with high performance and ease of use for **microservices** architecture.
 
@@ -22,11 +25,11 @@ Things have changed in microservices architecture. The 3 modules mentioned above
 
 ![Microservices Problem](https://cdn.nlark.com/lark/0/2018/png/18862/1545296781231-4029da9c-8803-43a4-ac2f-6c8b1e2ea448.png) 
 
-### How FESCAR do?
+### How Fescar do?
 
-FESCAR is just a solution to the problem mentioned above. 
+Fescar is just a solution to the problem mentioned above. 
 
-![FESCAR solution](https://cdn.nlark.com/lark/0/2018/png/18862/1545296791074-3bce7bce-025e-45c3-9386-7b95135dade8.png)
+![Fescar solution](https://cdn.nlark.com/lark/0/2018/png/18862/1545296791074-3bce7bce-025e-45c3-9386-7b95135dade8.png)
 
 Firstly, how to define a **Distributed Transaction**?
 
@@ -34,7 +37,7 @@ We say, a **Distributed Transaction** is a **Global Transaction** which is made
 
 ![Global & Branch](https://cdn.nlark.com/lark/0/2018/png/18862/1545015454979-a18e16f6-ed41-44f1-9c7a-bd82c4d5ff99.png) 
 
-There are 3 basic components in FESCAR: 
+There are 3 basic components in Fescar: 
 
 - **Transaction Coordinator(TC):** Maintain status of global and branch transactions, drive the global commit or rollback.
 - **Transaction Manager(TM):** Define the scope of global transaction: begin a global transaction, commit or rollback a global transaction.
@@ -42,7 +45,7 @@ There are 3 basic components in FESCAR:
 
 ![Model](https://cdn.nlark.com/lark/0/2018/png/18862/1545013915286-4a90f0df-5fda-41e1-91e0-2aa3d331c035.png) 
 
-A typical lifecycle of FESCAR managed distributed transaction:
+A typical lifecycle of Fescar managed distributed transaction:
 
 1. TM asks TC to begin a new global transaction. TC generates an XID representing the global transaction.
 2. XID is propagated through microservices' invoke chain.
@@ -52,26 +55,36 @@ A typical lifecycle of FESCAR managed distributed transaction:
 
 ![Typical Process](https://cdn.nlark.com/lark/0/2018/png/18862/1545296917881-26fabeb9-71fa-4f3e-8a7a-fc317d3389f4.png) 
 
-For more details about principle and design, please go to [FESCAR wiki page](https://github.com/alibaba/fescar/wiki). 
+For more details about principle and design, please go to [Fescar wiki page](https://github.com/alibaba/fescar/wiki). 
 
 ### History
 
 - **TXC**: Taobao Transaction Constructor. Alibaba middleware team start this project since 2014 to meet distributed transaction problem caused by application architecture change from monolithic to microservices.
 - **GTS**: Global Transaction Service. TXC as an Aliyun middleware product with new name GTS was published since 2016.
-- **FESCAR**: we start the open source project FESCAR based on TXC/GTS since 2019 to work closely with the community in the future.
+- **Fescar**: we start the open source project Fescar based on TXC/GTS since 2019 to work closely with the community in the future.
+
+## Maven dependency
+```xml
+<fescar.version>0.1.3</fescar.version>
 
+<dependency>
+    <groupId>com.alibaba.fescar</groupId>
+    <artifactId>fescar-all</artifactId>
+    <version>${fescar.version}</version>
+</dependency>
 
+```
 ## Quick Start
 
 [Quick Start](https://github.com/alibaba/fescar/wiki/Quick-Start)
 
 ## Documentation
 
-You can view the full documentation from the wiki: [FESCAR wiki page](https://github.com/alibaba/fescar/wiki).
+You can view the full documentation from the wiki: [Fescar wiki page](https://github.com/alibaba/fescar/wiki).
 
 ## Reporting bugs
 
-Please follow the [template]() for reporting any issues.
+Please follow the [template](https://github.com/alibaba/fescar/blob/develop/.github/ISSUE_TEMPLATE/BUG_REPORT.md) for reporting any issues.
 
 
 ## Contributing
@@ -81,14 +94,29 @@ Contributors are welcomed to join the FEATS project. Please check [CONTRIBUTING]
 
 ## Contact
 
-* [Twitter](): TBD. Follow along for latest FESCAR news on Twitter.
+* [Twitter](): TBD. Follow along for latest Fescar news on Twitter.
 * Email Group:
-     * dev.fescar@gmail.com: FESCAR developer discussion (APIs, feature design, etc).
+     * dev.fescar@gmail.com: Fescar developer discussion (APIs, feature design, etc).
 
 **Dingtalk**
 
-![dingding.png](https://upload-images.jianshu.io/upload_images/4420767-4e95b186a1a1bfba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
+<img src="https://upload-images.jianshu.io/upload_images/4420767-4e95b186a1a1bfba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"  height="300" width="300">
+
+
+## Fescar ecosystem
+
+* [Fescar Ecosystem Entry](https://github.com/fescar-group) - A GitHub group `fescar-group` to gather all Fescar relevant projects not appropriate in [alibaba](https://github.com/alibaba) group yet
+* [Fescar Samples](https://github.com/fescar-group/fescar-samples) - Samples for Fescar
+* [Fescar Docker](https://github.com/fescar-group/fescar-docker) - Fescar integration with docker
+* [Fescar K8s](https://github.com/fescar-group/fescar-k8s) - Fescar integration with k8s
+* [Awesome Fescar](https://github.com/fescar-group/awesome-fescar) - Description of Fescar related projects 
+* [Fescar Website](https://github.com/fescar-group/fescar.io) - Fescar official website （***In the process of design***）
+
+## Contributors
+
+This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
+<a href="https://github.com/alibaba/fescar/graphs/contributors"><img src="https://opencollective.com/fescar/contributors.svg?width=890&button=false" /></a>
 
 ## License
 
-FESCAR is under the Apache 2.0 license. See the [LICENSE](https://github.com/alibaba/fescar/blob/master/LICENSE) file for details.
+Fescar is under the Apache 2.0 license. See the [LICENSE](https://github.com/alibaba/fescar/blob/master/LICENSE) file for details.
diff --git a/common/pom.xml b/common/pom.xml
index ffe0b37af..9a9d614a3 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -20,16 +20,12 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.3</version>
+        <version>0.1.4</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-common</artifactId>
     <packaging>jar</packaging>
     <name>fescar-common ${project.version}</name>
-    <properties>
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
-    </properties>
     <dependencies>
         <dependency>
             <groupId>io.netty</groupId>
diff --git a/config/pom.xml b/config/pom.xml
index d67646feb..6b36abae9 100644
--- a/config/pom.xml
+++ b/config/pom.xml
@@ -20,16 +20,12 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.3</version>
+        <version>0.1.4</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-config</artifactId>
     <packaging>jar</packaging>
     <name>fescar-config ${project.version}</name>
-    <properties>
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
-    </properties>
 
     <dependencies>
         <dependency>
diff --git a/core/pom.xml b/core/pom.xml
index 77f200066..a68f0fe85 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -21,16 +21,12 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.3</version>
+        <version>0.1.4</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-core</artifactId>
     <packaging>jar</packaging>
     <name>fescar-core ${project.version}</name>
-    <properties>
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
-    </properties>
 
     <dependencies>
         <dependency>
@@ -45,10 +41,6 @@
             <groupId>${project.groupId}</groupId>
             <artifactId>fescar-config</artifactId>
         </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-common</artifactId>
-        </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-pool2</artifactId>
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/AbstractIdentifyResponse.java b/core/src/main/java/com/alibaba/fescar/core/protocol/AbstractIdentifyResponse.java
index 38c717393..cbd4f3ecf 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/AbstractIdentifyResponse.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/AbstractIdentifyResponse.java
@@ -121,4 +121,26 @@ public abstract class AbstractIdentifyResponse extends AbstractResultMessage {
 
         return true;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("version=");
+        result.append(String.valueOf(version));
+        result.append(",");
+        result.append("extraData=");
+        result.append(String.valueOf(extraData));
+        result.append(",");
+        result.append("identified=");
+        result.append(String.valueOf(identified));
+        result.append(",");
+        result.append("resultCode=");
+        result.append(String.valueOf(getResultCode()));
+        result.append(",");
+        result.append("msg=");
+        result.append(String.valueOf(getMsg()));
+
+
+        return result.toString();
+    }
 }
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/Version.java b/core/src/main/java/com/alibaba/fescar/core/protocol/Version.java
index f7e4e93ac..88e63353a 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/Version.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/Version.java
@@ -31,7 +31,7 @@ public class Version {
     /**
      * The constant CURRENT.
      */
-    public static final String CURRENT = "0.1.3";
+    public static final String CURRENT = "0.1.4";
 
     /**
      * The constant VERSION_MAP.
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/BranchRegisterResponse.java b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/BranchRegisterResponse.java
index 3b4ad8ee4..de704c95a 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/BranchRegisterResponse.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/BranchRegisterResponse.java
@@ -16,6 +16,8 @@
 
 package com.alibaba.fescar.core.protocol.transaction;
 
+import com.alibaba.fescar.core.protocol.AbstractMessage;
+
 import java.io.Serializable;
 import java.nio.ByteBuffer;
 
@@ -87,4 +89,22 @@ public class BranchRegisterResponse extends AbstractTransactionResponse implemen
         this.transactionId = byteBuffer.getLong();
         this.branchId = byteBuffer.getLong();
     }
+
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("BranchRegisterResponse: transactionId=");
+        result.append(transactionId);
+        result.append(",");
+        result.append("branchId=");
+        result.append(branchId);
+        result.append(",");
+        result.append("result code =");
+        result.append(getResultCode());
+        result.append(",");
+        result.append("getMsg =");
+        result.append(getMsg());
+
+        return result.toString();
+    }
 }
diff --git a/core/src/main/java/com/alibaba/fescar/core/rpc/netty/NettyServerConfig.java b/core/src/main/java/com/alibaba/fescar/core/rpc/netty/NettyServerConfig.java
index b380e0be9..ee6d6f04a 100644
--- a/core/src/main/java/com/alibaba/fescar/core/rpc/netty/NettyServerConfig.java
+++ b/core/src/main/java/com/alibaba/fescar/core/rpc/netty/NettyServerConfig.java
@@ -16,9 +16,6 @@
 
 package com.alibaba.fescar.core.rpc.netty;
 
-import com.alibaba.fescar.config.Configuration;
-import com.alibaba.fescar.config.ConfigurationFactory;
-
 import io.netty.buffer.PooledByteBufAllocator;
 import io.netty.channel.ServerChannel;
 import io.netty.channel.epoll.Epoll;
@@ -46,7 +43,6 @@ public class NettyServerConfig extends NettyBaseConfig {
     private static final int RPC_REQUEST_TIMEOUT = 30 * 1000;
     private boolean enableServerPooledByteBufAllocator = true;
     private int serverChannelMaxIdleTimeSeconds = 30;
-    private static final Configuration CONFIG = ConfigurationFactory.getInstance();
     private static final String DEFAULT_BOSS_THREAD_PREFIX = "NettyBoss";
     private static final String EPOLL_WORKER_THREAD_PREFIX = "NettyServerEPollWorker";
     private static final String NIO_WORKER_THREAD_PREFIX = "NettyServerNIOWorker";
diff --git a/distribution/pom.xml b/distribution/pom.xml
index 98c8e6cce..3014e442c 100644
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -20,16 +20,12 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.3</version>
+        <version>0.1.4</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-distribution</artifactId>
     <packaging>pom</packaging>
     <name>fescar-distribution ${project.version}</name>
-    <properties>
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
-    </properties>
 
     <dependencies>
         <dependency>
diff --git a/dubbo/pom.xml b/dubbo/pom.xml
index cc76e5f3c..f67561532 100644
--- a/dubbo/pom.xml
+++ b/dubbo/pom.xml
@@ -20,16 +20,13 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.3</version>
+        <version>0.1.4</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-dubbo</artifactId>
     <packaging>jar</packaging>
     <name>fescar-dubbo ${project.version}</name>
-    <properties>
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
-    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/examples/pom.xml b/examples/pom.xml
deleted file mode 100644
index 800534703..000000000
--- a/examples/pom.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~  Copyright 1999-2018 Alibaba Group Holding Ltd.
-  ~
-  ~  Licensed under the Apache License, Version 2.0 (the "License");
-  ~  you may not use this file except in compliance with the License.
-  ~  You may obtain a copy of the License at
-  ~
-  ~       http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~  Unless required by applicable law or agreed to in writing, software
-  ~  distributed under the License is distributed on an "AS IS" BASIS,
-  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~  See the License for the specific language governing permissions and
-  ~  limitations under the License.
-  -->
-<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">
-    <parent>
-        <artifactId>fescar-all</artifactId>
-        <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.3</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>fescar-examples</artifactId>
-    <packaging>jar</packaging>
-    <name>fescar-examples ${project.version}</name>
-    <properties>
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
-    </properties>
-    <dependencies>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-tm</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-test</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-spring</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-dubbo</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.101tec</groupId>
-            <artifactId>zkclient</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>dubbo-registry-nacos</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.alibaba.spring</groupId>
-            <artifactId>spring-context-support</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-deploy-plugin</artifactId>
-                <version>2.8.2</version>
-                <configuration>
-                    <skip>true</skip>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-</project>
\ No newline at end of file
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/api/DemoCode.java b/examples/src/main/java/com/alibaba/fescar/tm/api/DemoCode.java
deleted file mode 100644
index 2ba40f9e8..000000000
--- a/examples/src/main/java/com/alibaba/fescar/tm/api/DemoCode.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- *  Copyright 1999-2018 Alibaba Group Holding Ltd.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package com.alibaba.fescar.tm.api;
-
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-import com.alibaba.fescar.common.exception.ShouldNeverHappenException;
-import com.alibaba.fescar.common.thread.NamedThreadFactory;
-import com.alibaba.fescar.core.exception.TransactionException;
-import com.alibaba.fescar.rm.RMClientAT;
-import com.alibaba.fescar.tm.TMClient;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Demo code for API usage.
- */
-public class DemoCode {
-
-    private void init() {
-        String applicationId = "my_app";
-        String transactionServiceGroup = "my_tx_group";
-        TMClient.init(applicationId, transactionServiceGroup);
-        RMClientAT.init(applicationId, transactionServiceGroup);
-
-    }
-
-    /**
-     * Demo code for High Level API (TransactionalTemplate) usage.
-     *
-     * @throws Throwable business exception
-     */
-    public void demoByHighLevelAPI() throws Throwable {
-        // 0. init
-        init();
-
-        // 0.1 prepare for the template instance
-        TransactionalTemplate transactionalTemplate = new TransactionalTemplate();
-
-        // 0.2 prepare for the failure handler (this is optional)
-        FailureHandler failureHandler = new MyFailureHandler();
-
-        try {
-            // run you business in template
-            transactionalTemplate.execute(new TransactionalExecutor() {
-                @Override
-                public Object execute() throws Throwable {
-                    // Do Your BusinessService
-                    businessCall1();
-                    businessCall2();
-                    businessCall3();
-                    return null;
-                }
-
-                @Override
-                public int timeout() {
-                    return 30000;
-                }
-
-                @Override
-                public String name() {
-                    return "my_tx_instance";
-                }
-            });
-        } catch (TransactionalExecutor.ExecutionException e) {
-            TransactionalExecutor.Code code = e.getCode();
-            switch (code) {
-                case RollbackDone:
-                    throw e.getOriginalException();
-                case BeginFailure:
-                    failureHandler.onBeginFailure(e.getTransaction(), e.getCause());
-                    throw e.getCause();
-                case CommitFailure:
-                    failureHandler.onCommitFailure(e.getTransaction(), e.getCause());
-                    throw e.getCause();
-                case RollbackFailure:
-                    failureHandler.onRollbackFailure(e.getTransaction(), e.getCause());
-                    throw e.getCause();
-                default:
-                    throw new ShouldNeverHappenException("Unknown TransactionalExecutor.Code: " + code);
-
-            }
-        }
-
-    }
-
-    private static class MyFailureHandler implements FailureHandler {
-
-        private static final Logger LOGGER = LoggerFactory.getLogger(MyFailureHandler.class);
-
-        @Override
-        public void onBeginFailure(GlobalTransaction tx, Throwable cause) {
-            LOGGER.warn("Failed to begin transaction. ", cause);
-
-        }
-
-        @Override
-        public void onCommitFailure(final GlobalTransaction tx, Throwable cause) {
-            LOGGER.warn("Failed to commit transaction[" + tx.getXid() + "]", cause);
-            final ScheduledExecutorService schedule = new ScheduledThreadPoolExecutor(1,
-                new NamedThreadFactory("BusinessRetryCommit", 1, true));
-            schedule.scheduleAtFixedRate(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        tx.commit();
-                        schedule.shutdownNow();
-
-                    } catch (TransactionException ignore) {
-
-                    }
-
-                }
-            }, 0, 5, TimeUnit.SECONDS);
-
-
-        }
-
-        @Override
-        public void onRollbackFailure(final GlobalTransaction tx, Throwable cause) {
-            LOGGER.warn("Failed to begin transaction[" + tx.getXid() + "]", cause);
-            final ScheduledExecutorService schedule = new ScheduledThreadPoolExecutor(1,
-                new NamedThreadFactory("BusinessRetryRollback", 1, true));
-            schedule.scheduleAtFixedRate(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        tx.rollback();
-                        schedule.shutdownNow();
-
-                    } catch (TransactionException ignore) {
-
-                    }
-
-                }
-            }, 0, 5, TimeUnit.SECONDS);
-
-        }
-
-    }
-
-    /**
-     * Demo code for Low Level API (GlobalTransaction) usage.
-     *
-     * @throws Throwable business exception
-     */
-    public void demoByLowLevelAPI() throws Throwable {
-        // 0. init
-        init();
-
-        // 1. get or create a transaction
-        GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
-
-        // 2. begin transaction
-        try {
-            tx.begin(30000, "my_tx_instance");
-
-        } catch (TransactionException txe) {
-            // TODO: Handle the transaction begin failure.
-
-        }
-
-        Object rs = null;
-        try {
-
-            // Do Your BusinessService
-            businessCall1();
-            businessCall2();
-            businessCall3();
-
-        } catch (Throwable ex) {
-
-            // 3. any business exception, rollback.
-            try {
-                tx.rollback();
-
-                // 3.1 throw the business exception out.
-                throw ex;
-
-            } catch (TransactionException txe) {
-                // TODO: Handle the transaction rollback failure.
-
-            }
-
-        }
-
-        // 4. everything is fine, commit.
-        try {
-            tx.commit();
-
-        } catch (TransactionException txe) {
-            // TODO: Handle the transaction rollback failure.
-
-        }
-    }
-
-    private static void businessCall1() {
-
-    }
-
-    private static void businessCall2() {
-
-    }
-
-    private static void businessCall3() {
-
-    }
-}
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/Order.java b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/Order.java
deleted file mode 100644
index c9b26c281..000000000
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/Order.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- *  Copyright 1999-2018 Alibaba Group Holding Ltd.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package com.alibaba.fescar.tm.dubbo;
-
-import java.io.Serializable;
-
-/**
- * The type Order.
- */
-public class Order implements Serializable {
-    /**
-     * The Id.
-     */
-    public long id;
-    /**
-     * The User id.
-     */
-    public String userId;
-    /**
-     * The Commodity code.
-     */
-    public String commodityCode;
-    /**
-     * The Count.
-     */
-    public int count;
-    /**
-     * The Money.
-     */
-    public int money;
-
-    @Override
-    public String toString() {
-        return "Order{" +
-            "id=" + id +
-            ", userId='" + userId + '\'' +
-            ", commodityCode='" + commodityCode + '\'' +
-            ", count=" + count +
-            ", money=" + money +
-            '}';
-    }
-}
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/OrderService.java b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/OrderService.java
deleted file mode 100644
index b133bfbf7..000000000
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/OrderService.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  Copyright 1999-2018 Alibaba Group Holding Ltd.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package com.alibaba.fescar.tm.dubbo;
-
-/**
- * The interface Order service.
- */
-public interface OrderService {
-    /**
-     * 创建订单
-     *
-     * @param userId        用户ID
-     * @param commodityCode 商品编号
-     * @param orderCount    订购数量
-     * @return 生成的订单 order
-     */
-    Order create(String userId, String commodityCode, int orderCount);
-}
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/AccountServiceImpl.java b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/AccountServiceImpl.java
deleted file mode 100644
index ce767a16d..000000000
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/AccountServiceImpl.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *  Copyright 1999-2018 Alibaba Group Holding Ltd.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package com.alibaba.fescar.tm.dubbo.impl;
-
-import com.alibaba.fescar.core.context.RootContext;
-import com.alibaba.fescar.test.common.ApplicationKeeper;
-import com.alibaba.fescar.tm.dubbo.AccountService;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-import org.springframework.jdbc.core.JdbcTemplate;
-
-/**
- * Please add the follow VM arguments:
- * <pre>
- *     -Djava.net.preferIPv4Stack=true
- * </pre>
- */
-public class AccountServiceImpl implements AccountService {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(AccountService.class);
-
-    private JdbcTemplate jdbcTemplate;
-
-    /**
-     * Sets jdbc template.
-     *
-     * @param jdbcTemplate the jdbc template
-     */
-    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
-        this.jdbcTemplate = jdbcTemplate;
-    }
-
-    @Override
-    public void debit(String userId, int money) {
-        LOGGER.info("Account Service ... xid: " + RootContext.getXID());
-        LOGGER.info("Deducting balance SQL: update account_tbl set money = money - {} where user_id = {}",money,userId);
-
-        jdbcTemplate.update("update account_tbl set money = money - ? where user_id = ?", new Object[] {money, userId});
-        LOGGER.info("Account Service End ... ");
-    }
-
-    /**
-     * The entry point of application.
-     *
-     * @param args the input arguments
-     */
-    public static void main(String[] args) {
-        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"dubbo-account-service.xml"});
-        context.getBean("service");
-        JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
-        jdbcTemplate.update("delete from account_tbl where user_id = 'U100001'");
-        jdbcTemplate.update("insert into account_tbl(user_id, money) values ('U100001', 999)");
-
-        new ApplicationKeeper(context).keep();
-    }
-}
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/BusinessServiceImpl.java b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/BusinessServiceImpl.java
deleted file mode 100644
index a65a05b2a..000000000
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/BusinessServiceImpl.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- *  Copyright 1999-2018 Alibaba Group Holding Ltd.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package com.alibaba.fescar.tm.dubbo.impl;
-
-import com.alibaba.fescar.core.context.RootContext;
-import com.alibaba.fescar.spring.annotation.GlobalTransactional;
-import com.alibaba.fescar.tm.dubbo.BusinessService;
-import com.alibaba.fescar.tm.dubbo.OrderService;
-import com.alibaba.fescar.tm.dubbo.StorageService;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-/**
- * Please add the follow VM arguments:
- * <pre>
- *     -Djava.net.preferIPv4Stack=true
- * </pre>
- */
-public class BusinessServiceImpl implements BusinessService {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(BusinessService.class);
-
-    private StorageService storageService;
-    private OrderService orderService;
-
-    @Override
-    @GlobalTransactional(timeoutMills = 300000, name = "dubbo-demo-tx")
-    public void purchase(String userId, String commodityCode, int orderCount) {
-        LOGGER.info("purchase begin ... xid: " + RootContext.getXID());
-        storageService.deduct(commodityCode, orderCount);
-        orderService.create(userId, commodityCode, orderCount);
-        throw new RuntimeException("xxx");
-
-    }
-
-    /**
-     * Sets storage service.
-     *
-     * @param storageService the storage service
-     */
-    public void setStorageService(StorageService storageService) {
-        this.storageService = storageService;
-    }
-
-    /**
-     * Sets order service.
-     *
-     * @param orderService the order service
-     */
-    public void setOrderService(OrderService orderService) {
-        this.orderService = orderService;
-    }
-
-    /**
-     * The entry point of application.
-     *
-     * @param args the input arguments
-     */
-    public static void main(String[] args) {
-        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
-            new String[] {"dubbo-business.xml"});
-        final BusinessService business = (BusinessService)context.getBean("business");
-        business.purchase("U100001", "C00321", 2);
-    }
-}
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/OrderServiceImpl.java b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/OrderServiceImpl.java
deleted file mode 100644
index 793a4561a..000000000
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/OrderServiceImpl.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- *  Copyright 1999-2018 Alibaba Group Holding Ltd.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package com.alibaba.fescar.tm.dubbo.impl;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-
-import com.alibaba.fescar.core.context.RootContext;
-import com.alibaba.fescar.test.common.ApplicationKeeper;
-import com.alibaba.fescar.tm.dubbo.AccountService;
-import com.alibaba.fescar.tm.dubbo.Order;
-import com.alibaba.fescar.tm.dubbo.OrderService;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.PreparedStatementCreator;
-import org.springframework.jdbc.support.GeneratedKeyHolder;
-import org.springframework.jdbc.support.KeyHolder;
-
-/**
- * Please add the follow VM arguments:
- * <pre>
- *     -Djava.net.preferIPv4Stack=true
- * </pre>
- */
-public class OrderServiceImpl implements OrderService {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(OrderService.class);
-
-    private AccountService accountService;
-
-    private JdbcTemplate jdbcTemplate;
-
-    @Override
-    public Order create(String userId, String commodityCode, int orderCount) {
-        LOGGER.info("Order Service Begin ... xid: " + RootContext.getXID());
-
-        // 计算订单金额
-        int orderMoney = calculate(commodityCode, orderCount);
-
-        // 从账户余额扣款
-        accountService.debit(userId, orderMoney);
-
-        final Order order = new Order();
-        order.userId = userId;
-        order.commodityCode = commodityCode;
-        order.count = orderCount;
-        order.money = orderMoney;
-
-        KeyHolder keyHolder = new GeneratedKeyHolder();
-
-        LOGGER.info("Order Service SQL: insert into order_tbl (user_id, commodity_code, count, money) values ({}, {}, {}, {})" ,userId ,commodityCode ,orderCount ,orderMoney );
-
-        jdbcTemplate.update(new PreparedStatementCreator() {
-
-            @Override
-            public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
-                PreparedStatement pst = con.prepareStatement(
-                        "insert into order_tbl (user_id, commodity_code, count, money) values (?, ?, ?, ?)",
-                        PreparedStatement.RETURN_GENERATED_KEYS);
-                pst.setObject(1, order.userId);
-                pst.setObject(2, order.commodityCode);
-                pst.setObject(3, order.count);
-                pst.setObject(4, order.money);
-                return pst;
-            }
-        }, keyHolder);
-
-        order.id = keyHolder.getKey().longValue();
-
-        LOGGER.info("Order Service End ... Created " + order);
-
-        return order;
-    }
-
-    /**
-     * Sets account service.
-     *
-     * @param accountService the account service
-     */
-    public void setAccountService(AccountService accountService) {
-        this.accountService = accountService;
-    }
-
-    /**
-     * Sets jdbc template.
-     *
-     * @param jdbcTemplate the jdbc template
-     */
-    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
-        this.jdbcTemplate = jdbcTemplate;
-    }
-
-    private int calculate(String commodityId, int orderCount) {
-        return 200 * orderCount;
-    }
-
-    /**
-     * The entry point of application.
-     *
-     * @param args the input arguments
-     */
-    public static void main(String[] args) {
-
-        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"dubbo-order-service.xml"});
-        context.getBean("service");
-        new ApplicationKeeper(context).keep();
-    }
-}
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/StorageServiceImpl.java b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/StorageServiceImpl.java
deleted file mode 100644
index 768d0bca1..000000000
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/StorageServiceImpl.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *  Copyright 1999-2018 Alibaba Group Holding Ltd.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package com.alibaba.fescar.tm.dubbo.impl;
-
-import com.alibaba.fescar.core.context.RootContext;
-import com.alibaba.fescar.test.common.ApplicationKeeper;
-import com.alibaba.fescar.tm.dubbo.StorageService;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-import org.springframework.jdbc.core.JdbcTemplate;
-
-/**
- * Please add the follow VM arguments:
- * <pre>
- *     -Djava.net.preferIPv4Stack=true
- * </pre>
- */
-public class StorageServiceImpl implements StorageService {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(StorageService.class);
-
-    private JdbcTemplate jdbcTemplate;
-
-    /**
-     * Sets jdbc template.
-     *
-     * @param jdbcTemplate the jdbc template
-     */
-    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
-        this.jdbcTemplate = jdbcTemplate;
-    }
-
-    @Override
-    public void deduct(String commodityCode, int count) {
-        LOGGER.info("Storage Service Begin ... xid: " + RootContext.getXID());
-        LOGGER.info("Deducting inventory SQL: update storage_tbl set count = count - {} where commodity_code = {}",
-            count, commodityCode);
-
-        jdbcTemplate.update("update storage_tbl set count = count - ? where commodity_code = ?",
-            new Object[] {count, commodityCode});
-        LOGGER.info("Storage Service End ... ");
-
-    }
-
-    /**
-     * The entry point of application.
-     *
-     * @param args the input arguments
-     */
-    public static void main(String[] args) {
-        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
-            new String[] {"dubbo-storage-service.xml"});
-        context.getBean("service");
-        JdbcTemplate jdbcTemplate = (JdbcTemplate)context.getBean("jdbcTemplate");
-        jdbcTemplate.update("delete from storage_tbl where commodity_code = 'C00321'");
-        jdbcTemplate.update("insert into storage_tbl(commodity_code, count) values ('C00321', 100)");
-        new ApplicationKeeper(context).keep();
-    }
-}
diff --git a/examples/src/main/resources/application.conf b/examples/src/main/resources/application.conf
deleted file mode 100644
index 003576576..000000000
--- a/examples/src/main/resources/application.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-transport {
-  # tcp udt unix-domain-socket
-  type = "TCP"
-  #NIO NATIVE
-  server = "NIO"
-  #enable heartbeat
-  heartbeat = true
-  #thread factory for netty
-  thread-factory {
-    boss-thread-prefix = "NettyBoss"
-    worker-thread-prefix = "NettyServerNIOWorker"
-    server-executor-thread-prefix = "NettyServerBizHandler"
-    share-boss-worker = false
-    client-selector-thread-prefix = "NettyClientSelector"
-    client-selector-thread-size = 1
-    client-worker-thread-prefix = "NettyClientWorkerThread"
-    # netty boss thread size,will not be used for UDT
-    boss-thread-size = 1
-    #auto default pin or 8
-    worker-thread-size = 8
-  }
-}
-service {
-  #vgroup->rgroup
-  vgroup_mapping.my_test_tx_group = "localRgroup"
-  #only support single node
-  localRgroup.grouplist = "127.0.0.1:8091"
-  #degrade current not support
-  enableDegrade = false
-  #disable
-  disable = false
-}
diff --git a/examples/src/main/resources/dubbo-account-service.xml b/examples/src/main/resources/dubbo-account-service.xml
deleted file mode 100755
index e710b2cf6..000000000
--- a/examples/src/main/resources/dubbo-account-service.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~  Copyright 1999-2018 Alibaba Group Holding Ltd.
-  ~
-  ~  Licensed under the Apache License, Version 2.0 (the "License");
-  ~  you may not use this file except in compliance with the License.
-  ~  You may obtain a copy of the License at
-  ~
-  ~       http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~  Unless required by applicable law or agreed to in writing, software
-  ~  distributed under the License is distributed on an "AS IS" BASIS,
-  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~  See the License for the specific language governing permissions and
-  ~  limitations under the License.
-  -->
-
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
-
-    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
-        <property name="locations" value="classpath:jdbc.properties"/>
-    </bean>
-
-    <bean name="accountDataSource" class="com.alibaba.druid.pool.DruidDataSource"
-          init-method="init" destroy-method="close">
-        <property name="url" value="${jdbc.account.url}"/>
-        <property name="username" value="${jdbc.account.username}"/>
-        <property name="password" value="${jdbc.account.password}"/>
-        <property name="driverClassName" value="${jdbc.account.driver}"/>
-        <property name="initialSize" value="0" />
-        <property name="maxActive" value="180" />
-        <property name="minIdle" value="0" />
-        <property name="maxWait" value="60000" />
-        <property name="validationQuery" value="Select 'x' from DUAL" />
-        <property name="testOnBorrow" value="false" />
-        <property name="testOnReturn" value="false" />
-        <property name="testWhileIdle" value="true" />
-        <property name="timeBetweenEvictionRunsMillis" value="60000" />
-        <property name="minEvictableIdleTimeMillis" value="25200000" />
-        <property name="removeAbandoned" value="true" />
-        <property name="removeAbandonedTimeout" value="1800" />
-        <property name="logAbandoned" value="true" />
-        <property name="filters" value="mergeStat" />
-    </bean>
-
-    <bean id="accountDataSourceProxy" class="com.alibaba.fescar.rm.datasource.DataSourceProxy">
-        <constructor-arg ref="accountDataSource" />
-    </bean>
-
-    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
-        <property name="dataSource" ref="accountDataSourceProxy" />
-    </bean>
-
-    <dubbo:application name="dubbo-demo-account-service"  />
-    <dubbo:registry address="multicast://224.5.6.7:1234?unicast=false" />
-    <!--support zk-->
-    <!--dubbo:registry address="zookeeper://test.zk1.cc:1234?backup=test.zk2.cc:1234,test.zk3.cc:1234" /-->
-    <!--support nacos-->
-    <!-- <dubbo:registry address="nacos://127.0.0.1:8848"/> -->
-    <dubbo:protocol name="dubbo" port="20881" />
-    <dubbo:service interface="com.alibaba.fescar.tm.dubbo.AccountService" ref="service" timeout="10000"/>
-
-    <bean id="service" class="com.alibaba.fescar.tm.dubbo.impl.AccountServiceImpl">
-        <property name="jdbcTemplate" ref="jdbcTemplate"/>
-    </bean>
-
-    <bean class="com.alibaba.fescar.spring.annotation.GlobalTransactionScanner">
-        <constructor-arg value="dubbo-demo-account-service"/>
-        <constructor-arg value="my_test_tx_group"/>
-    </bean>
-</beans>
-            
diff --git a/examples/src/main/resources/dubbo-business.xml b/examples/src/main/resources/dubbo-business.xml
deleted file mode 100755
index 98adb012e..000000000
--- a/examples/src/main/resources/dubbo-business.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~  Copyright 1999-2018 Alibaba Group Holding Ltd.
-  ~
-  ~  Licensed under the Apache License, Version 2.0 (the "License");
-  ~  you may not use this file except in compliance with the License.
-  ~  You may obtain a copy of the License at
-  ~
-  ~       http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~  Unless required by applicable law or agreed to in writing, software
-  ~  distributed under the License is distributed on an "AS IS" BASIS,
-  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~  See the License for the specific language governing permissions and
-  ~  limitations under the License.
-  -->
-
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
-                        http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
-
-    <dubbo:application name="dubbo-demo-app"  />
-    <dubbo:registry address="multicast://224.5.6.7:1234?unicast=false" />
-
-    <dubbo:reference id="orderService" check="false" interface="com.alibaba.fescar.tm.dubbo.OrderService"/>
-    <dubbo:reference id="storageService" check="false" interface="com.alibaba.fescar.tm.dubbo.StorageService"/>
-
-    <bean id="business" class="com.alibaba.fescar.tm.dubbo.impl.BusinessServiceImpl">
-        <property name="orderService" ref="orderService"/>
-        <property name="storageService" ref="storageService"/>
-    </bean>
-
-    <bean class="com.alibaba.fescar.spring.annotation.GlobalTransactionScanner">
-        <constructor-arg value="dubbo-demo-app"/>
-        <constructor-arg value="my_test_tx_group"/>
-    </bean>
-
-</beans>
\ No newline at end of file
diff --git a/examples/src/main/resources/dubbo-order-service.xml b/examples/src/main/resources/dubbo-order-service.xml
deleted file mode 100755
index c2821e72c..000000000
--- a/examples/src/main/resources/dubbo-order-service.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~  Copyright 1999-2018 Alibaba Group Holding Ltd.
-  ~
-  ~  Licensed under the Apache License, Version 2.0 (the "License");
-  ~  you may not use this file except in compliance with the License.
-  ~  You may obtain a copy of the License at
-  ~
-  ~       http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~  Unless required by applicable law or agreed to in writing, software
-  ~  distributed under the License is distributed on an "AS IS" BASIS,
-  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~  See the License for the specific language governing permissions and
-  ~  limitations under the License.
-  -->
-
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
-
-    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
-        <property name="locations" value="classpath:jdbc.properties"/>
-    </bean>
-
-    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
-        <property name="locations" value="classpath:jdbc.properties"/>
-    </bean>
-
-    <bean name="orderDataSource" class="com.alibaba.druid.pool.DruidDataSource"
-          init-method="init" destroy-method="close">
-        <property name="url" value="${jdbc.order.url}"/>
-        <property name="username" value="${jdbc.order.username}"/>
-        <property name="password" value="${jdbc.order.password}"/>
-        <property name="driverClassName" value="${jdbc.order.driver}"/>
-        <property name="initialSize" value="0"/>
-        <property name="maxActive" value="180"/>
-        <property name="minIdle" value="0"/>
-        <property name="maxWait" value="60000"/>
-        <property name="validationQuery" value="Select 'x' from DUAL"/>
-        <property name="testOnBorrow" value="false"/>
-        <property name="testOnReturn" value="false"/>
-        <property name="testWhileIdle" value="true"/>
-        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
-        <property name="minEvictableIdleTimeMillis" value="25200000"/>
-        <property name="removeAbandoned" value="true"/>
-        <property name="removeAbandonedTimeout" value="1800"/>
-        <property name="logAbandoned" value="true"/>
-        <property name="filters" value="mergeStat"/>
-    </bean>
-
-    <bean id="orderDataSourceProxy" class="com.alibaba.fescar.rm.datasource.DataSourceProxy">
-        <constructor-arg ref="orderDataSource"/>
-    </bean>
-
-    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
-        <property name="dataSource" ref="orderDataSourceProxy"/>
-    </bean>
-
-    <dubbo:application name="dubbo-demo-order-service"/>
-    <dubbo:registry address="multicast://224.5.6.7:1234?unicast=false"/>
-    <!--support zk-->
-    <!--dubbo:registry address="zookeeper://test.zk1.cc:1234?backup=test.zk2.cc:1234,test.zk3.cc:1234" /-->
-    <!--support nacos-->
-    <!-- <dubbo:registry address="nacos://127.0.0.1:8848"/> -->
-    <dubbo:protocol name="dubbo" port="20883"/>
-    <dubbo:service interface="com.alibaba.fescar.tm.dubbo.OrderService" ref="service" timeout="10000"/>
-
-    <dubbo:reference id="accountService" check="false" interface="com.alibaba.fescar.tm.dubbo.AccountService"/>
-
-    <bean id="service" class="com.alibaba.fescar.tm.dubbo.impl.OrderServiceImpl">
-        <property name="jdbcTemplate" ref="jdbcTemplate"/>
-        <property name="accountService" ref="accountService"/>
-    </bean>
-
-    <bean class="com.alibaba.fescar.spring.annotation.GlobalTransactionScanner">
-        <constructor-arg value="dubbo-demo-order-service"/>
-        <constructor-arg value="my_test_tx_group"/>
-    </bean>
-</beans>
-            
diff --git a/examples/src/main/resources/dubbo-storage-service.xml b/examples/src/main/resources/dubbo-storage-service.xml
deleted file mode 100755
index 90745bc04..000000000
--- a/examples/src/main/resources/dubbo-storage-service.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~  Copyright 1999-2018 Alibaba Group Holding Ltd.
-  ~
-  ~  Licensed under the Apache License, Version 2.0 (the "License");
-  ~  you may not use this file except in compliance with the License.
-  ~  You may obtain a copy of the License at
-  ~
-  ~       http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~  Unless required by applicable law or agreed to in writing, software
-  ~  distributed under the License is distributed on an "AS IS" BASIS,
-  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~  See the License for the specific language governing permissions and
-  ~  limitations under the License.
-  -->
-
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
-
-    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
-        <property name="locations" value="classpath:jdbc.properties"/>
-    </bean>
-
-    <bean name="storageDataSource" class="com.alibaba.druid.pool.DruidDataSource"
-          init-method="init" destroy-method="close">
-        <property name="url" value="${jdbc.storage.url}"/>
-        <property name="username" value="${jdbc.storage.username}"/>
-        <property name="password" value="${jdbc.storage.password}"/>
-        <property name="driverClassName" value="${jdbc.storage.driver}"/>
-        <property name="initialSize" value="0" />
-        <property name="maxActive" value="180" />
-        <property name="minIdle" value="0" />
-        <property name="maxWait" value="60000" />
-        <property name="validationQuery" value="Select 'x' from DUAL" />
-        <property name="testOnBorrow" value="false" />
-        <property name="testOnReturn" value="false" />
-        <property name="testWhileIdle" value="true" />
-        <property name="timeBetweenEvictionRunsMillis" value="60000" />
-        <property name="minEvictableIdleTimeMillis" value="25200000" />
-        <property name="removeAbandoned" value="true" />
-        <property name="removeAbandonedTimeout" value="1800" />
-        <property name="logAbandoned" value="true" />
-        <property name="filters" value="mergeStat" />
-    </bean>
-
-    <bean id="storageDataSourceProxy" class="com.alibaba.fescar.rm.datasource.DataSourceProxy">
-        <constructor-arg ref="storageDataSource" />
-    </bean>
-
-    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
-        <property name="dataSource" ref="storageDataSourceProxy" />
-    </bean>
-
-    <dubbo:application name="dubbo-demo-storage-service"  />
-    <dubbo:registry address="multicast://224.5.6.7:1234?unicast=false" />
-    <!--support zk-->
-    <!--dubbo:registry address="zookeeper://test.zk1.cc:1234?backup=test.zk2.cc:1234,test.zk3.cc:1234" /-->
-    <!--support nacos-->
-    <!--<dubbo:registry address="nacos://127.0.0.1:8848"/>-->
-    <dubbo:protocol name="dubbo" port="20882" />
-    <dubbo:service interface="com.alibaba.fescar.tm.dubbo.StorageService" ref="service" timeout="10000"/>
-
-    <bean id="service" class="com.alibaba.fescar.tm.dubbo.impl.StorageServiceImpl">
-        <property name="jdbcTemplate" ref="jdbcTemplate"/>
-    </bean>
-
-    <bean class="com.alibaba.fescar.spring.annotation.GlobalTransactionScanner">
-        <constructor-arg value="dubbo-demo-storage-service"/>
-        <constructor-arg value="my_test_tx_group"/>
-    </bean>
-</beans>
-            
diff --git a/examples/src/main/resources/jdbc.properties b/examples/src/main/resources/jdbc.properties
deleted file mode 100644
index e0f9533c4..000000000
--- a/examples/src/main/resources/jdbc.properties
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-#  Copyright 1999-2018 Alibaba Group Holding Ltd.
-#
-#  Licensed under the Apache License, Version 2.0 (the "License");
-#  you may not use this file except in compliance with the License.
-#  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing, software
-#  distributed under the License is distributed on an "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#  See the License for the specific language governing permissions and
-#  limitations under the License.
-#
-jdbc.account.url=jdbc:mysql://localhost:3306/fescar_demo
-jdbc.account.username=root
-jdbc.account.password=111111
-jdbc.account.driver=com.mysql.jdbc.Driver
-# storage db config
-jdbc.storage.url=jdbc:mysql://localhost:3306/fescar_demo
-jdbc.storage.username=root
-jdbc.storage.password=111111
-jdbc.storage.driver=com.mysql.jdbc.Driver
-# order db config
-jdbc.order.url=jdbc:mysql://localhost:3306/fescar_demo
-jdbc.order.username=root
-jdbc.order.password=111111
-jdbc.order.driver=com.mysql.jdbc.Driver
\ No newline at end of file
diff --git a/examples/src/main/resources/sql/dubbo_biz.sql b/examples/src/main/resources/sql/dubbo_biz.sql
deleted file mode 100644
index 98a760143..000000000
--- a/examples/src/main/resources/sql/dubbo_biz.sql
+++ /dev/null
@@ -1,28 +0,0 @@
-DROP TABLE IF EXISTS `storage_tbl`;
-CREATE TABLE `storage_tbl` (
-  `id` int(11) NOT NULL AUTO_INCREMENT,
-  `commodity_code` varchar(255) DEFAULT NULL,
-  `count` int(11) DEFAULT 0,
-  PRIMARY KEY (`id`),
-  UNIQUE KEY (`commodity_code`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
-DROP TABLE IF EXISTS `order_tbl`;
-CREATE TABLE `order_tbl` (
-  `id` int(11) NOT NULL AUTO_INCREMENT,
-  `user_id` varchar(255) DEFAULT NULL,
-  `commodity_code` varchar(255) DEFAULT NULL,
-  `count` int(11) DEFAULT 0,
-  `money` int(11) DEFAULT 0,
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
-DROP TABLE IF EXISTS `account_tbl`;
-CREATE TABLE `account_tbl` (
-  `id` int(11) NOT NULL AUTO_INCREMENT,
-  `user_id` varchar(255) DEFAULT NULL,
-  `money` int(11) DEFAULT 0,
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
\ No newline at end of file
diff --git a/examples/src/main/resources/sql/undo_log.sql b/examples/src/main/resources/sql/undo_log.sql
deleted file mode 100644
index bede844bf..000000000
--- a/examples/src/main/resources/sql/undo_log.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-CREATE TABLE `undo_log` (
-  `id` bigint(20) NOT NULL AUTO_INCREMENT,
-  `branch_id` bigint(20) NOT NULL,
-  `xid` varchar(100) NOT NULL,
-  `rollback_info` longblob NOT NULL,
-  `log_status` int(11) NOT NULL,
-  `log_created` datetime NOT NULL,
-  `log_modified` datetime NOT NULL,
-  `ext` varchar(100) DEFAULT NULL,
-  PRIMARY KEY (`id`),
-  KEY `idx_unionkey` (`xid`,`branch_id`)
-) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index a975a64a0..c7372994d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
 
     <groupId>com.alibaba.fescar</groupId>
     <artifactId>fescar-all</artifactId>
-    <version>0.1.3</version>
+    <version>0.1.4</version>
     <modules>
         <module>config</module>
         <module>common</module>
@@ -33,7 +33,6 @@
         <module>spring</module>
         <module>dubbo</module>
         <module>test</module>
-        <module>examples</module>
     </modules>
     <packaging>pom</packaging>
 
@@ -82,8 +81,8 @@
         <maven.test.skip>false</maven.test.skip>
         <maven.javadoc.skip>true</maven.javadoc.skip>
         <!-- Compiler settings properties -->
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
         <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
         <netty4.version>4.1.24.Final</netty4.version>
         <org.springframework.spring.version>2.5.6.SEC03</org.springframework.spring.version>
@@ -102,6 +101,7 @@
         <dubbo.registry.nacos>0.0.1</dubbo.registry.nacos>
         <spring-context-support.version>1.0.2</spring-context-support.version>
         <testng.version>6.4</testng.version>
+        <jacoco-maven-plugin.version>0.8.3</jacoco-maven-plugin.version>
     </properties>
     <dependencyManagement>
         <dependencies>
@@ -115,11 +115,6 @@
                 <artifactId>fescar-config</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>${project.groupId}</groupId>
-                <artifactId>fescar-client</artifactId>
-                <version>${project.version}</version>
-            </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>fescar-server</artifactId>
@@ -155,11 +150,6 @@
                 <artifactId>fescar-test</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>${project.groupId}</groupId>
-                <artifactId>fescar-examples</artifactId>
-                <version>${project.version}</version>
-            </dependency>
             <dependency>
                 <groupId>io.netty</groupId>
                 <artifactId>netty-all</artifactId>
@@ -334,16 +324,23 @@
                 </configuration>
             </plugin>
             <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>cobertura-maven-plugin</artifactId>
-                <version>2.7</version>
-                <configuration>
-                    <formats>
-                        <format>html</format>
-                        <format>xml</format>
-                    </formats>
-                    <check/>
-                </configuration>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <version>${jacoco-maven-plugin.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>report</id>
+                        <phase>test</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                    </execution>
+                </executions>
             </plugin>
         </plugins>
     </build>
diff --git a/rm-datasource/pom.xml b/rm-datasource/pom.xml
index 196a8f1fb..b09971c28 100644
--- a/rm-datasource/pom.xml
+++ b/rm-datasource/pom.xml
@@ -21,16 +21,13 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.3</version>
+        <version>0.1.4</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-rm-datasource</artifactId>
     <packaging>jar</packaging>
     <name>fescar-rm-datasource ${project.version}</name>
-    <properties>
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
-    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/ConnectionProxy.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/ConnectionProxy.java
index 66f5e62e5..a082e3018 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/ConnectionProxy.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/ConnectionProxy.java
@@ -74,12 +74,11 @@ public class ConnectionProxy extends AbstractConnectionProxy {
     /**
      * Check lock.
      *
-     * @param records the records
+     * @param lockKeys the lockKeys
      * @throws SQLException the sql exception
      */
-    public void checkLock(TableRecords records) throws SQLException {
+    public void checkLock(String lockKeys) throws SQLException {
         // Just check lock without requiring lock by now.
-        String lockKeys = buildLockKey(records);
         try {
             boolean lockable = DataSourceManager.get().lockQuery(BranchType.AT, getDataSourceProxy().getResourceId(), context.getXid(), lockKeys);
             if (!lockable) {
@@ -93,12 +92,11 @@ public class ConnectionProxy extends AbstractConnectionProxy {
     /**
      * Register.
      *
-     * @param records the records
+     * @param lockKeys the lockKeys
      * @throws SQLException the sql exception
      */
-    public void register(TableRecords records) throws SQLException {
+    public void register(String lockKeys) throws SQLException {
         // Just check lock without requiring lock by now.
-        String lockKeys = buildLockKey(records);
         try {
             DataSourceManager.get().branchRegister(BranchType.AT, getDataSourceProxy().getResourceId(), null, context.getXid(), lockKeys);
         } catch (TransactionException e) {
@@ -116,56 +114,21 @@ public class ConnectionProxy extends AbstractConnectionProxy {
     }
 
     /**
-     * Prepare undo log.
+     * append sqlUndoLog
      *
-     * @param sqlType     the sql type
-     * @param tableName   the table name
-     * @param beforeImage the before image
-     * @param afterImage  the after image
-     * @throws SQLException the sql exception
+     * @param sqlUndoLog
      */
-    public void prepareUndoLog(SQLType sqlType, String tableName, TableRecords beforeImage, TableRecords afterImage) throws SQLException {
-        if(beforeImage.getRows().size() == 0 && afterImage.getRows().size() == 0) {
-            return;
-        }
-
-        TableRecords lockKeyRecords = afterImage;
-        if (sqlType == SQLType.DELETE) {
-            lockKeyRecords = beforeImage;
-        }
-        String lockKeys = buildLockKey(lockKeyRecords);
-        context.appendLockKey(lockKeys);
-        SQLUndoLog sqlUndoLog = buildUndoItem(sqlType, tableName, beforeImage, afterImage);
+    public void appendUndoLog(SQLUndoLog sqlUndoLog) {
         context.appendUndoItem(sqlUndoLog);
     }
 
-    private SQLUndoLog buildUndoItem(SQLType sqlType, String tableName, TableRecords beforeImage, TableRecords afterImage) {
-        SQLUndoLog sqlUndoLog = new SQLUndoLog();
-        sqlUndoLog.setSqlType(sqlType);
-        sqlUndoLog.setTableName(tableName);
-        sqlUndoLog.setBeforeImage(beforeImage);
-        sqlUndoLog.setAfterImage(afterImage);
-        return sqlUndoLog;
-    }
-
-    private String buildLockKey(TableRecords rowsIncludingPK) {
-        if (rowsIncludingPK.size() == 0) {
-            return null;
-        }
-        StringBuilder sb = new StringBuilder();
-        sb.append(rowsIncludingPK.getTableMeta().getTableName());
-        sb.append(":");
-
-        boolean flag = false;
-        for (Field field : rowsIncludingPK.pkRows()) {
-            if (flag) {
-                sb.append(",");
-            } else {
-                flag = true;
-            }
-            sb.append(field.getValue());
-        }
-        return sb.toString();
+    /**
+     * append lockKey
+     *
+     * @param lockKey
+     */
+    public void appendLockKey(String lockKey) {
+        context.appendLockKey(lockKey);
     }
 
     @Override
@@ -200,7 +163,7 @@ public class ConnectionProxy extends AbstractConnectionProxy {
 
     private void register() throws TransactionException {
         Long branchId = DataSourceManager.get().branchRegister(BranchType.AT, getDataSourceProxy().getResourceId(),
-            null, context.getXid(), context.buildLockKeys());
+                null, context.getXid(), context.buildLockKeys());
         context.setBranchId(branchId);
     }
 
@@ -210,7 +173,8 @@ public class ConnectionProxy extends AbstractConnectionProxy {
         if (context.inGlobalTransaction()) {
             if (context.isBranchRegistered()) {
                 report(false);
-            }}
+            }
+        }
         context.reset();
     }
 
@@ -228,7 +192,7 @@ public class ConnectionProxy extends AbstractConnectionProxy {
         while (retry > 0) {
             try {
                 DataSourceManager.get().branchReport(context.getXid(), context.getBranchId(),
-                    (commitDone ? BranchStatus.PhaseOne_Done : BranchStatus.PhaseOne_Failed), null);
+                        (commitDone ? BranchStatus.PhaseOne_Done : BranchStatus.PhaseOne_Failed), null);
                 return;
             } catch (Throwable ex) {
                 LOGGER.error("Failed to report [" + context.getBranchId() + "/" + context.getXid() + "] commit done [" + commitDone + "] Retry Countdown: " + retry);
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/AbstractDMLBaseExecutor.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/AbstractDMLBaseExecutor.java
index 48d6bf80e..add9a2b46 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/AbstractDMLBaseExecutor.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/AbstractDMLBaseExecutor.java
@@ -69,7 +69,7 @@ public abstract class AbstractDMLBaseExecutor<T, S extends Statement> extends Ba
         TableRecords beforeImage = beforeImage();
         T result = statementCallback.execute(statementProxy.getTargetStatement(), args);
         TableRecords afterImage = afterImage(beforeImage);
-        statementProxy.getConnectionProxy().prepareUndoLog(sqlRecognizer.getSQLType(), sqlRecognizer.getTableName(), beforeImage, afterImage);
+        prepareUndoLog(beforeImage, afterImage);
         return result;
     }
 
@@ -92,6 +92,7 @@ public abstract class AbstractDMLBaseExecutor<T, S extends Statement> extends Ba
                     connectionProxy.commit();
                     break;
                 } catch (LockConflictException lockConflict) {
+                    connectionProxy.getTargetConnection().rollback();
                     lockRetryController.sleep(lockConflict);
                 }
             }
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/BaseTransactionalExecutor.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/BaseTransactionalExecutor.java
index 2bd342b3f..84507970b 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/BaseTransactionalExecutor.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/BaseTransactionalExecutor.java
@@ -21,11 +21,18 @@ import java.sql.Statement;
 import java.util.List;
 
 import com.alibaba.fescar.core.context.RootContext;
+import com.alibaba.fescar.core.exception.TransactionException;
+import com.alibaba.fescar.core.model.BranchType;
+import com.alibaba.fescar.rm.datasource.ConnectionProxy;
+import com.alibaba.fescar.rm.datasource.DataSourceManager;
 import com.alibaba.fescar.rm.datasource.StatementProxy;
 import com.alibaba.fescar.rm.datasource.sql.SQLRecognizer;
+import com.alibaba.fescar.rm.datasource.sql.SQLType;
 import com.alibaba.fescar.rm.datasource.sql.struct.Field;
 import com.alibaba.fescar.rm.datasource.sql.struct.TableMeta;
 import com.alibaba.fescar.rm.datasource.sql.struct.TableMetaCache;
+import com.alibaba.fescar.rm.datasource.sql.struct.TableRecords;
+import com.alibaba.fescar.rm.datasource.undo.SQLUndoLog;
 
 /**
  * The type Base transactional executor.
@@ -153,4 +160,71 @@ public abstract class BaseTransactionalExecutor<T, S extends Statement> implemen
         return tableMeta;
     }
 
+    /**
+     * prepare undo log.
+     *
+     * @param beforeImage the before image
+     * @param afterImage  the after image
+     * @throws SQLException the sql exception
+     */
+    protected void prepareUndoLog(TableRecords beforeImage, TableRecords afterImage) throws SQLException {
+        if (beforeImage.getRows().size() == 0 && afterImage.getRows().size() == 0) {
+            return;
+        }
+
+        ConnectionProxy connectionProxy = statementProxy.getConnectionProxy();
+
+        TableRecords lockKeyRecords = sqlRecognizer.getSQLType() == SQLType.DELETE ? beforeImage : afterImage;
+        String lockKeys = buildLockKey(lockKeyRecords);
+        connectionProxy.appendLockKey(lockKeys);
+
+        SQLUndoLog sqlUndoLog = buildUndoItem(beforeImage, afterImage);
+        connectionProxy.appendUndoLog(sqlUndoLog);
+    }
+
+
+    /**
+     * build lockKey
+     *
+     * @param rowsIncludingPK the records
+     */
+    protected String buildLockKey(TableRecords rowsIncludingPK) {
+        if (rowsIncludingPK.size() == 0) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        sb.append(rowsIncludingPK.getTableMeta().getTableName());
+        sb.append(":");
+
+        boolean flag = false;
+        for (Field field : rowsIncludingPK.pkRows()) {
+            if (flag) {
+                sb.append(",");
+            } else {
+                flag = true;
+            }
+            sb.append(field.getValue());
+        }
+        return sb.toString();
+    }
+
+    /**
+     * build a SQLUndoLog
+     *
+     * @param beforeImage
+     * @param afterImage
+     * @return
+     */
+    protected SQLUndoLog buildUndoItem(TableRecords beforeImage, TableRecords afterImage) {
+        SQLType sqlType = sqlRecognizer.getSQLType();
+        String tableName = sqlRecognizer.getTableName();
+
+        SQLUndoLog sqlUndoLog = new SQLUndoLog();
+        sqlUndoLog.setSqlType(sqlType);
+        sqlUndoLog.setTableName(tableName);
+        sqlUndoLog.setBeforeImage(beforeImage);
+        sqlUndoLog.setAfterImage(afterImage);
+        return sqlUndoLog;
+    }
+
 }
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/SelectForUpdateExecutor.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/SelectForUpdateExecutor.java
index 68781315c..c708f9272 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/SelectForUpdateExecutor.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/SelectForUpdateExecutor.java
@@ -99,7 +99,8 @@ public class SelectForUpdateExecutor<S extends Statement> extends BaseTransactio
                     }
 
                     TableRecords selectPKRows = TableRecords.buildRecords(getTableMeta(), rsPK);
-                    statementProxy.getConnectionProxy().checkLock(selectPKRows);
+                    String lockKeys = buildLockKey(selectPKRows);
+                    statementProxy.getConnectionProxy().checkLock(lockKeys);
                     break;
 
                 } catch (LockConflictException lce) {
diff --git a/server/pom.xml b/server/pom.xml
index f4aecc121..aef847cdd 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -20,16 +20,13 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.3</version>
+        <version>0.1.4</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-server</artifactId>
     <packaging>jar</packaging>
     <name>fescar-server ${project.version}</name>
-    <properties>
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
-    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
@@ -80,7 +77,6 @@
                                 <extraArguments>
                                     <extraArgument>-server</extraArgument>
                                     <extraArgument>-XX:MaxDirectMemorySize=1024M</extraArgument>
-                                    <extraArgument>$EXTRA_JVM_ARGUMENTS</extraArgument>
                                 </extraArguments>
                             </jvmSettings>
                         </program>
diff --git a/server/src/main/java/com/alibaba/fescar/server/Server.java b/server/src/main/java/com/alibaba/fescar/server/Server.java
index 2316d1287..d79cd5fd0 100644
--- a/server/src/main/java/com/alibaba/fescar/server/Server.java
+++ b/server/src/main/java/com/alibaba/fescar/server/Server.java
@@ -71,7 +71,11 @@ public class Server {
 
         UUIDGenerator.init(1);
 
-        XID.setIpAddress(NetUtil.getLocalIp());
+        if (args.length > 2) {
+            XID.setIpAddress(args[2]);
+        } else {
+            XID.setIpAddress(NetUtil.getLocalIp());
+        }
         XID.setPort(rpcServer.getListenPort());
 
         rpcServer.init();
diff --git a/spring/pom.xml b/spring/pom.xml
index 841e40ada..565cc8b57 100644
--- a/spring/pom.xml
+++ b/spring/pom.xml
@@ -20,16 +20,13 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.3</version>
+        <version>0.1.4</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-spring</artifactId>
     <packaging>jar</packaging>
     <name>fescar-spring ${project.version}</name>
-    <properties>
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
-    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
@@ -48,7 +45,11 @@
             <groupId>cglib</groupId>
             <artifactId>cglib</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/AccountService.java b/spring/src/test/java/com/alibaba/fescar/spring/annotation/Business.java
similarity index 70%
rename from examples/src/main/java/com/alibaba/fescar/tm/dubbo/AccountService.java
rename to spring/src/test/java/com/alibaba/fescar/spring/annotation/Business.java
index 2228585eb..f6d9e7197 100644
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/AccountService.java
+++ b/spring/src/test/java/com/alibaba/fescar/spring/annotation/Business.java
@@ -14,18 +14,8 @@
  *  limitations under the License.
  */
 
-package com.alibaba.fescar.tm.dubbo;
+package com.alibaba.fescar.spring.annotation;
 
-/**
- * The interface Account service.
- */
-public interface AccountService {
-
-    /**
-     * 余额扣款
-     *
-     * @param userId 用户ID
-     * @param money  扣款金额
-     */
-    void debit(String userId, int money);
+public interface Business {
+    String doBiz(String msg);
 }
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/StorageService.java b/spring/src/test/java/com/alibaba/fescar/spring/annotation/BusinessImpl.java
similarity index 60%
rename from examples/src/main/java/com/alibaba/fescar/tm/dubbo/StorageService.java
rename to spring/src/test/java/com/alibaba/fescar/spring/annotation/BusinessImpl.java
index eb06ccbd1..00d9978e4 100644
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/StorageService.java
+++ b/spring/src/test/java/com/alibaba/fescar/spring/annotation/BusinessImpl.java
@@ -14,18 +14,18 @@
  *  limitations under the License.
  */
 
-package com.alibaba.fescar.tm.dubbo;
+package com.alibaba.fescar.spring.annotation;
 
-/**
- * The interface Storage service.
- */
-public interface StorageService {
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BusinessImpl implements Business {
+    Logger logger = LoggerFactory.getLogger(BusinessImpl.class);
 
-    /**
-     * 扣减库存
-     *
-     * @param commodityCode 商品编号
-     * @param count         扣减数量
-     */
-    void deduct(String commodityCode, int count);
+    @Override
+    @GlobalTransactional(timeoutMills = 300000, name = "busi-doBiz")
+    public String doBiz(String msg) {
+        logger.info("Business doBiz");
+        return "hello " + msg;
+    }
 }
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/BusinessService.java b/spring/src/test/java/com/alibaba/fescar/spring/annotation/BusinessProxy.java
similarity index 50%
rename from examples/src/main/java/com/alibaba/fescar/tm/dubbo/BusinessService.java
rename to spring/src/test/java/com/alibaba/fescar/spring/annotation/BusinessProxy.java
index 4a7889c87..a847ee574 100644
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/BusinessService.java
+++ b/spring/src/test/java/com/alibaba/fescar/spring/annotation/BusinessProxy.java
@@ -14,19 +14,28 @@
  *  limitations under the License.
  */
 
-package com.alibaba.fescar.tm.dubbo;
+package com.alibaba.fescar.spring.annotation;
 
-/**
- * The interface Business service.
- */
-public interface BusinessService {
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+public class BusinessProxy implements InvocationHandler {
+    private Object proxy;
+
+    public BusinessProxy(Object proxy) {
+        this.proxy = proxy;
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        System.out.println("before");
+        Object result = null;
+        try {
+            result = method.invoke(proxy, args);
+        } catch (Exception e) {
 
-    /**
-     * 用户订购商品
-     *
-     * @param userId        用户ID
-     * @param commodityCode 商品编号
-     * @param orderCount    订购数量
-     */
-    void purchase(String userId, String commodityCode, int orderCount);
+        }
+        System.out.println("after");
+        return result;
+    }
 }
diff --git a/tm/pom.xml b/tm/pom.xml
index 892d80104..d1a9e74ee 100644
--- a/tm/pom.xml
+++ b/tm/pom.xml
@@ -21,16 +21,12 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.3</version>
+        <version>0.1.4</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-tm</artifactId>
     <packaging>jar</packaging>
     <name>fescar-tm ${project.version}</name>
-    <properties>
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
-    </properties>
 
     <dependencies>
         <dependency>
diff --git a/tm/src/main/java/com/alibaba/fescar/tm/DefaultTransactionManager.java b/tm/src/main/java/com/alibaba/fescar/tm/DefaultTransactionManager.java
index 9c460a9d8..65f204a67 100644
--- a/tm/src/main/java/com/alibaba/fescar/tm/DefaultTransactionManager.java
+++ b/tm/src/main/java/com/alibaba/fescar/tm/DefaultTransactionManager.java
@@ -41,7 +41,7 @@ import com.alibaba.fescar.core.rpc.netty.TmRpcClient;
 public class DefaultTransactionManager implements TransactionManager {
 
     private static class SingletonHolder {
-        private static final TransactionManager INSTANCE = new DefaultTransactionManager();
+        private static TransactionManager INSTANCE = new DefaultTransactionManager();
     }
 
     /**
@@ -53,6 +53,14 @@ public class DefaultTransactionManager implements TransactionManager {
         return SingletonHolder.INSTANCE;
     }
 
+    /**
+     * Set a TM instance.
+     * @param mock commonly used for test mocking
+     */
+    public static void set(TransactionManager mock) {
+        SingletonHolder.INSTANCE = mock;
+    }
+
     private DefaultTransactionManager() {
 
     }
diff --git a/tm/src/main/java/com/alibaba/fescar/tm/api/DefaultFailureHandlerImpl.java b/tm/src/main/java/com/alibaba/fescar/tm/api/DefaultFailureHandlerImpl.java
index 4ef02aa39..441fff503 100644
--- a/tm/src/main/java/com/alibaba/fescar/tm/api/DefaultFailureHandlerImpl.java
+++ b/tm/src/main/java/com/alibaba/fescar/tm/api/DefaultFailureHandlerImpl.java
@@ -43,6 +43,6 @@ public class DefaultFailureHandlerImpl implements FailureHandler {
 
     @Override
     public void onRollbackFailure(GlobalTransaction tx, Throwable cause) {
-        LOGGER.warn("Failed to begin transaction[" + tx.getXid() + "]", cause);
+        LOGGER.warn("Failed to rollback transaction[" + tx.getXid() + "]", cause);
     }
 }
diff --git a/tm/src/main/java/com/alibaba/fescar/tm/api/DefaultGlobalTransaction.java b/tm/src/main/java/com/alibaba/fescar/tm/api/DefaultGlobalTransaction.java
index d0faea155..956270518 100644
--- a/tm/src/main/java/com/alibaba/fescar/tm/api/DefaultGlobalTransaction.java
+++ b/tm/src/main/java/com/alibaba/fescar/tm/api/DefaultGlobalTransaction.java
@@ -41,15 +41,15 @@ public class DefaultGlobalTransaction implements GlobalTransaction {
 
     private String xid;
 
-    private GlobalStatus status = GlobalStatus.UnKnown;
+    private GlobalStatus status;
 
-    private GlobalTransactionRole role = GlobalTransactionRole.Launcher;
+    private GlobalTransactionRole role;
 
     /**
      * Instantiates a new Default global transaction.
      */
     DefaultGlobalTransaction() {
-        this(null);
+        this(null, GlobalStatus.UnKnown, GlobalTransactionRole.Launcher);
     }
 
     /**
@@ -57,13 +57,11 @@ public class DefaultGlobalTransaction implements GlobalTransaction {
      *
      * @param xid the xid
      */
-    DefaultGlobalTransaction(String xid) {
+    DefaultGlobalTransaction(String xid, GlobalStatus status, GlobalTransactionRole role) {
         this.transactionManager = DefaultTransactionManager.get();
         this.xid = xid;
-        if (xid != null) {
-            status = GlobalStatus.Begin;
-            role = GlobalTransactionRole.Participant;
-        }
+        this.status = status;
+        this.role = role;
     }
 
     @Override
@@ -78,46 +76,77 @@ public class DefaultGlobalTransaction implements GlobalTransaction {
 
     @Override
     public void begin(int timeout, String name) throws TransactionException {
-        if (xid == null && role == GlobalTransactionRole.Launcher) {
-            xid = transactionManager.begin(null, null, name, timeout);
-            status = GlobalStatus.Begin;
-            RootContext.bind(xid);
-        } else {
-            if (xid == null) {
-                throw new ShouldNeverHappenException(role + " is NOT in a global transaction context.");
+        if (role != GlobalTransactionRole.Launcher) {
+            check();
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("Ignore Begin(): just involved in global transaction [" + xid + "]");
             }
-            LOGGER.info(role + " is already in global transaction " + xid);
+            return;
+        }
+        if (xid != null) {
+            throw new IllegalStateException();
+        }
+        if (RootContext.getXID() != null) {
+            throw new IllegalStateException();
+        }
+        xid = transactionManager.begin(null, null, name, timeout);
+        status = GlobalStatus.Begin;
+        RootContext.bind(xid);
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("Begin a NEW global transaction [" + xid + "]");
         }
 
     }
 
     @Override
     public void commit() throws TransactionException {
-        check();
-        RootContext.unbind();
         if (role == GlobalTransactionRole.Participant) {
             // Participant has no responsibility of committing
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("Ignore Commit(): just involved in global transaction [" + xid + "]");
+            }
             return;
         }
+        if (xid == null) {
+            throw new IllegalStateException();
+        }
+
         status = transactionManager.commit(xid);
+        if (RootContext.getXID() != null) {
+            if (xid.equals(RootContext.getXID())) {
+                RootContext.unbind();
+            }
+        }
 
     }
 
     @Override
     public void rollback() throws TransactionException {
-        check();
-        RootContext.unbind();
         if (role == GlobalTransactionRole.Participant) {
             // Participant has no responsibility of committing
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("Ignore Rollback(): just involved in global transaction [" + xid + "]");
+            }
             return;
         }
+        if (xid == null) {
+            throw new IllegalStateException();
+        }
+
         status = transactionManager.rollback(xid);
+        if (RootContext.getXID() != null) {
+            if (xid.equals(RootContext.getXID())) {
+                RootContext.unbind();
+            }
+        }
 
     }
 
     @Override
     public GlobalStatus getStatus() throws TransactionException {
-        check();
+        if (xid == null) {
+            return GlobalStatus.UnKnown;
+        }
         status = transactionManager.getStatus(xid);
         return status;
     }
diff --git a/tm/src/main/java/com/alibaba/fescar/tm/api/GlobalTransactionContext.java b/tm/src/main/java/com/alibaba/fescar/tm/api/GlobalTransactionContext.java
index c92e4f99d..09d4a2a16 100644
--- a/tm/src/main/java/com/alibaba/fescar/tm/api/GlobalTransactionContext.java
+++ b/tm/src/main/java/com/alibaba/fescar/tm/api/GlobalTransactionContext.java
@@ -17,24 +17,25 @@
 package com.alibaba.fescar.tm.api;
 
 import com.alibaba.fescar.core.context.RootContext;
+import com.alibaba.fescar.core.exception.TransactionException;
+import com.alibaba.fescar.core.model.GlobalStatus;
+import com.alibaba.fescar.core.model.TransactionManager;
 
 /**
- * Context of global transaction on current thread.
+ * GlobalTransaction API
  */
 public class GlobalTransactionContext {
 
-    private static final ThreadLocal<GlobalTransaction> THREAD_TRANSACTION_CONTEXT = new ThreadLocal<>();
-
     private GlobalTransactionContext() {
     }
 
     /**
      * Try to create a new GlobalTransaction.
+     *
      * @return
      */
     private static GlobalTransaction createNew() {
         GlobalTransaction tx = new DefaultGlobalTransaction();
-        THREAD_TRANSACTION_CONTEXT.set(tx);
         return tx;
     }
 
@@ -43,23 +44,16 @@ public class GlobalTransactionContext {
      *
      * @return null if no transaction context there.
      */
-    public static GlobalTransaction getCurrent() {
-        GlobalTransaction tx = THREAD_TRANSACTION_CONTEXT.get();
-        if (tx != null) {
-            return tx;
-        }
+    private static GlobalTransaction getCurrent() {
         String xid = RootContext.getXID();
         if (xid == null) {
             return null;
         }
-        tx = new DefaultGlobalTransaction(xid);
-        THREAD_TRANSACTION_CONTEXT.set(tx);
-        return tx;
+        return new DefaultGlobalTransaction(xid, GlobalStatus.Begin, GlobalTransactionRole.Participant);
     }
 
     /**
-     * Get GlobalTransaction instance bind on current thread.
-     * Create a new on if no existing there.
+     * Get GlobalTransaction instance bind on current thread. Create a new on if no existing there.
      *
      * @return new context if no existing there.
      */
@@ -72,10 +66,17 @@ public class GlobalTransactionContext {
     }
 
     /**
-     * Clean context.
+     * Reload GlobalTransaction instance according to the given XID
+     *
+     * @return reloaded transaction instance.
      */
-    public static void clean() {
-        THREAD_TRANSACTION_CONTEXT.remove();
-        RootContext.unbind();
+    public static GlobalTransaction reload(String xid) throws TransactionException {
+        GlobalTransaction tx = new DefaultGlobalTransaction(xid, GlobalStatus.UnKnown, GlobalTransactionRole.Launcher) {
+            @Override
+            public void begin(int timeout, String name) throws TransactionException {
+                throw new IllegalStateException("Never BEGIN on a RELOADED GlobalTransaction. ");
+            }
+        };
+        return tx;
     }
 }
diff --git a/tm/src/main/java/com/alibaba/fescar/tm/api/TransactionalTemplate.java b/tm/src/main/java/com/alibaba/fescar/tm/api/TransactionalTemplate.java
index e3a5994d9..f44ad945a 100644
--- a/tm/src/main/java/com/alibaba/fescar/tm/api/TransactionalTemplate.java
+++ b/tm/src/main/java/com/alibaba/fescar/tm/api/TransactionalTemplate.java
@@ -28,7 +28,7 @@ public class TransactionalTemplate {
      *
      * @param business the business
      * @return the object
-     * @throws ExecutionException the execution exception
+     * @throws TransactionalExecutor.ExecutionException the execution exception
      */
     public Object execute(TransactionalExecutor business) throws TransactionalExecutor.ExecutionException {
 
@@ -65,8 +65,6 @@ public class TransactionalTemplate {
                 throw new TransactionalExecutor.ExecutionException(tx, txe,
                     TransactionalExecutor.Code.RollbackFailure, ex);
 
-            } finally {
-                GlobalTransactionContext.clean();
             }
 
         }
@@ -80,8 +78,6 @@ public class TransactionalTemplate {
             throw new TransactionalExecutor.ExecutionException(tx, txe,
                 TransactionalExecutor.Code.CommitFailure);
 
-        } finally {
-            GlobalTransactionContext.clean();
         }
         return rs;
     }


Test patch:
diff --git a/core/src/test/java/com/alibaba/fescar/core/message/BranchRegisterResponseTest.java b/core/src/test/java/com/alibaba/fescar/core/message/BranchRegisterResponseTest.java
new file mode 100644
index 000000000..7861e7e59
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fescar/core/message/BranchRegisterResponseTest.java
@@ -0,0 +1,37 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.core.message;
+
+import com.alibaba.fescar.core.protocol.ResultCode;
+import com.alibaba.fescar.core.protocol.transaction.BranchRegisterResponse;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BranchRegisterResponseTest {
+
+  @Test
+  public void toStringTest() throws Exception{
+    BranchRegisterResponse branchRegisterResponse = new BranchRegisterResponse();
+
+    branchRegisterResponse.setTransactionId(123456L);
+    branchRegisterResponse.setBranchId(123457L);
+    branchRegisterResponse.setResultCode(ResultCode.Success);
+    branchRegisterResponse.setMsg("");
+    Assert.assertEquals("BranchRegisterResponse: transactionId=123456,branchId=123457,result code =Success,getMsg =", branchRegisterResponse.toString());
+
+  }
+}
diff --git a/core/src/test/java/com/alibaba/fescar/core/message/RegisterTMResponseTest.java b/core/src/test/java/com/alibaba/fescar/core/message/RegisterTMResponseTest.java
new file mode 100644
index 000000000..dacd449da
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fescar/core/message/RegisterTMResponseTest.java
@@ -0,0 +1,37 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.core.message;
+
+import com.alibaba.fescar.core.protocol.RegisterTMResponse;
+import com.alibaba.fescar.core.protocol.ResultCode;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class RegisterTMResponseTest {
+
+  @Test
+  public void testToString() throws Exception{
+    RegisterTMResponse registerTMResponse = new RegisterTMResponse();
+
+    registerTMResponse.setVersion("1");
+    registerTMResponse.setIdentified(true);
+    registerTMResponse.setResultCode(ResultCode.Success);
+
+    Assert.assertEquals("version=1,extraData=null,identified=true,resultCode=Success,msg=null", registerTMResponse.toString());
+
+  }
+}
diff --git a/core/src/test/java/com/alibaba/fescar/core/rpc/netty/TmRpcClientTest.java b/core/src/test/java/com/alibaba/fescar/core/rpc/netty/TmRpcClientTest.java
index dccec5be4..699edd43b 100644
--- a/core/src/test/java/com/alibaba/fescar/core/rpc/netty/TmRpcClientTest.java
+++ b/core/src/test/java/com/alibaba/fescar/core/rpc/netty/TmRpcClientTest.java
@@ -16,25 +16,87 @@
 
 package com.alibaba.fescar.core.rpc.netty;
 
+import org.apache.commons.pool.impl.GenericKeyedObjectPool;
+import org.junit.Assert;
 import org.junit.Test;
 
+import java.lang.reflect.Field;
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.bootstrap.ChannelFactory;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.socket.nio.NioSocketChannel;
+
 /**
  * The type Tm rpc client test.
- *
- * @Author: jimin.jm @alibaba-inc.com
- * @Project: fescar -all
- * @DateTime: 2018 /12/26 14:32
+ * @Author: jimin.jm@alibaba-inc.com
+ * @Author: xiajun.0706@163.com
+ * @Project: fescar-all
+ * @DateTime: 2019/01/25 08:32
  * @FileName: TmRpcClientTest
  * @Description:
  */
 public class TmRpcClientTest {
+
+    private static final ThreadPoolExecutor
+        workingThreads = new ThreadPoolExecutor(100, 500, 500, TimeUnit.SECONDS,
+                                                new LinkedBlockingQueue(20000), new ThreadPoolExecutor.CallerRunsPolicy());
+
+    @Test
+    public void testGetInstance() throws Exception {
+        String applicationId = "app 1";
+        String transactionServiceGroup = "group A";
+        TmRpcClient tmRpcClient = TmRpcClient.getInstance(applicationId, transactionServiceGroup);
+
+        NettyClientConfig defaultNettyClientConfig = new NettyClientConfig();
+        GenericKeyedObjectPool.Config config = tmRpcClient.getNettyPoolConfig();
+        Assert.assertEquals(defaultNettyClientConfig.getMaxPoolActive(), config.maxActive);
+        Assert.assertEquals(defaultNettyClientConfig.getMinPoolIdle(), config.minIdle);
+        Assert.assertEquals(defaultNettyClientConfig.getMaxAcquireConnMills(), config.maxWait);
+        Assert.assertEquals(defaultNettyClientConfig.isPoolTestBorrow(), config.testOnBorrow);
+        Assert.assertEquals(defaultNettyClientConfig.isPoolTestReturn(), config.testOnReturn);
+        Assert.assertEquals(defaultNettyClientConfig.isPoolFifo(), config.lifo);
+    }
+
     /**
      * Do connect.
      *
      * @throws Exception the exception
      */
     @Test
-    public void doConnect() throws Exception {
+    public void testInit() throws Exception {
+        String applicationId = "app 1";
+        String transactionServiceGroup = "group A";
+        TmRpcClient tmRpcClient = TmRpcClient.getInstance(applicationId, transactionServiceGroup);
+
+        tmRpcClient.init();
+
+        //check if attr of tmRpcClient object has been set success
+        Field bootstrapField = getDeclaredField(tmRpcClient, "bootstrap");
+        bootstrapField.setAccessible(true);
+        Bootstrap bootstrap = (Bootstrap) bootstrapField.get(tmRpcClient);
+
+        Assert.assertNotNull(bootstrap);
+        Field optionsField = getDeclaredField(bootstrap, "options");
+        optionsField.setAccessible(true);
+        Map<ChannelOption<?>, Object> options = (Map<ChannelOption<?>, Object>) optionsField.get(bootstrap);
+        Assert.assertTrue(Boolean.TRUE.equals(options.get(ChannelOption.TCP_NODELAY)));
+        Assert.assertTrue(Boolean.TRUE.equals(options.get(ChannelOption.SO_KEEPALIVE)));
+        Assert.assertEquals(10000, options.get(ChannelOption.CONNECT_TIMEOUT_MILLIS));
+        Assert.assertTrue(Boolean.TRUE.equals(options.get(ChannelOption.SO_KEEPALIVE)));
+        Assert.assertEquals(153600, options.get(ChannelOption.SO_RCVBUF));
+
+        Field channelFactoryField = getDeclaredField(bootstrap, "channelFactory");
+        channelFactoryField.setAccessible(true);
+        ChannelFactory<? extends Channel>
+            channelFactory = (ChannelFactory<? extends Channel>) channelFactoryField.get(bootstrap);
+        Assert.assertNotNull(channelFactory);
+        Assert.assertTrue(channelFactory.newChannel() instanceof NioSocketChannel);
 
     }
 
@@ -58,4 +120,25 @@ public class TmRpcClientTest {
 
     }
 
+    /**
+     * get private field in parent class
+     *
+     * @param object
+     * @param fieldName
+     * @return
+     */
+    public static Field getDeclaredField(Object object, String fieldName){
+        Field field = null ;
+        Class<?> clazz = object.getClass() ;
+        for(; clazz != Object.class ; clazz = clazz.getSuperclass()) {
+            try {
+                field = clazz.getDeclaredField(fieldName) ;
+                return field ;
+            } catch (Exception e) {
+
+            }
+        }
+
+        return null;
+    }
 }
diff --git a/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/struct/TableMetaTest.java b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/struct/TableMetaTest.java
new file mode 100644
index 000000000..5a4f6fc02
--- /dev/null
+++ b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/struct/TableMetaTest.java
@@ -0,0 +1,1094 @@
+package com.alibaba.fescar.rm.datasource.sql.struct;
+
+import com.alibaba.druid.mock.MockStatementBase;
+import com.alibaba.druid.mock.handler.MockExecuteHandler;
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.druid.util.jdbc.ResultSetMetaDataBase;
+import com.alibaba.fescar.rm.datasource.DataSourceProxy;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.sql.*;
+import java.util.*;
+
+/**
+ * The table meta fetch test.
+ *
+ * @author hanwen created at 2019-02-01
+ */
+public class TableMetaTest {
+
+    private static Object[][] columnMetas =
+            new Object[][]{
+                    new Object[]{"", "", "t1", "id", Types.INTEGER, "INTEGER", 64, 0, 10, 1, "", "", 0, 0, 64, 1, "NO", "YES"},
+                    new Object[]{"", "", "t1", "name1", Types.VARCHAR, "VARCHAR", 64, 0, 10, 0, "", "", 0, 0, 64, 2, "YES", "NO"},
+                    new Object[]{"", "", "t1", "name2", Types.VARCHAR, "VARCHAR", 64, 0, 10, 0, "", "", 0, 0, 64, 3, "YES", "NO"},
+                    new Object[]{"", "", "t1", "name3", Types.VARCHAR, "VARCHAR", 64, 0, 10, 0, "", "", 0, 0, 64, 4, "YES", "NO"}
+            };
+
+    private static Object[][] indexMetas =
+            new Object[][]{
+                    new Object[]{"PRIMARY", "id", false, "", 3, 1, "A", 34},
+                    new Object[]{"name1", "name1", false, "", 3, 1, "A", 34}
+            };
+
+    /**
+     * The table meta fetch test.
+     */
+    @Test
+    public void getTableMetaTest_0() {
+
+        MockDriver mockDriver = new MockDriver();
+        mockDriver.setExecuteHandler(new MockExecuteHandler() {
+            @Override
+            public ResultSet executeQuery(MockStatementBase statement, String s) throws SQLException {
+
+                com.alibaba.druid.mock.MockResultSet resultSet = new com.alibaba.druid.mock.MockResultSet(statement);
+
+                // just fetch meta from select * from `table` limit 1
+                List<ResultSetMetaDataBase.ColumnMetaData> columns = resultSet.getMockMetaData().getColumns();
+                columns.add(new ResultSetMetaDataBase.ColumnMetaData());
+                columns.add(new ResultSetMetaDataBase.ColumnMetaData());
+                columns.add(new ResultSetMetaDataBase.ColumnMetaData());
+                columns.add(new ResultSetMetaDataBase.ColumnMetaData());
+
+                return resultSet;
+            }
+        });
+        DruidDataSource dataSource = new DruidDataSource();
+        dataSource.setUrl("jdbc:mock:xxx");
+        dataSource.setDriver(mockDriver);
+
+        DataSourceProxy proxy = new DataSourceProxy(dataSource);
+
+        TableMeta tableMeta = TableMetaCache.getTableMeta(proxy, "t1");
+
+        Assert.assertEquals("t1", tableMeta.getTableName());
+        Assert.assertEquals("id", tableMeta.getPkName());
+
+        Assert.assertEquals("id", tableMeta.getColumnMeta("id").getColumnName());
+        Assert.assertEquals("id", tableMeta.getAutoIncreaseColumn().getColumnName());
+        Assert.assertEquals(1, tableMeta.getPrimaryKeyMap().size());
+        Assert.assertEquals(Collections.singletonList("id"), tableMeta.getPrimaryKeyOnlyName());
+
+        Assert.assertEquals(4, tableMeta.getAllColumns().size());
+
+        assertColumnMetaEquals(columnMetas[0], tableMeta.getAllColumns().get("id"));
+        assertColumnMetaEquals(columnMetas[1], tableMeta.getAllColumns().get("name1"));
+        assertColumnMetaEquals(columnMetas[2], tableMeta.getAllColumns().get("name2"));
+        assertColumnMetaEquals(columnMetas[3], tableMeta.getAllColumns().get("name3"));
+
+        Assert.assertEquals(2, tableMeta.getAllIndexes().size());
+
+        assertIndexMetaEquals(indexMetas[0], tableMeta.getAllIndexes().get("PRIMARY"));
+        Assert.assertEquals(IndexType.PRIMARY, tableMeta.getAllIndexes().get("PRIMARY").getIndextype());
+        assertIndexMetaEquals(indexMetas[1], tableMeta.getAllIndexes().get("name1"));
+        Assert.assertEquals(IndexType.Unique, tableMeta.getAllIndexes().get("name1").getIndextype());
+
+    }
+
+    private void assertColumnMetaEquals(Object[] expected, ColumnMeta actual) {
+        Assert.assertEquals(expected[0], actual.getTableCat());
+        Assert.assertEquals(expected[3], actual.getColumnName());
+        Assert.assertEquals(expected[4], actual.getDataType());
+        Assert.assertEquals(expected[5], actual.getDataTypeName());
+        Assert.assertEquals(expected[6], actual.getColumnSize());
+        Assert.assertEquals(expected[7], actual.getDecimalDigits());
+        Assert.assertEquals(expected[8], actual.getNumPrecRadix());
+        Assert.assertEquals(expected[9], actual.getNullAble());
+        Assert.assertEquals(expected[10], actual.getRemarks());
+        Assert.assertEquals(expected[11], actual.getColumnDef());
+        Assert.assertEquals(expected[12], actual.getSqlDataType());
+        Assert.assertEquals(expected[13], actual.getSqlDatetimeSub());
+        Assert.assertEquals(expected[14], actual.getCharOctetLength());
+        Assert.assertEquals(expected[15], actual.getOrdinalPosition());
+        Assert.assertEquals(expected[16], actual.getIsNullAble());
+        Assert.assertEquals(expected[17], actual.getIsAutoincrement());
+    }
+
+    private void assertIndexMetaEquals(Object[] expected, IndexMeta actual) {
+        Assert.assertEquals(expected[0], actual.getIndexName());
+        Assert.assertEquals(expected[3], actual.getIndexQualifier());
+        Assert.assertEquals(expected[4], (int) actual.getType());
+        Assert.assertEquals(expected[5], actual.getOrdinalPosition());
+        Assert.assertEquals(expected[6], actual.getAscOrDesc());
+        Assert.assertEquals(expected[7], actual.getCardinality());
+    }
+
+    private class MockDriver extends com.alibaba.druid.mock.MockDriver {
+
+        @Override
+        public MockConnection createMockConnection(com.alibaba.druid.mock.MockDriver driver, String url, Properties connectProperties) {
+            return new MockConnection(this, url, connectProperties);
+        }
+    }
+
+    private class MockResultSet extends com.alibaba.druid.mock.MockResultSet {
+
+        private List<String> columnLabels;
+
+        public MockResultSet(Statement statement, List<String> columnLabels) {
+            super(statement);
+            this.columnLabels = new ArrayList<>(columnLabels);
+        }
+
+        @Override
+        public int findColumn(String columnLabel) throws SQLException {
+            return columnLabels.indexOf(columnLabel) + 1;
+        }
+    }
+
+    private class MockConnection extends com.alibaba.druid.mock.MockConnection {
+
+        public MockConnection(com.alibaba.druid.mock.MockDriver driver, String url, Properties connectProperties) {
+            super(driver, url, connectProperties);
+        }
+
+        @Override
+        public DatabaseMetaData getMetaData() throws SQLException {
+
+            return new DatabaseMetaData() {
+
+                @Override
+                public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException {
+                    List<String> columnLabels = Arrays.asList(
+                            "TABLE_CAT",
+                            "TABLE_SCHEM",
+                            "TABLE_NAME",
+                            "COLUMN_NAME",
+                            "DATA_TYPE",
+                            "TYPE_NAME",
+                            "COLUMN_SIZE",
+                            "DECIMAL_DIGITS",
+                            "NUM_PREC_RADIX",
+                            "NULLABLE",
+                            "REMARKS",
+                            "COLUMN_DEF",
+                            "SQL_DATA_TYPE",
+                            "SQL_DATETIME_SUB",
+                            "CHAR_OCTET_LENGTH",
+                            "ORDINAL_POSITION",
+                            "IS_NULLABLE",
+                            "IS_AUTOINCREMENT"
+                    );
+
+                    MockResultSet resultSet = new MockResultSet(createStatement(), columnLabels);
+
+                    List<ResultSetMetaDataBase.ColumnMetaData> columns = resultSet.getMockMetaData().getColumns();
+                    for (String columnLabel : columnLabels) {
+                        ResultSetMetaDataBase.ColumnMetaData column = new ResultSetMetaDataBase.ColumnMetaData();
+                        column.setColumnName(columnLabel);
+                        columns.add(column);
+                    }
+
+                    resultSet.getRows().add(columnMetas[0]);
+                    resultSet.getRows().add(columnMetas[1]);
+                    resultSet.getRows().add(columnMetas[2]);
+                    resultSet.getRows().add(columnMetas[3]);
+
+                    return resultSet;
+                }
+
+
+                @Override
+                public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException {
+
+                    List<String> columnLabels = Arrays.asList(
+                            "INDEX_NAME",
+                            "COLUMN_NAME",
+                            "NON_UNIQUE",
+                            "INDEX_QUALIFIER",
+                            "TYPE",
+                            "ORDINAL_POSITION",
+                            "ASC_OR_DESC",
+                            "CARDINALITY"
+                    );
+
+                    MockResultSet resultSet = new MockResultSet(createStatement(), columnLabels);
+
+                    List<ResultSetMetaDataBase.ColumnMetaData> columns = resultSet.getMockMetaData().getColumns();
+                    for (String columnLabel : columnLabels) {
+                        ResultSetMetaDataBase.ColumnMetaData column = new ResultSetMetaDataBase.ColumnMetaData();
+                        column.setColumnName(columnLabel);
+                        columns.add(column);
+                    }
+
+                    resultSet.getRows().add(indexMetas[0]);
+                    resultSet.getRows().add(indexMetas[1]);
+
+                    return resultSet;
+                }
+
+                @Override
+                public boolean allProceduresAreCallable() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean allTablesAreSelectable() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public String getURL() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getUserName() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public boolean isReadOnly() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean nullsAreSortedHigh() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean nullsAreSortedLow() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean nullsAreSortedAtStart() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean nullsAreSortedAtEnd() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public String getDatabaseProductName() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getDatabaseProductVersion() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getDriverName() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getDriverVersion() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public int getDriverMajorVersion() {
+                    return 0;
+                }
+
+                @Override
+                public int getDriverMinorVersion() {
+                    return 0;
+                }
+
+                @Override
+                public boolean usesLocalFiles() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean usesLocalFilePerTable() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsMixedCaseIdentifiers() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean storesUpperCaseIdentifiers() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean storesLowerCaseIdentifiers() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean storesMixedCaseIdentifiers() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public String getIdentifierQuoteString() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getSQLKeywords() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getNumericFunctions() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getStringFunctions() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getSystemFunctions() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getTimeDateFunctions() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getSearchStringEscape() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getExtraNameCharacters() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public boolean supportsAlterTableWithAddColumn() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsAlterTableWithDropColumn() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsColumnAliasing() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean nullPlusNonNullIsNull() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsConvert() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsConvert(int fromType, int toType) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsTableCorrelationNames() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsDifferentTableCorrelationNames() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsExpressionsInOrderBy() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsOrderByUnrelated() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsGroupBy() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsGroupByUnrelated() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsGroupByBeyondSelect() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsLikeEscapeClause() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsMultipleResultSets() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsMultipleTransactions() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsNonNullableColumns() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsMinimumSQLGrammar() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsCoreSQLGrammar() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsExtendedSQLGrammar() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsANSI92EntryLevelSQL() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsANSI92IntermediateSQL() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsANSI92FullSQL() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsIntegrityEnhancementFacility() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsOuterJoins() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsFullOuterJoins() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsLimitedOuterJoins() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public String getSchemaTerm() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getProcedureTerm() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public String getCatalogTerm() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public boolean isCatalogAtStart() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public String getCatalogSeparator() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public boolean supportsSchemasInDataManipulation() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsSchemasInProcedureCalls() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsSchemasInTableDefinitions() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsSchemasInIndexDefinitions() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsCatalogsInDataManipulation() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsCatalogsInProcedureCalls() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsCatalogsInTableDefinitions() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsPositionedDelete() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsPositionedUpdate() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsSelectForUpdate() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsStoredProcedures() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsSubqueriesInComparisons() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsSubqueriesInExists() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsSubqueriesInIns() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsSubqueriesInQuantifieds() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsCorrelatedSubqueries() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsUnion() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsUnionAll() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public int getMaxBinaryLiteralLength() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxCharLiteralLength() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxColumnNameLength() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxColumnsInGroupBy() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxColumnsInIndex() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxColumnsInOrderBy() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxColumnsInSelect() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxColumnsInTable() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxConnections() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxCursorNameLength() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxIndexLength() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxSchemaNameLength() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxProcedureNameLength() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxCatalogNameLength() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxRowSize() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public int getMaxStatementLength() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxStatements() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxTableNameLength() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxTablesInSelect() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getMaxUserNameLength() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getDefaultTransactionIsolation() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public boolean supportsTransactions() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsTransactionIsolationLevel(int level) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsDataManipulationTransactionsOnly() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean dataDefinitionCausesTransactionCommit() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getSchemas() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getCatalogs() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getTableTypes() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getTypeInfo() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public boolean supportsResultSetType(int type) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean ownUpdatesAreVisible(int type) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean ownDeletesAreVisible(int type) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean ownInsertsAreVisible(int type) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean othersUpdatesAreVisible(int type) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean othersDeletesAreVisible(int type) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean othersInsertsAreVisible(int type) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean updatesAreDetected(int type) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean deletesAreDetected(int type) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean insertsAreDetected(int type) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsBatchUpdates() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public Connection getConnection() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public boolean supportsSavepoints() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsNamedParameters() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsMultipleOpenResults() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsGetGeneratedKeys() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public boolean supportsResultSetHoldability(int holdability) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public int getResultSetHoldability() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getDatabaseMajorVersion() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getDatabaseMinorVersion() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getJDBCMajorVersion() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getJDBCMinorVersion() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public int getSQLStateType() throws SQLException {
+                    return 0;
+                }
+
+                @Override
+                public boolean locatorsUpdateCopy() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean supportsStatementPooling() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public RowIdLifetime getRowIdLifetime() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public boolean autoCommitFailureClosesAllResultSets() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public ResultSet getClientInfoProperties() throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public boolean generatedKeyAlwaysReturned() throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public <T> T unwrap(Class<T> iface) throws SQLException {
+                    return null;
+                }
+
+                @Override
+                public boolean isWrapperFor(Class<?> iface) throws SQLException {
+                    return false;
+                }
+            };
+        }
+    }
+}
diff --git a/spring/src/test/java/com/alibaba/fescar/spring/annotation/GlobalTransactionScannerTest.java b/spring/src/test/java/com/alibaba/fescar/spring/annotation/GlobalTransactionScannerTest.java
new file mode 100644
index 000000000..6c7a43704
--- /dev/null
+++ b/spring/src/test/java/com/alibaba/fescar/spring/annotation/GlobalTransactionScannerTest.java
@@ -0,0 +1,47 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.alibaba.fescar.spring.annotation;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * GlobalTransactionScanner Unit Test
+ */
+public class GlobalTransactionScannerTest {
+    private GlobalTransactionScanner globalTransactionScanner = new GlobalTransactionScanner("global-trans-scanner-test");
+
+    @Test(dataProvider = "normalBeanProvider")
+    public void testWrapNormalBean(Object bean, String beanName, Object cacheKey) {
+        Object result = globalTransactionScanner.wrapIfNecessary(bean, beanName, cacheKey);
+        Assert.assertNotSame(result, bean);
+    }
+
+    @Test
+    public void testAfterPropertiesSet() {
+        globalTransactionScanner.afterPropertiesSet();
+    }
+
+    @DataProvider
+    public static Object[][] normalBeanProvider() {
+        Business business = new BusinessImpl();
+        String beanName = "business";
+        String cacheKey = "business-key";
+        return new Object[][]{{business, beanName, cacheKey}};
+    }
+}
diff --git a/test/pom.xml b/test/pom.xml
index f314724a1..2620a98de 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -20,25 +20,18 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.3</version>
+        <version>0.1.4</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-test</artifactId>
     <packaging>jar</packaging>
     <name>fescar-test ${project.version}</name>
-    <properties>
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
-    </properties>
+
     <build>
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <configuration>
-                    <source>6</source>
-                    <target>6</target>
-                </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
@@ -56,6 +49,10 @@
             <groupId>${project.groupId}</groupId>
             <artifactId>fescar-tm</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>fescar-server</artifactId>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>fescar-rm-datasource</artifactId>
diff --git a/test/src/test/java/com/alibaba/fescar/core/rpc/netty/TmRpcClientTest.java b/test/src/test/java/com/alibaba/fescar/core/rpc/netty/TmRpcClientTest.java
new file mode 100644
index 000000000..8adbe53d9
--- /dev/null
+++ b/test/src/test/java/com/alibaba/fescar/core/rpc/netty/TmRpcClientTest.java
@@ -0,0 +1,159 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.alibaba.fescar.core.rpc.netty;
+
+import com.alibaba.fescar.core.protocol.ResultCode;
+import com.alibaba.fescar.core.protocol.transaction.BranchRegisterRequest;
+import com.alibaba.fescar.core.protocol.transaction.BranchRegisterResponse;
+import com.alibaba.fescar.server.UUIDGenerator;
+import com.alibaba.fescar.server.coordinator.DefaultCoordinator;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import io.netty.channel.Channel;
+
+/**
+ * @Author: jimin.jm@alibaba-inc.com
+ * @Author: xiajun.0706@163.com
+ * @Project: fescar-all
+ * @DateTime: 2019/01/25 08:32
+ * @FileName: TmRpcClientTest
+ * @Description:
+ */
+public class TmRpcClientTest {
+
+    private static final ThreadPoolExecutor
+        workingThreads = new ThreadPoolExecutor(100, 500, 500, TimeUnit.SECONDS,
+                                                new LinkedBlockingQueue(20000), new ThreadPoolExecutor.CallerRunsPolicy());
+
+    /**
+     * Client rely on server's starting first
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testDoConnect() throws Exception {
+
+        //start fescar server first
+        workingThreads.submit(new Runnable() {
+            @Override
+            public void run() {
+                RpcServer rpcServer = new RpcServer(workingThreads);
+                rpcServer.setHandler(new DefaultCoordinator(rpcServer));
+                UUIDGenerator.init(1);
+                rpcServer.init();
+            }
+        });
+
+        //then test client
+        Thread.sleep(3000);
+
+        String applicationId = "app 1";
+        String transactionServiceGroup = "group A";
+        TmRpcClient tmRpcClient = TmRpcClient.getInstance(applicationId, transactionServiceGroup);
+
+        tmRpcClient.init();
+
+        Method doConnectMethod = TmRpcClient.class.getDeclaredMethod("doConnect", String.class);
+        doConnectMethod.setAccessible(true);
+        String serverAddress = "0.0.0.0:8091";
+        Channel channel = (Channel) doConnectMethod.invoke(tmRpcClient, serverAddress);
+        System.out.print("channel = ");
+        Assert.assertNotNull(channel);
+    }
+
+    /**
+     * Client rely on server's starting first
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testReconnect() throws Exception {
+
+        //start fescar server first
+        workingThreads.submit(new Runnable() {
+            @Override
+            public void run() {
+                RpcServer rpcServer = new RpcServer(workingThreads);
+                rpcServer.setHandler(new DefaultCoordinator(rpcServer));
+                UUIDGenerator.init(1);
+                rpcServer.init();
+            }
+        });
+
+        //then test client
+        Thread.sleep(3000);
+
+        String applicationId = "app 1";
+        String transactionServiceGroup = "my_test_tx_group";
+        TmRpcClient tmRpcClient = TmRpcClient.getInstance(applicationId, transactionServiceGroup);
+
+        tmRpcClient.init();
+
+        Method doConnectMethod = TmRpcClient.class.getDeclaredMethod("reconnect");
+        doConnectMethod.setAccessible(true);
+        doConnectMethod.invoke(tmRpcClient);
+    }
+
+    @Test
+    public void testSendMsgWithResponse() throws Exception {
+
+        //start fescar server first
+        workingThreads.submit(new Runnable() {
+            @Override
+            public void run() {
+                RpcServer rpcServer = new RpcServer(workingThreads);
+                rpcServer.setHandler(new DefaultCoordinator(rpcServer));
+                UUIDGenerator.init(1);
+                rpcServer.init();
+            }
+        });
+
+        //then test client
+        Thread.sleep(3000);
+
+        String applicationId = "app 1";
+        String transactionServiceGroup = "my_test_tx_group";
+        TmRpcClient tmRpcClient = TmRpcClient.getInstance(applicationId, transactionServiceGroup);
+
+        tmRpcClient.init();
+
+        Method doConnectMethod = TmRpcClient.class.getDeclaredMethod("doConnect", String.class);
+        doConnectMethod.setAccessible(true);
+        String serverAddress = "0.0.0.0:8091";
+        Channel channel = (Channel) doConnectMethod.invoke(tmRpcClient, serverAddress);
+        System.out.print("channel = " + channel);
+        Assert.assertNotNull(channel);
+
+        BranchRegisterRequest request = new BranchRegisterRequest();
+        request.setTransactionId(123456L);
+        request.setLockKey("lock key testSendMsgWithResponse");
+        request.setResourceId("resoutceId1");
+        BranchRegisterResponse branchRegisterResponse = (BranchRegisterResponse)tmRpcClient.sendMsgWithResponse(request);
+        Assert.assertNotNull(branchRegisterResponse);
+        //we have not init SessionManager
+        Assert.assertEquals(ResultCode.Failed, branchRegisterResponse.getResultCode());
+        Assert.assertEquals("RuntimeException[SessionManager is NOT init!]",
+                            branchRegisterResponse.getMsg());
+    }
+}
diff --git a/tm/src/test/java/com/alibaba/fescar/tm/api/APITest.java b/tm/src/test/java/com/alibaba/fescar/tm/api/APITest.java
index 0f368120b..ba12ac2b5 100644
--- a/tm/src/test/java/com/alibaba/fescar/tm/api/APITest.java
+++ b/tm/src/test/java/com/alibaba/fescar/tm/api/APITest.java
@@ -18,14 +18,54 @@ package com.alibaba.fescar.tm.api;
 
 import com.alibaba.fescar.core.context.RootContext;
 
+import com.alibaba.fescar.core.exception.TransactionException;
+import com.alibaba.fescar.core.model.GlobalStatus;
+import com.alibaba.fescar.core.model.TransactionManager;
+import com.alibaba.fescar.tm.DefaultTransactionManager;
+import org.junit.After;
 import org.junit.Assert;
+import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 /**
  * The type Api test.
  */
 public class APITest {
 
+    private static final String DEFAULT_XID = "1234567890";
+
+    @BeforeClass
+    public static void init() {
+        DefaultTransactionManager.set(new TransactionManager() {
+            @Override
+            public String begin(String applicationId, String transactionServiceGroup, String name, int timeout)
+                throws TransactionException {
+                return DEFAULT_XID;
+            }
+
+            @Override
+            public GlobalStatus commit(String xid) throws TransactionException {
+                return GlobalStatus.Committed;
+            }
+
+            @Override
+            public GlobalStatus rollback(String xid) throws TransactionException {
+                return GlobalStatus.Rollbacked;
+            }
+
+            @Override
+            public GlobalStatus getStatus(String xid) throws TransactionException {
+                return GlobalStatus.Begin;
+            }
+        });
+    }
+
+    @After
+    public void cleanRootContext() {
+        RootContext.unbind();
+    }
+
     /**
      * Test current.
      *
@@ -33,10 +73,109 @@ public class APITest {
      */
     @Test
     public void testCurrent() throws Exception {
-        String xid = "1234567890";
-        RootContext.bind(xid);
+        RootContext.bind(DEFAULT_XID);
+        GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
+        Assert.assertEquals(tx.getXid(), DEFAULT_XID);
+        Assert.assertEquals(tx.getStatus(), GlobalStatus.Begin);
+
+    }
+
+    @Test
+    public void testNewTx() throws Exception {
+        GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
+        Assert.assertEquals(tx.getStatus(), GlobalStatus.UnKnown);
+        Assert.assertNull(tx.getXid());
+    }
+
+    @Test
+    public void testBegin() throws Exception {
         GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
-        Assert.assertEquals(xid, tx.getXid());
+        tx.begin();
+        Assert.assertEquals(tx.getStatus(), GlobalStatus.Begin);
+        Assert.assertNotNull(tx.getXid());
+
+    }
+
+    @Test
+    public void testNestedCommit() throws Exception {
+        TransactionalTemplate template = new TransactionalTemplate();
+        template.execute(new AbstractTransactionalExecutor() {
+            @Override
+            public Object execute() throws Throwable {
+
+                TransactionalTemplate template = new TransactionalTemplate();
+                template.execute(new AbstractTransactionalExecutor() {
+                    @Override
+                    public Object execute() throws Throwable {
+
+                        TransactionalTemplate template = new TransactionalTemplate();
+                        template.execute(new AbstractTransactionalExecutor() {
+                            @Override
+                            public Object execute() throws Throwable {
+                                return null;
+                            }
+                        });
+                        return null;
+                    }
+                });
+                return null;
+            }
+        });
+    }
+
+    @Test
+    public void testNestedRollback() throws Exception {
+
+        final String oexMsg = "xxx";
+
+        TransactionalTemplate template = new TransactionalTemplate();
+        try {
+            template.execute(new AbstractTransactionalExecutor() {
+                @Override
+                public Object execute() throws Throwable {
+
+                    TransactionalTemplate template = new TransactionalTemplate();
+                    try {
+                        template.execute(new AbstractTransactionalExecutor() {
+                            @Override
+                            public Object execute() throws Throwable {
+
+                                TransactionalTemplate template = new TransactionalTemplate();
+                                try {
+                                    template.execute(new AbstractTransactionalExecutor() {
+                                        @Override
+                                        public Object execute() throws Throwable {
+                                            throw new RuntimeException(oexMsg);
+                                        }
+                                    });
+                                } catch (TransactionalExecutor.ExecutionException ex) {
+                                    throw ex.getOriginalException();
+                                }
+                                return null;
+                            }
+                        });
+                    } catch (TransactionalExecutor.ExecutionException ex) {
+                        throw ex.getOriginalException();
+                    }
+                    return null;
+                }
+            });
+        } catch (TransactionalExecutor.ExecutionException ex) {
+            Throwable oex = ex.getOriginalException();
+            Assert.assertEquals(oex.getMessage(), oexMsg);
+        }
+    }
+
+    private static abstract class AbstractTransactionalExecutor implements TransactionalExecutor {
+
+        @Override
+        public int timeout() {
+            return 30000;
+        }
 
+        @Override
+        public String name() {
+            return "test";
+        }
     }
 }