├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── pom.xml └── src ├── docs └── docbook │ ├── en │ ├── cobar-client-background.dbx │ ├── cobar-client-in-future.dbx │ ├── cobar-client-initial-requirements.dbx │ ├── cobar-client-migration-guide.dbx │ ├── cobar-client-reference.dbx │ ├── cobar-client-strategies-leverage.dbx │ ├── css │ │ └── cc.css │ ├── images │ │ └── cobarClientArch.png │ └── index.dbx │ └── zh │ ├── cobar-client-background.dbx │ ├── cobar-client-in-future.dbx │ ├── cobar-client-initial-requirements.dbx │ ├── cobar-client-migration-guide.dbx │ ├── cobar-client-reference.dbx │ ├── cobar-client-strategies-leverage.dbx │ ├── css │ └── cc.css │ ├── images │ └── cobarClientArch.png │ └── index.dbx ├── main ├── assembly │ └── dist.xml ├── java │ └── com │ │ └── alibaba │ │ └── cobar │ │ └── client │ │ ├── CobarSqlMapClientDaoSupport.java │ │ ├── CobarSqlMapClientTemplate.java │ │ ├── audit │ │ ├── ConcurrentSqlAuditor.java │ │ ├── ISqlAuditor.java │ │ └── SimpleSqlAuditor.java │ │ ├── datasources │ │ ├── CobarDataSourceDescriptor.java │ │ ├── DefaultCobarDataSourceService.java │ │ ├── ICobarDataSourceService.java │ │ └── ha │ │ │ ├── FailoverHotSwapDataSourceCreator.java │ │ │ ├── FailoverMonitorJob.java │ │ │ ├── IHADataSourceCreator.java │ │ │ ├── NonHADataSourceCreator.java │ │ │ ├── PassiveEventHotSwappableAdvice.java │ │ │ └── support │ │ │ └── IDataSourcePostProcessor.java │ │ ├── exception │ │ └── UncategorizedCobarClientException.java │ │ ├── merger │ │ ├── ConcurrentSortMerger.java │ │ └── IMerger.java │ │ ├── router │ │ ├── CobarClientInternalRouter.java │ │ ├── DefaultCobarClientInternalRouter.java │ │ ├── DroolsBasedCobarRouter.java │ │ ├── ICobarRouter.java │ │ ├── RoutingException.java │ │ ├── aspects │ │ │ └── RoutingResultCacheAspect.java │ │ ├── config │ │ │ ├── AbstractCobarClientInternalRouterFactoryBean.java │ │ │ ├── AbstractCobarInternalRouterConfigurationFactoryBean.java │ │ │ ├── CobarInteralRouterXmlFactoryBean.java │ │ │ ├── CobarInternalRouterDSLFactoryBean.java │ │ │ ├── CobarInternalRouterXlsRuleFactoryBean.java │ │ │ ├── DefaultCobarClientInternalRouterXmlFactoryBean.java │ │ │ ├── StaticCobarClientInternalRouterFactoryBean.java │ │ │ ├── support │ │ │ │ └── InternalRuleLoader4DefaultInternalRouter.java │ │ │ └── vo │ │ │ │ ├── InternalRule.java │ │ │ │ └── InternalRules.java │ │ ├── rules │ │ │ ├── AbstractEntityAttributeRule.java │ │ │ ├── AbstractEntityTypeRule.java │ │ │ ├── IRoutingRule.java │ │ │ └── ibatis │ │ │ │ ├── AbstractIBatisOrientedRule.java │ │ │ │ ├── IBatisNamespaceRule.java │ │ │ │ ├── IBatisNamespaceShardingRule.java │ │ │ │ ├── IBatisSqlActionRule.java │ │ │ │ └── IBatisSqlActionShardingRule.java │ │ └── support │ │ │ ├── IBatisRoutingFact.java │ │ │ └── RoutingResult.java │ │ ├── support │ │ ├── LRUMap.java │ │ ├── execution │ │ │ ├── ConcurrentRequest.java │ │ │ ├── DefaultConcurrentRequestProcessor.java │ │ │ ├── IConcurrentRequestProcessor.java │ │ │ └── RequestDepository.java │ │ ├── utils │ │ │ ├── CollectionUtils.java │ │ │ ├── MapUtils.java │ │ │ └── Predicate.java │ │ └── vo │ │ │ ├── BatchInsertTask.java │ │ │ ├── CobarMRBase.java │ │ │ └── Pair.java │ │ └── transaction │ │ └── MultipleDataSourcesTransactionManager.java └── resources │ └── rules.dtd └── test ├── java ├── META-INF │ ├── ibatis │ │ ├── sqlmap-config.xml │ │ └── sqlmap │ │ │ ├── followers.xml │ │ │ ├── offers.xml │ │ │ └── tweets.xml │ ├── routing │ │ ├── ns-only-rules.xml │ │ ├── ns-sharding-rules.xml │ │ ├── offer-sharding-rules-on-namespace.xml │ │ ├── offer-sql-action-rules.xml │ │ ├── sqlaction-only-rules.xml │ │ └── sqlaction-sharding-rules.xml │ ├── spring │ │ ├── cobar-client-appctx.xml │ │ ├── cobar-client-custom-merger-appctx.xml │ │ ├── cobar-client-offer-services-appctx.xml │ │ ├── datasources-appctx.xml │ │ ├── namespace-router-appctx.xml │ │ ├── namespace-sharding-router-appctx.xml │ │ ├── namespace-sqlaction-composed-router-appctx.xml │ │ ├── sqlaction-router-appctx.xml │ │ └── sqlaction-sharding-router-appctx.xml │ └── sql │ │ ├── cobarha_schema.sql │ │ ├── follower_schema.sql │ │ ├── offer_schema.sql │ │ └── tweets_schema.sql └── com │ └── alibaba │ └── cobar │ └── client │ ├── AbstractTestNGCobarClientTest.java │ ├── CobarSqlMapClientDaoSupportTestWithComposedRuleRouter.java │ ├── CobarSqlMapClientTemplateWithComposedRuleRouterTest.java │ ├── CobarSqlMapClientTemplateWithCustomMergerTest.java │ ├── CobarSqlMapClientTemplateWithNamespaceRouterTest.java │ ├── CobarSqlMapClientTemplateWithNamespaceShardingRouterTest.java │ ├── CobarSqlMapClientTemplateWithSqlActionOnlyRouterTest.java │ ├── CobarSqlMapClientTemplateWithSqlActionShardingRouterTest.java │ ├── CobarTestNGTestsRunner.java │ ├── entities │ ├── Follower.java │ ├── Offer.java │ └── Tweet.java │ ├── merger │ └── ConcurrentSortMergerTest.java │ ├── router │ ├── config │ │ ├── CobarInternalRouterXmlFactoryBeanTest.java │ │ ├── abnormal_rule_fixture1.xml │ │ ├── abnormal_rule_fixture2.xml │ │ ├── abnormal_rule_fixture3.xml │ │ ├── abnormal_rule_fixture4.xml │ │ ├── normal_rule_fixture.xml │ │ ├── normal_rule_fixture2.xml │ │ └── normal_rule_fixture3.xml │ └── rules │ │ ├── IBatisNamespaceRuleTest.java │ │ ├── IBatisNamespaceShardingRuleTest.java │ │ ├── IBatisSqlActionRuleTest.java │ │ ├── IBatisSqlActionShardingRuleTest.java │ │ └── support │ │ ├── IFunction2.java │ │ └── ModFunction.java │ ├── support │ └── OfferComparator.java │ ├── test │ └── services │ │ ├── AbnormalOfferService.java │ │ ├── AbstractOfferService.java │ │ ├── IOfferService.java │ │ └── NormalOfferService.java │ └── transaction │ └── MultipleDataSourcesTransactionManagerTest.java └── resources ├── testng-sequencial-tests.xml └── testng.xml /.gitignore: -------------------------------------------------------------------------------- 1 | lib_managed/ 2 | project/target/* 3 | project/project/target/* 4 | project/build/target/* 5 | project/boot/* 6 | project/plugins/lib_managed/* 7 | project/plugins/project/* 8 | project/plugins/target/* 9 | project/plugins/src_managed/* 10 | target/ 11 | .idea/ 12 | .idea_modules/ 13 | *.iml 14 | .DS_Store 15 | out/ 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk7 4 | - openjdk6 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cobarclient 2 | ============ 3 | 4 | 5 | `mvn install` will package everything for you, including the documentations, the libraries, etc. 6 | 7 | A quick-start can be found at ~~~~(Since the domain "alibabatech" is discarded by alibaba internally, I have moved a copy of [中文版参考文档](http://afoo.me/shortcuts/cobarclient/zh/index.html) and [Reference Guide](http://afoo.me/shortcuts/cobarclient/en/index.html) to my personal blog.) 8 | 9 | you can start with cobar-client by reading the documentation bundled with the distribution, the documentation is very elaborate. 10 | 11 | GL & HF with cobar-client! 12 | 13 | 14 | ## Lisence 15 |
16 | Apache License
17 | Version 2.0, January 2004
18 | http://www.apache.org/licenses/
19 | 
20 | -------------------------------------------------------------------------------- /src/docs/docbook/en/cobar-client-background.dbx: -------------------------------------------------------------------------------- 1 | 2 | 4 | The Background of Why CobarClient Was Launched 5 | 6 | We alibaba have a 7 | Cobar 8 | project already which does help on distributed data access, but in 9 | order to meet the HA and performance requirements, 10 | two or more servers 11 | are needed to make it run. Usually it's not a good choice for small 12 | applications which still need distributed data access abilities. Since 13 | the technology department of ICBU(Alibaba) requires a lightweight but 14 | still powerful solution on distributed data access requirement, 15 | CobarClient(Version) comes into the play. 16 | 17 | 18 | CobarClient is mainly for specific usage scenarios, that's, 19 | distributed data access on small or modest scale database 20 | shardings/partitions. 21 | So before you decide whether to use CobarClient, 22 | leverage your application scenario first. 23 | (For Alibaba Internal, if 24 | CobarClient can't meet 25 | your needs, you can turn 26 | to Cobar instead.) 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/docs/docbook/en/cobar-client-in-future.dbx: -------------------------------------------------------------------------------- 1 | 2 | 4 | CobarClient Possible RoadMaps In The Future 5 | 6 | We hope CobarClient can provide an abstraction layer to hide the 7 | complexity of distributed data access, also minimize the efforts to 8 | access 9 | multiple different data storage services. 10 | 11 | 12 | We also hope to provide a consistent data access layer which can 13 | standardize the data access behaviors of the applications, 14 | and as the 15 | requirements and architecture evolve, more functionalities can be 16 | introduced into this layer, including data replication and 17 | synchronization, data caching, real-time index building, etc. With 18 | this CobarClient, the applications only need to know the concerns they 19 | are real care about, rather to care about what changes, how much 20 | changes, the left things can leave to CobarClient to take care of. 21 | 22 | -------------------------------------------------------------------------------- /src/docs/docbook/en/cobar-client-initial-requirements.dbx: -------------------------------------------------------------------------------- 1 | 2 | 4 | Initial Requirements of CobarClient 5 | 6 | CobarClient must support following functionalities: 7 | 8 | 9 | 10 | data access support with horizontal or vertical partitions. 11 | 12 | 13 | 14 | 15 | support 2-master active HA deployment infrustructure, of 16 | course, the applications still can choose other HA solutions, like 17 | the ones specific to destination databases(e.g. RAC of Oracle). 18 | 19 | 20 | 21 | 22 | Data aggregation support, currently only simple data merge 23 | functionality is 24 | available. 25 | 26 | 27 | 28 | 29 | Local database transaction support(Currently, such requirement is 30 | fulfilled by using 31 | Best Efforts 1PC Pattern 32 | ). 33 | 34 | 35 | 36 | 37 | SQL auditing, analysis, etc. 38 | 39 | 40 | ICBU Internal can use their old 41 | Ark 42 | solution to do such works, but CobarClient still provides 43 | extension point for this. 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/docs/docbook/en/cobar-client-strategies-leverage.dbx: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | Possible Strategies for CobarClient Design and Development 6 | 7 | 8 | The Design and Development of CobarClient can be done from 9 | different aspects, but we choose three solutions for it for the time 10 | being. 11 | 12 | 13 | JDBC API Layer Solution 14 | 15 | The available 16 | Cobar 17 | project do data access routings by parsing and analyzing SQL, so most 18 | of us will think it's easy to do almost same things by wrapping the 19 | JDBC drivers. Of course, it should work, but it takes time, long 20 | time. 21 | 22 | 23 | To do things in this way, we can't just wrap or intercept 24 | several JDBC interfaces to make it run, we need to implement the 25 | whole JDBC specification, and it will take too much time on 26 | development and testing. 27 | 28 | 29 | At first, we just try to intercept serveral methods of 30 | Connection 31 | and 32 | Statement 33 | to get the SQL and then parse it to do left works, but several 34 | headaches come to bother. You will find that several methods' 35 | lifecycle and invocation logic will mismatch with each other, you 36 | will find you have to trace the method invocation sequences, you will 37 | also find you have to take care of all of the database metadata 38 | things. 39 | 40 | 41 | You see, we do can implement a whole JDBC driver to do works like 42 | current 43 | Cobar 44 | does, but it's not an easy thing with limit time frame. 45 | 46 | 47 | 48 | DAL(Data Access Layer) Solution 49 | 50 | We can do the same thing on DAL. Many benefits are avaialble, 51 | including that: 52 | 53 | 54 | we can make a standard development process; 55 | 56 | 57 | we can simplify the implementation of data access routing; 58 | 59 | 60 | 61 | furthermore, if more shards or other storage services(e.g. KV 62 | store) are required, the applications won't need any changes, 63 | 'cause the DAL has hidden these changes for them. 64 | 65 | 66 | 67 | 68 | If we do use such solution on DAL, we can externalize the 69 | sharding strategies and rules, the routing rules can be configured in 70 | a consistent way(Annotation, or external XML configuration files), 71 | and the rules can be defined only as per the type of DO(Data Object) 72 | and their attributes. It's so simple and flexible, the complexity 73 | of 74 | SQL parsing is involved. 75 | 76 | 77 | But such solution impacts too much to the current applications, 78 | so althought it's a good go, we can't make it run for the time being. 79 | 80 | 81 | 82 | The Solution That's Specific To ICBU Applications 83 | 84 | After thinking on multiple factors like the time frame limitation, 85 | the compatibility to available applications, etc, we give out a 86 | solution that stands between 87 | 88 | and 89 | 90 | . 91 | 92 | 93 | We internally use iBatis to do data access, in order to 94 | accelerate the development process, we use SqlMapClientTemplate of 95 | spring framework, too. To make less impacts on current applications, 96 | we have to extend the SqlMapClientTemplate class, because all of the 97 | data access requests will be sent out by this class, and 98 | if we add 99 | routing support in it, then it can route different data 100 | access 101 | requests to their specific data shards as per the routing 102 | rules we 103 | provide. 104 | 105 | 106 | In fact, this is indeed the solution we choose to use in the 1st 107 | version 108 | of CobarClient. 109 | 110 | 111 | -------------------------------------------------------------------------------- /src/docs/docbook/en/css/cc.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin-top: 1em; 3 | margin-bottom: 1em; 4 | margin-left: 10%; 5 | margin-right: 10%; 6 | font-size: 12pt; 7 | font-family: arial, sans-serif; 8 | } 9 | 10 | pre.programlisting { 11 | font-size: 9pt; 12 | padding: 5pt 2pt; 13 | border: 1pt solid black; 14 | background: #eeeeee; 15 | } 16 | 17 | div.note, div.important, div.example, div.informalexample, div.tip, div.warning, div.caution { 18 | margin: 1em; 19 | padding: 0.5em; 20 | border: 1px solid gray; 21 | background-color: #f8f8e0; 22 | } 23 | 24 | div.important th, div.note th, div.tip th { 25 | text-align: left; 26 | border-bottom: solid 1px gray; 27 | font-size: 12px; 28 | } -------------------------------------------------------------------------------- /src/docs/docbook/en/images/cobarClientArch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/cobarclient/46396017857e213c537b0fc88cae7e8ea3a798db/src/docs/docbook/en/images/cobarClientArch.png -------------------------------------------------------------------------------- /src/docs/docbook/en/index.dbx: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | Cobar Client Documentation 6 | 7 | 8 | 王福强(darren.wangfq@alibaba-inc.com) 9 | 10 | 11 | 12 | 13 | 14 | This document describes all of the information of Cobar 15 | Client 16 | product. 17 | 18 | 19 | 20 | 21 | Cobar Client 22 | Distributed Data Access Layer 23 | Spring, IBatis 24 | 25 | 26 | 27 | 28 | 29 | 30 | Migrate To Cobar Client 31 | 32 | 33 | 34 | Cobar Client Bible 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/docs/docbook/zh/cobar-client-background.dbx: -------------------------------------------------------------------------------- 1 | 2 | 3 | CobarClient发起的背景 4 | 5 | 现有的Cobar方案需要单独的服务器来运行, 为了保证性能和可用性, 通常最少需要两台独立服务器.国际站应用方出于扩展和可用性等因素考虑, 6 | 希望一种不依赖于独立服务器的Cobar解决方案, 鉴于此, 决定开发Cobar的Client版本, 该版本主要面向小规模的数据库sharding集群访问, 7 | 因现有的Cobar已经在中文站等多个项目中成功应用并实施, 如果CobarClient无法满足进一步的需求,可以转而使用现有的Cobar方案. 8 | 9 | 10 | 所以, CobarClient的使用原则上只限定于某些特定场景. 11 | 12 | -------------------------------------------------------------------------------- /src/docs/docbook/zh/cobar-client-in-future.dbx: -------------------------------------------------------------------------------- 1 | 2 | 3 | CobarClient展望 4 | 5 | 希望CobarClient从更抽象的层次来屏蔽分布式数据以及不同数据存储服务之间的差异性, 所以, 我们希望提供一个统一的数据访问层(DAL), 由该DAL来规范和统一数据访问行为,同时屏蔽分布式场景下的数据访问的复杂度. 6 | 另外, 随着需求的变更以及架构的演化,可以将数据的复制和同步, 缓存的接入, 实时的索引构建等等, 都可以通过我们的DAL层进行, 对于应用方来说, 他们只需要关注应用端的关注点, 而不需要关注DAL之后发生了什么,变更了什么,增加和减少了什么... 7 | 8 | -------------------------------------------------------------------------------- /src/docs/docbook/zh/cobar-client-initial-requirements.dbx: -------------------------------------------------------------------------------- 1 | 2 | 3 | CobarClient最初需求 4 | 5 | CobarClient需要满足以下需求: 6 | 7 | 8 | 9 | 可以支持垂直和水平数据切分数据库集群的访问; 10 | 11 | 12 | 13 | 14 | 支持双机热备的HA解决方案, 应用方可以根据情况选用数据库特定的HA解决方案(比如Oracle的RAC),或者选用CobarClient提供的HA解决方案. 15 | 16 | 17 | 18 | 19 | 小数据量的数据集计(Aggregation), 暂时只支持简单的数据合并. 20 | 21 | 22 | 23 | 24 | 数据库本地事务的支持, 目前采用Best Efforts 1PC模式的事务管理. 25 | 26 | 27 | 28 | 29 | 数据访问操作相关SQL的记录, 分析等.(可以采用国际站现有Ark解决方案,但CobarClient提供扩展的切入接口) 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/docs/docbook/zh/cobar-client-strategies-leverage.dbx: -------------------------------------------------------------------------------- 1 | 2 | 3 | CobarClient方案之间的权衡 4 | 5 | CobarClient的实现方案可以从多个角度进行考虑, 我们暂且选择三种方案进行推演. 6 | 7 | 8 | JDBC API层次的解决方案 9 | 10 | 因为现有的Cobar解决方案通过SQL解析来实现了shards间的路由功能, 所以, 自然而然的, 大家会马上联想到在JDBC Driver层次进行同样的封装,然后也是通过SQL解析的方式来实现路由功能. 11 | 首先这种方案是可以实现的, 但工期也绝对不会像想象的那么短. 12 | 13 | 14 | 要走这条路, 我们不可能通过封装或者拦截几个JDBC接口就很容易的搞定, 我们需要实现一整套的JDBC规范,这无论从开发还是测试方面考虑,投入的时间都会很多. 15 | 16 | 17 | 最初我们尝试只拦截Connection, Statement的相关方法来获取SQL并进行解析等工作,但发现相关方法调用的lifecycle的不匹配问题, 方法调用的trace问题, 数据库metadata等都会造成实现过程中的尴尬和难行. 18 | 19 | 20 | 但不管怎么样, 完全的实现一套JDBC规范的API,原则上来说可以实现类似于现有Cobar解决方案类似的方案. 21 | 22 | 23 | 24 | DAL层次的解决方案 25 | 26 | 要实现数据方案的路由功能, 我们也可以在数据访问层做文章. 从DAL层做文章的好处在于, 我们可以规范开发流程, 简化路由功能的实现, 而且, 不管将来增加更多的shards或者其它异构的存储, 比如KV store, 27 | DAL层都可以屏蔽这些变化, 使得应用程序不受任何影响. 28 | 29 | 30 | 如果采用DAL层的解决方案, 我们可以将sharding策略和规则外部化, 通过统一的配置(Annotation也好, 外部XML之类配置文件也好)来定义路由规则, 路由规则可以根据DO的类型以及相关属性进行定义, 31 | 定义简单又不失灵活性, 完全不用引入SQL解析之类的复杂性. 32 | 33 | 34 | 但基于DAL层次的解决方案对现有网站的应用来说, 冲击性太大,所以, 这虽然是个方向,但短期内无法有效施行. 35 | 36 | 37 | 38 | 特定国际站场景的解决方案 39 | 40 | 考虑到工期以及兼容性等因素, 我们可以考虑介于之间的一种解决方案. 41 | 42 | 43 | B2B内部数据访问全部采用iBatis进行, 为了提高开发效率,自然也采用了Spring提供的SqlMapClientTemplate进行数据访问逻辑的开发. 要较少的侵入现有应用, 44 | 我们可以考虑对SqlMapClientTemplate做手脚, 既然所有的数据访问都通过该类走,那么就在该类中插入路由逻辑, 根据数据访问请求的属性指定路由规则, 然后将符合路由规则的数据访问请求路由到相应的shard上去. 45 | 46 | 47 | 这实际上就是我们现在第一阶段采用的解决方案. 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/docs/docbook/zh/css/cc.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin-top: 1em; 3 | margin-bottom: 1em; 4 | margin-left: 10%; 5 | margin-right: 10%; 6 | font-size: 12pt; 7 | font-family: arial, sans-serif; 8 | } 9 | 10 | pre.programlisting { 11 | font-size: 9pt; 12 | padding: 5pt 2pt; 13 | border: 1pt solid black; 14 | background: #eeeeee; 15 | } 16 | 17 | div.note, div.important, div.example, div.informalexample, div.tip, div.warning, div.caution { 18 | margin: 1em; 19 | padding: 0.5em; 20 | border: 1px solid gray; 21 | background-color: #f8f8e0; 22 | } 23 | 24 | div.important th, div.note th, div.tip th { 25 | text-align: left; 26 | border-bottom: solid 1px gray; 27 | font-size: 12px; 28 | } -------------------------------------------------------------------------------- /src/docs/docbook/zh/images/cobarClientArch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/cobarclient/46396017857e213c537b0fc88cae7e8ea3a798db/src/docs/docbook/zh/images/cobarClientArch.png -------------------------------------------------------------------------------- /src/docs/docbook/zh/index.dbx: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | Cobar Client 文档全集 6 | 7 | 8 | 王福强(darren.wangfq@alibaba-inc.com) 9 | 10 | 11 | 12 | 13 | 14 | 该文档描述了CobarClient产品的方方面面... 15 | 16 | 17 | 18 | 19 | Cobar Client 20 | 分布式数据访问层 21 | Spring, IBatis 22 | 23 | 24 | 25 | 26 | 27 | 向Cobar Client迁移 28 | 29 | 30 | 31 | Cobar Client百科大全 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/main/assembly/dist.xml: -------------------------------------------------------------------------------- 1 | 5 | dist 6 | 7 | zip 8 | tar.gz 9 | 10 | 11 | 12 | . 13 | / 14 | 15 | README* 16 | 17 | 18 | 19 | target/docs 20 | /docs 21 | 22 | **/* 23 | 24 | 25 | 26 | 27 | 28 | /lib 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/CobarSqlMapClientDaoSupport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client; 17 | 18 | import java.sql.SQLException; 19 | import java.util.Collection; 20 | 21 | import org.springframework.dao.DataAccessException; 22 | import org.springframework.orm.ibatis.SqlMapClientCallback; 23 | import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport; 24 | 25 | import com.ibatis.sqlmap.client.SqlMapExecutor; 26 | 27 | /** 28 | * A DAO base class definition which adds more helper methods on batch 29 | * operations.
30 | * Users can configure their DAO implementations with same configuration items 31 | * of {@link CobarSqlMapClientTemplate}.
32 | *
33 | * Feature requested by Yao Ming. 34 | * 35 | * @author fujohnwang 36 | * @since 1.0 37 | */ 38 | public class CobarSqlMapClientDaoSupport extends SqlMapClientDaoSupport { 39 | 40 | public int batchInsert(final String statementName, final Collection entities) 41 | throws DataAccessException { 42 | if (isPartitionBehaviorEnabled()) { 43 | int counter = 0; 44 | DataAccessException lastEx = null; 45 | for (Object parameterObject : entities) { 46 | try { 47 | getSqlMapClientTemplate().insert(statementName, parameterObject); 48 | counter++; 49 | } catch (DataAccessException e) { 50 | lastEx = e; 51 | } 52 | } 53 | if (lastEx != null) { 54 | throw lastEx; 55 | } 56 | return counter; 57 | } else { 58 | return (Integer) getSqlMapClientTemplate().execute(new SqlMapClientCallback() { 59 | public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException { 60 | executor.startBatch(); 61 | for (Object item : entities) { 62 | executor.insert(statementName, item); 63 | } 64 | return executor.executeBatch(); 65 | } 66 | }); 67 | } 68 | } 69 | 70 | public int batchDelete(final String statementName, final Collection entities) 71 | throws DataAccessException { 72 | if (isPartitionBehaviorEnabled()) { 73 | int counter = 0; 74 | DataAccessException lastEx = null; 75 | for (Object entity : entities) { 76 | try { 77 | counter += getSqlMapClientTemplate().delete(statementName, entity); 78 | } catch (DataAccessException e) { 79 | lastEx = e; 80 | } 81 | } 82 | if (lastEx != null) { 83 | throw lastEx; 84 | } 85 | return counter; 86 | } else { 87 | return (Integer) getSqlMapClientTemplate().execute(new SqlMapClientCallback() { 88 | public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException { 89 | executor.startBatch(); 90 | for (Object parameterObject : entities) { 91 | executor.delete(statementName, parameterObject); 92 | } 93 | return executor.executeBatch(); 94 | } 95 | }); 96 | } 97 | } 98 | 99 | public int batchUpdate(final String statementName, final Collection entities) 100 | throws DataAccessException { 101 | if (isPartitionBehaviorEnabled()) { 102 | int counter = 0; 103 | DataAccessException lastEx = null; 104 | for (Object parameterObject : entities) { 105 | try { 106 | counter += getSqlMapClientTemplate().update(statementName, parameterObject); 107 | } catch (DataAccessException e) { 108 | lastEx = e; 109 | } 110 | } 111 | if (lastEx != null) { 112 | throw lastEx; 113 | } 114 | return counter; 115 | } else { 116 | return (Integer) getSqlMapClientTemplate().execute(new SqlMapClientCallback() { 117 | 118 | public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException { 119 | executor.startBatch(); 120 | for (Object parameterObject : entities) { 121 | executor.update(statementName, parameterObject); 122 | } 123 | return executor.executeBatch(); 124 | } 125 | }); 126 | } 127 | } 128 | 129 | protected boolean isPartitionBehaviorEnabled() { 130 | if (getSqlMapClientTemplate() instanceof CobarSqlMapClientTemplate) { 131 | return ((CobarSqlMapClientTemplate) getSqlMapClientTemplate()) 132 | .isPartitioningBehaviorEnabled(); 133 | } 134 | return false; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/audit/ConcurrentSqlAuditor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.audit; 17 | 18 | import java.util.concurrent.ConcurrentHashMap; 19 | import java.util.concurrent.ConcurrentMap; 20 | import java.util.concurrent.ExecutorService; 21 | 22 | public class ConcurrentSqlAuditor implements ISqlAuditor { 23 | private ExecutorService executorService; 24 | 25 | /** 26 | * simple map-reduce results holder 27 | * it's not the final abstraction yet, may be refactored later. 28 | */ 29 | private ConcurrentMap statementStatistics = new ConcurrentHashMap(); 30 | 31 | public void audit(String id, String sql, Object sqlContext) { 32 | // TODO 33 | // implement application-specific profiling logic here. 34 | } 35 | 36 | public void setExecutorService(ExecutorService executorService) { 37 | this.executorService = executorService; 38 | } 39 | 40 | public ExecutorService getExecutorService() { 41 | return executorService; 42 | } 43 | 44 | public void setStatementStatistics(ConcurrentMap statementStatistics) { 45 | this.statementStatistics = statementStatistics; 46 | } 47 | 48 | public ConcurrentMap getStatementStatistics() { 49 | return statementStatistics; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/audit/ISqlAuditor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.audit; 17 | 18 | /** 19 | * group by the SQL statement when auditing them.
20 | * 21 | * the group-by SQL will be published to audit server or be fetched by audit server in a periodic way.
22 | * 23 | * simple handling is OK, but you can escalate to a more scalable solution like store SQL statement into NoSQL storage 24 | * and do analysis later with powerful computing cluster. 25 | 26 | * @author fujohnwang 27 | * @since 1.0 28 | */ 29 | public interface ISqlAuditor { 30 | void audit(String id, String sql, Object sqlContext); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/audit/SimpleSqlAuditor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.audit; 17 | 18 | import org.slf4j.Logger; 19 | import org.slf4j.LoggerFactory; 20 | 21 | /** 22 | * A simple {@link ISqlAuditor} implementation that will just simple print the 23 | * SQL and its parameter.
24 | * 25 | * @author fujohnwang 26 | */ 27 | public class SimpleSqlAuditor implements ISqlAuditor { 28 | 29 | private transient final Logger logger = LoggerFactory.getLogger(SimpleSqlAuditor.class); 30 | 31 | public void audit(String id, String sql, Object sqlContext) { 32 | logger.info("SQL id:{} SQL:{} - Parameter:{}", new Object[] { id, sql, sqlContext }); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/datasources/CobarDataSourceDescriptor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.datasources; 17 | 18 | import javax.sql.DataSource; 19 | 20 | /** 21 | * {@link CobarDataSourceDescriptor} describe a data base deployment structure 22 | * with 2 databases as HA group.
23 | * it looks like:
24 | * 25 | *
 26 |  *                  Client
 27 |  *                    /\
 28 |  *                  /    \
 29 |  *         Active DB <-> Standby DB
 30 |  * 
{@link #targetDataSource} should be the reference to the current active 31 | * database, while {@link #standbyDataSource} should be the standby database.
32 | * for both {@link #targetDataSource} and {@link #standbyDataSource}, each one 33 | * should have a sibling data source that connect to the same target database.
34 | * as to the reason why do so, that's : 35 | *
    36 | *
  1. these sibling DataSources will be used when do 37 | * database-status-detecting.(if we fetch connection from target data source, 38 | * when it's full, the deteting behavior can't be performed.)
  2. 39 | *
  3. if the {@link #targetDataSource} and {@link #standbyDataSource} are 40 | * DataSource implementations configured in local application container, we can 41 | * fetch necessary information via reflection to create connection to target 42 | * database independently, but if they are fetched from JNDI, we can't, so 43 | * explicitly declaring sibling data sources is necessary in this situation.
  4. 44 | *
45 | * 46 | * @author fujohnwang 47 | * @since 1.0 48 | */ 49 | public class CobarDataSourceDescriptor { 50 | /** 51 | * the identity of to-be-exposed DataSource. 52 | */ 53 | private String identity; 54 | /** 55 | * active data source 56 | */ 57 | private DataSource targetDataSource; 58 | /** 59 | * detecting data source for active data source 60 | */ 61 | private DataSource targetDetectorDataSource; 62 | /** 63 | * standby data source 64 | */ 65 | private DataSource standbyDataSource; 66 | /** 67 | * detecting datasource for standby data source 68 | */ 69 | private DataSource standbyDetectorDataSource; 70 | 71 | /** 72 | * we will initialize proper thread pools which stand in front of data 73 | * sources as per connection pool size.
74 | * usually, they will have same number of objects.
75 | * you have to set a proper size for this attribute as per your data source 76 | * attributes. In case you forget it, we set a default value with 77 | * "number of CPU" * 5. 78 | */ 79 | private int poolSize = Runtime.getRuntime().availableProcessors() * 5; 80 | 81 | public String getIdentity() { 82 | return identity; 83 | } 84 | 85 | public void setIdentity(String identity) { 86 | this.identity = identity; 87 | } 88 | 89 | public DataSource getTargetDataSource() { 90 | return targetDataSource; 91 | } 92 | 93 | public void setTargetDataSource(DataSource targetDataSource) { 94 | this.targetDataSource = targetDataSource; 95 | } 96 | 97 | public DataSource getTargetDetectorDataSource() { 98 | return targetDetectorDataSource; 99 | } 100 | 101 | public void setTargetDetectorDataSource(DataSource targetDetectorDataSource) { 102 | this.targetDetectorDataSource = targetDetectorDataSource; 103 | } 104 | 105 | public DataSource getStandbyDataSource() { 106 | return standbyDataSource; 107 | } 108 | 109 | public void setStandbyDataSource(DataSource standbyDataSource) { 110 | this.standbyDataSource = standbyDataSource; 111 | } 112 | 113 | public DataSource getStandbyDetectorDataSource() { 114 | return standbyDetectorDataSource; 115 | } 116 | 117 | public void setStandbyDetectorDataSource(DataSource standbyDetectorDataSource) { 118 | this.standbyDetectorDataSource = standbyDetectorDataSource; 119 | } 120 | 121 | public void setPoolSize(int poolSize) { 122 | this.poolSize = poolSize; 123 | } 124 | 125 | public int getPoolSize() { 126 | return poolSize; 127 | } 128 | 129 | @Override 130 | public int hashCode() { 131 | final int prime = 31; 132 | int result = 1; 133 | result = prime * result + ((identity == null) ? 0 : identity.hashCode()); 134 | return result; 135 | } 136 | 137 | @Override 138 | public boolean equals(Object obj) { 139 | if (this == obj) 140 | return true; 141 | if (obj == null) 142 | return false; 143 | if (getClass() != obj.getClass()) 144 | return false; 145 | CobarDataSourceDescriptor other = (CobarDataSourceDescriptor) obj; 146 | if (identity == null) { 147 | if (other.identity != null) 148 | return false; 149 | } else if (!identity.equals(other.identity)) 150 | return false; 151 | return true; 152 | } 153 | 154 | @Override 155 | public String toString() { 156 | return "CobarDataSourceDescriptor [identity=" + identity + ", poolSize=" + poolSize 157 | + ", standbyDataSource=" + standbyDataSource + ", standbyDetectorDataSource=" 158 | + standbyDetectorDataSource + ", targetDataSource=" + targetDataSource 159 | + ", targetDetectorDataSource=" + targetDetectorDataSource + "]"; 160 | } 161 | 162 | 163 | } 164 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/datasources/DefaultCobarDataSourceService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.datasources; 17 | 18 | import java.util.ArrayList; 19 | import java.util.HashMap; 20 | import java.util.HashSet; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.Set; 24 | 25 | import javax.sql.DataSource; 26 | 27 | import org.apache.commons.lang.Validate; 28 | import org.springframework.beans.factory.InitializingBean; 29 | import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy; 30 | 31 | import com.alibaba.cobar.client.datasources.ha.IHADataSourceCreator; 32 | import com.alibaba.cobar.client.datasources.ha.NonHADataSourceCreator; 33 | import com.alibaba.cobar.client.datasources.ha.support.IDataSourcePostProcessor; 34 | import com.alibaba.cobar.client.support.utils.CollectionUtils; 35 | 36 | /** 37 | * StrongRefDataSourceLocator is mainly responsible for assembling data sources 38 | * mapping relationship as per data source definitions in spring container. 39 | * 40 | * @author fujohnwang 41 | */ 42 | public class DefaultCobarDataSourceService implements ICobarDataSourceService, InitializingBean { 43 | private Set dataSourceDescriptors = new HashSet(); 44 | private List dataSourcePostProcessor = new ArrayList(); 45 | private IHADataSourceCreator haDataSourceCreator; 46 | private Map dataSources = new HashMap(); 47 | 48 | public Map getDataSources() { 49 | return dataSources; 50 | } 51 | 52 | public void afterPropertiesSet() throws Exception { 53 | if (getHaDataSourceCreator() == null) { 54 | setHaDataSourceCreator(new NonHADataSourceCreator()); 55 | } 56 | if (CollectionUtils.isEmpty(dataSourceDescriptors)) { 57 | return; 58 | } 59 | 60 | for (CobarDataSourceDescriptor descriptor : getDataSourceDescriptors()) { 61 | Validate.notEmpty(descriptor.getIdentity()); 62 | Validate.notNull(descriptor.getTargetDataSource()); 63 | 64 | DataSource dataSourceToUse = descriptor.getTargetDataSource(); 65 | 66 | if (descriptor.getStandbyDataSource() != null) { 67 | dataSourceToUse = getHaDataSourceCreator().createHADataSource(descriptor); 68 | if (CollectionUtils.isNotEmpty(dataSourcePostProcessor)) { 69 | for (IDataSourcePostProcessor pp : dataSourcePostProcessor) { 70 | dataSourceToUse = pp.postProcess(dataSourceToUse); 71 | } 72 | } 73 | } 74 | 75 | dataSources.put(descriptor.getIdentity(), new LazyConnectionDataSourceProxy( 76 | dataSourceToUse)); 77 | } 78 | } 79 | 80 | public void setDataSourceDescriptors(Set dataSourceDescriptors) { 81 | this.dataSourceDescriptors = dataSourceDescriptors; 82 | } 83 | 84 | public Set getDataSourceDescriptors() { 85 | return dataSourceDescriptors; 86 | } 87 | 88 | public void setHaDataSourceCreator(IHADataSourceCreator haDataSourceCreator) { 89 | this.haDataSourceCreator = haDataSourceCreator; 90 | } 91 | 92 | public IHADataSourceCreator getHaDataSourceCreator() { 93 | return haDataSourceCreator; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/datasources/ICobarDataSourceService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.datasources; 17 | 18 | import java.util.Map; 19 | import java.util.Set; 20 | 21 | import javax.sql.DataSource; 22 | 23 | import com.alibaba.cobar.client.CobarSqlMapClientTemplate; 24 | import com.alibaba.cobar.client.transaction.MultipleDataSourcesTransactionManager; 25 | /** 26 | * A ICobarDataSourceLocator is responsible for constructing a mapping of data sources and their identities 27 | * so that {@link MultipleDataSourcesTransactionManager} and {@link CobarSqlMapClientTemplate} can get a collection of data source dependencies in a consistent way. 28 | *
29 | * The implementations of this interface can assemble such a mapping relationship as per data source references in a spring container, 30 | * or read data source service configuration information from some location and then assemble data sources for usage later. 31 | * 32 | * @author fujohnwang 33 | * @since 1.0 34 | */ 35 | public interface ICobarDataSourceService { 36 | Map getDataSources(); 37 | Set getDataSourceDescriptors(); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/datasources/ha/IHADataSourceCreator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.datasources.ha; 17 | 18 | import javax.sql.DataSource; 19 | 20 | import com.alibaba.cobar.client.datasources.CobarDataSourceDescriptor; 21 | 22 | public interface IHADataSourceCreator { 23 | DataSource createHADataSource(CobarDataSourceDescriptor descriptor) throws Exception; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/datasources/ha/NonHADataSourceCreator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.datasources.ha; 17 | 18 | import javax.sql.DataSource; 19 | 20 | import com.alibaba.cobar.client.datasources.CobarDataSourceDescriptor; 21 | 22 | public class NonHADataSourceCreator implements IHADataSourceCreator { 23 | 24 | public DataSource createHADataSource(CobarDataSourceDescriptor descriptor) throws Exception { 25 | return descriptor.getTargetDataSource(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/datasources/ha/support/IDataSourcePostProcessor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.datasources.ha.support; 17 | 18 | import javax.sql.DataSource; 19 | 20 | import com.alibaba.cobar.client.datasources.DefaultCobarDataSourceService; 21 | 22 | /** 23 | * A Callback Interface that can be used to hook in custom cross-cutting concerns for your DataSource.
24 | * currently, there is no need to use it yet. 25 | * 26 | * @author fujohnwang 27 | * @see DefaultCobarDataSourceService 28 | */ 29 | public interface IDataSourcePostProcessor { 30 | DataSource postProcess(DataSource dataSource); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/exception/UncategorizedCobarClientException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.exception; 17 | 18 | import org.springframework.dao.UncategorizedDataAccessException; 19 | 20 | public class UncategorizedCobarClientException extends UncategorizedDataAccessException { 21 | private static final long serialVersionUID = -5001927974502714777L; 22 | 23 | public UncategorizedCobarClientException(String msg, Throwable cause) { 24 | super(msg, cause); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/merger/ConcurrentSortMerger.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.merger; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Comparator; 20 | import java.util.List; 21 | import java.util.concurrent.Callable; 22 | import java.util.concurrent.ExecutionException; 23 | import java.util.concurrent.ExecutorService; 24 | import java.util.concurrent.Executors; 25 | import java.util.concurrent.Future; 26 | 27 | import org.springframework.beans.factory.DisposableBean; 28 | import org.springframework.beans.factory.InitializingBean; 29 | 30 | import com.alibaba.cobar.client.support.utils.CollectionUtils; 31 | 32 | /** 33 | * This merger implementation is mainly for situations that the original 34 | * sub-result lists are all in order.
35 | * In this situation, we only need to do the 2nd part of merge-sort algorithm to 36 | * sort all of the sub-result lists.
37 | * 38 | * @author fujohnwang 39 | * @since 1.0 40 | * @param 41 | */ 42 | public class ConcurrentSortMerger implements IMerger, List>, InitializingBean, 43 | DisposableBean { 44 | 45 | private boolean usingDefaultExecutor = false; 46 | 47 | private ExecutorService executor; 48 | private Comparator comparator; 49 | 50 | public List merge(List> entities) { 51 | List resultList = new ArrayList(); 52 | if (CollectionUtils.isNotEmpty(entities)) { 53 | if (entities.size() == 1) { 54 | resultList.addAll(entities.get(0)); 55 | } else { 56 | List> partialResult = new ArrayList>(); 57 | int pairs = entities.size() / 2; 58 | List>> futures = new ArrayList>>(); 59 | 60 | for (int i = 0; i < pairs; i++) { 61 | final List llst = entities.get(i * 2); 62 | final List rlst = entities.get(i * 2 + 1); 63 | futures.add(getExecutor().submit(new Callable>() { 64 | public List call() throws Exception { 65 | return partialSortMerge(llst, rlst); 66 | } 67 | })); 68 | } 69 | 70 | for (Future> f : futures) { 71 | try { 72 | partialResult.add(f.get()); 73 | } catch (InterruptedException e) { 74 | e.printStackTrace(); 75 | } catch (ExecutionException e) { 76 | e.printStackTrace(); 77 | } 78 | } 79 | 80 | if (entities.size() % 2 == 1) { 81 | partialResult.add(entities.get(pairs * 2)); 82 | } 83 | 84 | resultList.addAll(merge(partialResult)); 85 | } 86 | } 87 | return resultList; 88 | } 89 | 90 | protected List partialSortMerge(List llst, List rlst) { 91 | List resultList = new ArrayList(); 92 | int li = 0, ri = 0; 93 | while (li < llst.size() && ri < rlst.size()) { 94 | E le = llst.get(li); 95 | E re = rlst.get(ri); 96 | if (getComparator().compare(le, re) <= 0) { 97 | resultList.add(le); 98 | li++; 99 | } else { 100 | resultList.add(re); 101 | ri++; 102 | } 103 | } 104 | 105 | if (li < llst.size()) { 106 | resultList.addAll(llst.subList(li, llst.size())); 107 | } 108 | if (ri < rlst.size()) { 109 | resultList.addAll(rlst.subList(ri, rlst.size())); 110 | } 111 | return resultList; 112 | } 113 | 114 | public void setExecutor(ExecutorService executor) { 115 | this.executor = executor; 116 | } 117 | 118 | public ExecutorService getExecutor() { 119 | return executor; 120 | } 121 | 122 | public void afterPropertiesSet() throws Exception { 123 | if (getComparator() == null) { 124 | throw new IllegalArgumentException( 125 | "you must provide a comparator for us to compare the element for merge."); 126 | } 127 | if (getExecutor() == null) { 128 | setExecutor(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())); 129 | usingDefaultExecutor = true; 130 | } 131 | } 132 | 133 | public void destroy() throws Exception { 134 | if (usingDefaultExecutor) { 135 | getExecutor().shutdown(); 136 | } 137 | } 138 | 139 | public void setComparator(Comparator comparator) { 140 | this.comparator = comparator; 141 | } 142 | 143 | public Comparator getComparator() { 144 | return comparator; 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/merger/IMerger.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.merger; 17 | 18 | import java.util.List; 19 | 20 | public interface IMerger { 21 | R merge(List entities); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/CobarClientInternalRouter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.Set; 21 | 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import com.alibaba.cobar.client.router.rules.IRoutingRule; 26 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 27 | import com.alibaba.cobar.client.router.support.RoutingResult; 28 | import com.alibaba.cobar.client.support.LRUMap; 29 | import com.alibaba.cobar.client.support.utils.CollectionUtils; 30 | 31 | /** 32 | * CobarInternalRouter is the default router that will be used in cobar client, 33 | * but it will not be the only one.
34 | * if it can't meet the needs, we can provide other {@link ICobarRouter} like a 35 | * one that use rule engines.
36 | * for now, CobarInternalRouter will hold 4 set of routing rules: 37 | *
    38 | *
  1. sqlActionShardingRules 39 | *
  2. 40 | *
  3. sqlActionRules 41 | *
  4. 42 | *
  5. namespaceShardingRules 43 | *
  6. 44 | *
  7. namespaceRules 45 | *
  8. 46 | *
47 | * rules start with "sqlAction" are rules that will exactly match against the 48 | * sql-map action id in the routing fact, while rules start with "namesapce" 49 | * just match against the "namespace" part in the sql action id; we will match 50 | * these rules in sequence against the routing fact, each later rule will be 51 | * used as fall-back rule if former match fails.
52 | * To enhance the rule matching performance, we add a LRU cache, you can decide 53 | * whether to use this cache by set the {@link #enableCache} property's value to 54 | * true or false.
55 | * 56 | * @author fujohnwang 57 | * @since 1.0 58 | */ 59 | public class CobarClientInternalRouter implements ICobarRouter { 60 | 61 | private transient final Logger logger = LoggerFactory.getLogger(CobarClientInternalRouter.class); 62 | 63 | private LRUMap localCache; 64 | private boolean enableCache = false; 65 | 66 | public CobarClientInternalRouter(boolean enableCache) { 67 | this(enableCache, 10000); 68 | } 69 | 70 | public CobarClientInternalRouter(int cacheSize) { 71 | this(true, cacheSize); 72 | } 73 | 74 | public CobarClientInternalRouter(boolean enableCache, int cacheSize) { 75 | this.enableCache = enableCache; 76 | if (this.enableCache) { 77 | localCache = new LRUMap(cacheSize); 78 | } 79 | } 80 | 81 | private List>>> ruleSequences = new ArrayList>>>(); 82 | 83 | public RoutingResult doRoute(IBatisRoutingFact routingFact) throws RoutingException { 84 | if (enableCache) { 85 | synchronized (localCache) { 86 | if (localCache.containsKey(routingFact)) { 87 | RoutingResult result = (RoutingResult) localCache.get(routingFact); 88 | logger.info("return routing result:{} from cache for fact:{}", result, routingFact); 89 | return result; 90 | } 91 | } 92 | } 93 | 94 | RoutingResult result = new RoutingResult(); 95 | result.setResourceIdentities(new ArrayList()); 96 | 97 | IRoutingRule> ruleToUse = null; 98 | if (!CollectionUtils.isEmpty(getRuleSequences())) { 99 | for (Set>> ruleSet : getRuleSequences()) { 100 | ruleToUse = searchMatchedRuleAgainst(ruleSet, routingFact); 101 | if (ruleToUse != null) { 102 | break; 103 | } 104 | } 105 | } 106 | 107 | if (ruleToUse != null) { 108 | logger.info("matched with rule:{} with fact:{}", ruleToUse, routingFact); 109 | result.getResourceIdentities().addAll(ruleToUse.action()); 110 | } else { 111 | logger.info("No matched rule found for routing fact:{}", routingFact); 112 | } 113 | 114 | if (enableCache) { 115 | synchronized (localCache) { 116 | localCache.put(routingFact, result); 117 | } 118 | } 119 | 120 | return result; 121 | } 122 | 123 | private IRoutingRule> searchMatchedRuleAgainst( 124 | Set>> rules, 125 | IBatisRoutingFact routingFact) { 126 | if (CollectionUtils.isEmpty(rules)) { 127 | return null; 128 | } 129 | for (IRoutingRule> rule : rules) { 130 | if (rule.isDefinedAt(routingFact)) { 131 | return rule; 132 | } 133 | } 134 | return null; 135 | } 136 | 137 | public LRUMap getLocalCache() { 138 | return localCache; 139 | } 140 | 141 | public synchronized void clearLocalCache(){ 142 | this.localCache.clear(); 143 | } 144 | 145 | public boolean isEnableCache() { 146 | return enableCache; 147 | } 148 | 149 | public void setRuleSequences(List>>> ruleSequences) { 150 | this.ruleSequences = ruleSequences; 151 | } 152 | 153 | public List>>> getRuleSequences() { 154 | return ruleSequences; 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/DefaultCobarClientInternalRouter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router; 17 | 18 | import java.util.ArrayList; 19 | import java.util.HashMap; 20 | import java.util.List; 21 | import java.util.Map; 22 | import java.util.Set; 23 | 24 | import org.apache.commons.lang.StringUtils; 25 | import org.apache.commons.lang.Validate; 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | 29 | import com.alibaba.cobar.client.router.config.DefaultCobarClientInternalRouterXmlFactoryBean; 30 | import com.alibaba.cobar.client.router.rules.IRoutingRule; 31 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 32 | import com.alibaba.cobar.client.router.support.RoutingResult; 33 | import com.alibaba.cobar.client.support.utils.CollectionUtils; 34 | 35 | /** 36 | * {@link DefaultCobarClientInternalRouter} receive a map which will maintain a 37 | * group of rules as per SQ-map namespaces.
38 | * it will evaluate the rules as per namesapce and a sequence from specific 39 | * rules to more generic rules.
40 | * usually, the users don't need to care about these internal details, to use 41 | * {@link DefaultCobarClientInternalRouter}, just turn to 42 | * {@link DefaultCobarClientInternalRouterXmlFactoryBean} for instantiation.
43 | * 44 | * @author fujohnwang 45 | * @since 1.0 46 | * @see DefaultCobarClientInternalRouterXmlFactoryBean 47 | */ 48 | public class DefaultCobarClientInternalRouter implements ICobarRouter { 49 | 50 | private transient final Logger logger = LoggerFactory 51 | .getLogger(DefaultCobarClientInternalRouter.class); 52 | 53 | private Map>>>> rulesGroupByNamespaces = new HashMap>>>>(); 54 | 55 | public RoutingResult doRoute(IBatisRoutingFact routingFact) throws RoutingException { 56 | Validate.notNull(routingFact); 57 | String action = routingFact.getAction(); 58 | Validate.notEmpty(action); 59 | String namespace = StringUtils.substringBeforeLast(action, "."); 60 | List>>> rules = getRulesGroupByNamespaces() 61 | .get(namespace); 62 | 63 | RoutingResult result = new RoutingResult(); 64 | result.setResourceIdentities(new ArrayList()); 65 | 66 | if (!CollectionUtils.isEmpty(rules)) { 67 | IRoutingRule> ruleToUse = null; 68 | for (Set>> ruleSet : rules) { 69 | ruleToUse = searchMatchedRuleAgainst(ruleSet, routingFact); 70 | if (ruleToUse != null) { 71 | break; 72 | } 73 | } 74 | 75 | if (ruleToUse != null) { 76 | logger.info("matched with rule:{} with fact:{}", ruleToUse, routingFact); 77 | result.getResourceIdentities().addAll(ruleToUse.action()); 78 | } else { 79 | logger.info("No matched rule found for routing fact:{}", routingFact); 80 | } 81 | } 82 | 83 | return result; 84 | } 85 | 86 | private IRoutingRule> searchMatchedRuleAgainst( 87 | Set>> rules, 88 | IBatisRoutingFact routingFact) { 89 | if (CollectionUtils.isEmpty(rules)) { 90 | return null; 91 | } 92 | for (IRoutingRule> rule : rules) { 93 | if (rule.isDefinedAt(routingFact)) { 94 | return rule; 95 | } 96 | } 97 | return null; 98 | } 99 | 100 | public void setRulesGroupByNamespaces( 101 | Map>>>> rulesGroupByNamespaces) { 102 | this.rulesGroupByNamespaces = rulesGroupByNamespaces; 103 | } 104 | 105 | public Map>>>> getRulesGroupByNamespaces() { 106 | return rulesGroupByNamespaces; 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/DroolsBasedCobarRouter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router; 17 | 18 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 19 | import com.alibaba.cobar.client.router.support.RoutingResult; 20 | 21 | /** 22 | * TODO when rule numbers increase incredibly, we can introduce a rule engine like drools to enhance the performance of rule matching.
23 | * 24 | * @author fujohnwang 25 | * 26 | */ 27 | public class DroolsBasedCobarRouter implements ICobarRouter { 28 | 29 | public RoutingResult doRoute(IBatisRoutingFact routingFact) 30 | throws RoutingException { 31 | // TODO Auto-generated method stub 32 | return null; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/ICobarRouter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router; 17 | 18 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 19 | import com.alibaba.cobar.client.router.support.RoutingResult; 20 | 21 | /** 22 | * the routing fact can be any type, for our current ibatis-based solution, 23 | * it can be a wrapper object of sql action and its argument.
24 | * for other solutions, it can be other type as per different situations.
25 | * 26 | * @author fujohnwang 27 | * @since 1.0 28 | * @see IBatisRoutingFact 29 | */ 30 | public interface ICobarRouter { 31 | RoutingResult doRoute(T routingFact) throws RoutingException; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/RoutingException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router; 17 | 18 | import org.springframework.core.NestedRuntimeException; 19 | 20 | public class RoutingException extends NestedRuntimeException { 21 | private static final long serialVersionUID = 8980219652872668164L; 22 | 23 | public RoutingException(String msg, Throwable cause) { 24 | super(msg, cause); 25 | } 26 | 27 | public RoutingException(String msg) 28 | { 29 | super(msg); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/aspects/RoutingResultCacheAspect.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2010 Alibaba.com Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.aspects; 17 | 18 | import java.util.Arrays; 19 | 20 | import org.aopalliance.intercept.MethodInterceptor; 21 | import org.aopalliance.intercept.MethodInvocation; 22 | 23 | import com.alibaba.cobar.client.router.DefaultCobarClientInternalRouter; 24 | import com.alibaba.cobar.client.router.ICobarRouter; 25 | import com.alibaba.cobar.client.router.config.AbstractCobarClientInternalRouterFactoryBean; 26 | import com.alibaba.cobar.client.router.config.StaticCobarClientInternalRouterFactoryBean; 27 | import com.alibaba.cobar.client.support.LRUMap; 28 | 29 | /** 30 | * An advice that will provide cache service for {@link ICobarRouter} to improve 31 | * the routing performance if necessary.
32 | * 33 | * @author fujohnwang 34 | * @since 1.0 35 | * @see {@link ICobarRouter} 36 | * @see {@link AbstractCobarClientInternalRouterFactoryBean} 37 | * @see {@link DefaultCobarClientInternalRouter} 38 | * @see {@link StaticCobarClientInternalRouterFactoryBean} 39 | */ 40 | public class RoutingResultCacheAspect implements MethodInterceptor { 41 | 42 | private LRUMap internalCache = new LRUMap(1000); 43 | 44 | public Object invoke(MethodInvocation invocation) throws Throwable { 45 | Object[] args = invocation.getArguments(); 46 | if (args.length != 1) { 47 | throw new IllegalArgumentException("unexpected argument status on method:" 48 | + invocation.getMethod() + ", args:" + Arrays.toString(args)); 49 | } 50 | 51 | synchronized (internalCache) { 52 | if (internalCache.containsKey(args[0])) { 53 | return internalCache.get(args[0]); 54 | } 55 | } 56 | 57 | Object result = null; 58 | try { 59 | result = invocation.proceed(); 60 | } finally { 61 | synchronized (internalCache) { 62 | internalCache.put(args[0], result); 63 | } 64 | } 65 | 66 | return result; 67 | } 68 | 69 | public void setInternalCache(LRUMap internalCache) { 70 | if (internalCache == null) { 71 | throw new IllegalArgumentException("Null Cache Map is not allowed."); 72 | } 73 | this.internalCache = internalCache; 74 | } 75 | 76 | public LRUMap getInternalCache() { 77 | return internalCache; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/config/AbstractCobarClientInternalRouterFactoryBean.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.config; 17 | 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | import org.springframework.aop.framework.ProxyFactory; 23 | import org.springframework.beans.factory.FactoryBean; 24 | import org.springframework.beans.factory.InitializingBean; 25 | 26 | import com.alibaba.cobar.client.router.DefaultCobarClientInternalRouter; 27 | import com.alibaba.cobar.client.router.ICobarRouter; 28 | import com.alibaba.cobar.client.router.aspects.RoutingResultCacheAspect; 29 | import com.alibaba.cobar.client.router.config.support.InternalRuleLoader4DefaultInternalRouter; 30 | import com.alibaba.cobar.client.router.config.vo.InternalRule; 31 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 32 | import com.alibaba.cobar.client.support.LRUMap; 33 | 34 | /** 35 | * Top super class used to configure DefaultCobarClientInternalRouter instances.
36 | * 37 | * @author fujohnwang 38 | * @see DefaultCobarClientInternalRouter 39 | * @see DefaultCobarClientInternalRouterXmlFactoryBean 40 | * @see StaticCobarClientInternalRouterFactoryBean 41 | */ 42 | public abstract class AbstractCobarClientInternalRouterFactoryBean implements FactoryBean, 43 | InitializingBean { 44 | private ICobarRouter router; 45 | 46 | private Map functionsMap = new HashMap(); 47 | 48 | private InternalRuleLoader4DefaultInternalRouter ruleLoader = new InternalRuleLoader4DefaultInternalRouter(); 49 | 50 | private boolean enableCache; 51 | private int cacheSize = -1; 52 | 53 | public Object getObject() throws Exception { 54 | return router; 55 | } 56 | 57 | @SuppressWarnings("unchecked") 58 | public Class getObjectType() { 59 | return ICobarRouter.class; 60 | } 61 | 62 | public boolean isSingleton() { 63 | return true; 64 | } 65 | 66 | @SuppressWarnings("unchecked") 67 | public void afterPropertiesSet() throws Exception { 68 | 69 | DefaultCobarClientInternalRouter routerToUse = new DefaultCobarClientInternalRouter(); 70 | 71 | List rules = loadRulesFromExternal(); 72 | 73 | getRuleLoader().loadRulesAndEquipRouter(rules, routerToUse, getFunctionsMap()); 74 | 75 | if (isEnableCache()) { 76 | ProxyFactory proxyFactory = new ProxyFactory(routerToUse); 77 | proxyFactory.setInterfaces(new Class[] { ICobarRouter.class }); 78 | RoutingResultCacheAspect advice = new RoutingResultCacheAspect(); 79 | if (cacheSize > 0) { 80 | advice.setInternalCache(new LRUMap(cacheSize)); 81 | } 82 | proxyFactory.addAdvice(advice); 83 | this.router = (ICobarRouter) proxyFactory.getProxy(); 84 | } else { 85 | this.router = routerToUse; 86 | } 87 | } 88 | 89 | protected abstract List loadRulesFromExternal() throws Exception; 90 | 91 | public ICobarRouter getRouter() { 92 | return router; 93 | } 94 | 95 | public void setRouter(ICobarRouter router) { 96 | this.router = router; 97 | } 98 | 99 | public Map getFunctionsMap() { 100 | return functionsMap; 101 | } 102 | 103 | public void setFunctionsMap(Map functionsMap) { 104 | this.functionsMap = functionsMap; 105 | } 106 | 107 | public InternalRuleLoader4DefaultInternalRouter getRuleLoader() { 108 | return ruleLoader; 109 | } 110 | 111 | public void setRuleLoader(InternalRuleLoader4DefaultInternalRouter ruleLoader) { 112 | this.ruleLoader = ruleLoader; 113 | } 114 | 115 | public void setEnableCache(boolean enableCache) { 116 | this.enableCache = enableCache; 117 | } 118 | 119 | public boolean isEnableCache() { 120 | return enableCache; 121 | } 122 | 123 | public void setCacheSize(int cacheSize) { 124 | this.cacheSize = cacheSize; 125 | } 126 | 127 | public int getCacheSize() { 128 | return cacheSize; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/config/CobarInteralRouterXmlFactoryBean.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.config; 17 | 18 | import java.io.IOException; 19 | import java.util.List; 20 | import java.util.Set; 21 | 22 | import org.apache.commons.lang.StringUtils; 23 | import org.apache.commons.lang.Validate; 24 | import org.springframework.core.io.Resource; 25 | 26 | import com.alibaba.cobar.client.router.CobarClientInternalRouter; 27 | import com.alibaba.cobar.client.router.config.vo.InternalRule; 28 | import com.alibaba.cobar.client.router.config.vo.InternalRules; 29 | import com.alibaba.cobar.client.router.rules.IRoutingRule; 30 | import com.alibaba.cobar.client.router.rules.ibatis.IBatisNamespaceRule; 31 | import com.alibaba.cobar.client.router.rules.ibatis.IBatisNamespaceShardingRule; 32 | import com.alibaba.cobar.client.router.rules.ibatis.IBatisSqlActionRule; 33 | import com.alibaba.cobar.client.router.rules.ibatis.IBatisSqlActionShardingRule; 34 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 35 | import com.alibaba.cobar.client.support.utils.CollectionUtils; 36 | import com.alibaba.cobar.client.support.utils.MapUtils; 37 | import com.thoughtworks.xstream.XStream; 38 | 39 | public class CobarInteralRouterXmlFactoryBean extends 40 | AbstractCobarInternalRouterConfigurationFactoryBean { 41 | 42 | @Override 43 | protected void assembleRulesForRouter( 44 | CobarClientInternalRouter router, 45 | Resource configLocation, 46 | Set>> sqlActionShardingRules, 47 | Set>> sqlActionRules, 48 | Set>> namespaceShardingRules, 49 | Set>> namespaceRules) 50 | throws IOException { 51 | XStream xstream = new XStream(); 52 | xstream.alias("rules", InternalRules.class); 53 | xstream.alias("rule", InternalRule.class); 54 | xstream.addImplicitCollection(InternalRules.class, "rules"); 55 | xstream.useAttributeFor(InternalRule.class, "merger"); 56 | 57 | InternalRules internalRules = (InternalRules) xstream.fromXML(configLocation 58 | .getInputStream()); 59 | List rules = internalRules.getRules(); 60 | if (CollectionUtils.isEmpty(rules)) { 61 | return; 62 | } 63 | 64 | for (InternalRule rule : rules) { 65 | String namespace = StringUtils.trimToEmpty(rule.getNamespace()); 66 | String sqlAction = StringUtils.trimToEmpty(rule.getSqlmap()); 67 | String shardingExpression = StringUtils.trimToEmpty(rule.getShardingExpression()); 68 | String destinations = StringUtils.trimToEmpty(rule.getShards()); 69 | 70 | Validate.notEmpty(destinations, "destination shards must be given explicitly."); 71 | 72 | if (StringUtils.isEmpty(namespace) && StringUtils.isEmpty(sqlAction)) { 73 | throw new IllegalArgumentException( 74 | "at least one of 'namespace' or 'sqlAction' must be given."); 75 | } 76 | if (StringUtils.isNotEmpty(namespace) && StringUtils.isNotEmpty(sqlAction)) { 77 | throw new IllegalArgumentException( 78 | "'namespace' and 'sqlAction' are alternatives, can't guess which one to use if both of them are provided."); 79 | } 80 | 81 | if (StringUtils.isNotEmpty(namespace)) { 82 | if (StringUtils.isEmpty(shardingExpression)) { 83 | namespaceRules.add(new IBatisNamespaceRule(namespace, destinations)); 84 | } else { 85 | IBatisNamespaceShardingRule insr = new IBatisNamespaceShardingRule(namespace, 86 | destinations, shardingExpression); 87 | if (MapUtils.isNotEmpty(getFunctionsMap())) { 88 | insr.setFunctionMap(getFunctionsMap()); 89 | } 90 | namespaceShardingRules.add(insr); 91 | } 92 | } 93 | if (StringUtils.isNotEmpty(sqlAction)) { 94 | if (StringUtils.isEmpty(shardingExpression)) { 95 | sqlActionRules.add(new IBatisSqlActionRule(sqlAction, destinations)); 96 | } else { 97 | IBatisSqlActionShardingRule issr = new IBatisSqlActionShardingRule(sqlAction, 98 | destinations, shardingExpression); 99 | if (MapUtils.isNotEmpty(getFunctionsMap())) { 100 | issr.setFunctionMap(getFunctionsMap()); 101 | } 102 | sqlActionShardingRules.add(issr); 103 | } 104 | } 105 | } 106 | 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/config/CobarInternalRouterDSLFactoryBean.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.config; 17 | 18 | import java.io.IOException; 19 | import java.util.List; 20 | import java.util.Set; 21 | 22 | import org.springframework.core.io.Resource; 23 | 24 | import com.alibaba.cobar.client.router.CobarClientInternalRouter; 25 | import com.alibaba.cobar.client.router.rules.IRoutingRule; 26 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 27 | 28 | /** 29 | * read in DSL style configuration and construct/assemble corresponding rules, 30 | * for example:
31 | * 32 | *
33 |  *  route 
34 |  *      fact{namespace=some((;sqlmap=com.alibaba....)? ;shard=expression)?} 
35 |  *  to 
36 |  *      shards{ds1, ds2, ...}
37 |  *      
38 |  *  route 
39 |  *      fact{namespace=some((;sqlmap=com.alibaba....)? ;shard=expression)?} 
40 |  *  to
41 |  * shards{ds1, ds2, ...}
42 |  * 
43 |  * 
44 |  * TBD if needed.
45 |  * 
46 |  * @author fujohnwang
47 |  */
48 | public class CobarInternalRouterDSLFactoryBean extends
49 |         AbstractCobarInternalRouterConfigurationFactoryBean {
50 | 
51 |     @Override
52 |     protected void assembleRulesForRouter(
53 |                                           CobarClientInternalRouter router,
54 |                                           Resource configLocation,
55 |                                           Set>> sqlActionShardingRules,
56 |                                           Set>> sqlActionRules,
57 |                                           Set>> namespaceShardingRules,
58 |                                           Set>> namespaceRules)
59 |             throws IOException {
60 |         // TODO Auto-generated method stub
61 | 
62 |     }
63 | 
64 | }
65 | 


--------------------------------------------------------------------------------
/src/main/java/com/alibaba/cobar/client/router/config/CobarInternalRouterXlsRuleFactoryBean.java:
--------------------------------------------------------------------------------
 1 | /**
 2 |  * Copyright 1999-2011 Alibaba Group
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 |  package com.alibaba.cobar.client.router.config;
17 | 
18 | import java.io.IOException;
19 | import java.util.List;
20 | import java.util.Set;
21 | 
22 | import org.springframework.core.io.Resource;
23 | 
24 | import com.alibaba.cobar.client.router.CobarClientInternalRouter;
25 | import com.alibaba.cobar.client.router.rules.IRoutingRule;
26 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact;
27 | 
28 | /**
29 |  * read rules from decision table which is stored with excel file.
30 | * except for the 1st row as title, other each rows will be rule definitions.
31 | * it seems like: 32 | * 33 | *
34 |  * --------------------------------------------------------------------
35 |  * namespace   | sqlaction         |  shardingExpression|   shards    |
36 |  * --------------------------------------------------------------------
37 |  * com...Offer |                   | memberId < 10000   | shardOne,   |
38 |  * --------------------------------------------------------------------
39 |  *             |com...Offer.create | memberId > 1000000 | shardOne,   |
40 |  * --------------------------------------------------------------------
41 |  * 
42 | * 43 | * @author fujohnwang 44 | * @since 1.0 45 | */ 46 | public class CobarInternalRouterXlsRuleFactoryBean extends 47 | AbstractCobarInternalRouterConfigurationFactoryBean { 48 | 49 | @Override 50 | protected void assembleRulesForRouter( 51 | CobarClientInternalRouter router, 52 | Resource configLocation, 53 | Set>> sqlActionShardingRules, 54 | Set>> sqlActionRules, 55 | Set>> namespaceShardingRules, 56 | Set>> namespaceRules) 57 | throws IOException { 58 | // TODO Auto-generated method stub 59 | 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/config/DefaultCobarClientInternalRouterXmlFactoryBean.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.config; 17 | 18 | import java.io.IOException; 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | import org.springframework.core.io.Resource; 23 | 24 | import com.alibaba.cobar.client.router.config.vo.InternalRule; 25 | import com.alibaba.cobar.client.router.config.vo.InternalRules; 26 | import com.alibaba.cobar.client.support.utils.CollectionUtils; 27 | import com.thoughtworks.xstream.XStream; 28 | /** 29 | * 30 | * {@link DefaultCobarClientInternalRouterXmlFactoryBean} will load rule definitions from external xml configuration files.
31 | * if you want to directly define rules in spring's IoC Container, see {@link StaticCobarClientInternalRouterFactoryBean}. 32 | * @author fujohnwang 33 | * @see StaticCobarClientInternalRouterFactoryBean 34 | */ 35 | public class DefaultCobarClientInternalRouterXmlFactoryBean extends 36 | AbstractCobarClientInternalRouterFactoryBean { 37 | 38 | private Resource configLocation; 39 | private Resource[] configLocations; 40 | 41 | public Resource getConfigLocation() { 42 | return configLocation; 43 | } 44 | 45 | public void setConfigLocation(Resource configLocation) { 46 | this.configLocation = configLocation; 47 | } 48 | 49 | public Resource[] getConfigLocations() { 50 | return configLocations; 51 | } 52 | 53 | public void setConfigLocations(Resource[] configLocations) { 54 | this.configLocations = configLocations; 55 | } 56 | 57 | @Override 58 | protected List loadRulesFromExternal() throws IOException { 59 | XStream xstream = new XStream(); 60 | xstream.alias("rules", InternalRules.class); 61 | xstream.alias("rule", InternalRule.class); 62 | xstream.addImplicitCollection(InternalRules.class, "rules"); 63 | xstream.useAttributeFor(InternalRule.class, "merger"); 64 | 65 | List rules = new ArrayList(); 66 | 67 | if (getConfigLocation() != null) { 68 | InternalRules internalRules = (InternalRules) xstream.fromXML(getConfigLocation() 69 | .getInputStream()); 70 | if (!CollectionUtils.isEmpty(internalRules.getRules())) { 71 | rules.addAll(internalRules.getRules()); 72 | } 73 | } 74 | if (getConfigLocations() != null && getConfigLocations().length > 0) { 75 | for (Resource resource : getConfigLocations()) { 76 | InternalRules internalRules = (InternalRules) xstream.fromXML(resource 77 | .getInputStream()); 78 | if (!CollectionUtils.isEmpty(internalRules.getRules())) { 79 | rules.addAll(internalRules.getRules()); 80 | } 81 | } 82 | } 83 | 84 | return rules; 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/config/StaticCobarClientInternalRouterFactoryBean.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.config; 17 | 18 | import java.util.List; 19 | 20 | import com.alibaba.cobar.client.router.config.vo.InternalRule; 21 | 22 | /** 23 | * with StaticCobarClientInternalRouterFactoryBean, you can configure rules 24 | * directly in spring's IoC container.
25 | * that's, declaring bean definitions of {@link InternalRule} directly as 26 | * dependency of {@link StaticCobarClientInternalRouterFactoryBean}. 27 | * 28 | * @author fujohnwang 29 | * @see DefaultCobarClientInternalRouterXmlFactoryBean for another alternative 30 | * which will load rule definitions from external xml. 31 | */ 32 | public class StaticCobarClientInternalRouterFactoryBean extends 33 | AbstractCobarClientInternalRouterFactoryBean { 34 | 35 | private List rules; 36 | 37 | public void setRules(List rules) { 38 | this.rules = rules; 39 | } 40 | 41 | public List getRules() { 42 | return rules; 43 | } 44 | 45 | @Override 46 | protected List loadRulesFromExternal() { 47 | return getRules(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/config/vo/InternalRule.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.config.vo; 17 | 18 | public class InternalRule { 19 | 20 | private String namespace; 21 | private String sqlmap; 22 | private String shardingExpression; 23 | private String shards; 24 | /** 25 | * this field is not used for now, because it's still in leverage whether 26 | * it's proper to bind merging information into a routing concern. 27 | */ 28 | private String merger; 29 | 30 | public String getNamespace() { 31 | return namespace; 32 | } 33 | 34 | public void setNamespace(String namespace) { 35 | this.namespace = namespace; 36 | } 37 | 38 | public String getSqlmap() { 39 | return sqlmap; 40 | } 41 | 42 | public void setSqlmap(String sqlmap) { 43 | this.sqlmap = sqlmap; 44 | } 45 | 46 | public String getShardingExpression() { 47 | return shardingExpression; 48 | } 49 | 50 | public void setShardingExpression(String shardingExpression) { 51 | this.shardingExpression = shardingExpression; 52 | } 53 | 54 | public String getShards() { 55 | return shards; 56 | } 57 | 58 | public void setShards(String shards) { 59 | this.shards = shards; 60 | } 61 | 62 | /** 63 | * set the bean name of merger to use. 64 | * 65 | * @param merger, the bean name in the container. 66 | */ 67 | public void setMerger(String merger) { 68 | this.merger = merger; 69 | } 70 | 71 | /** 72 | * @return the bean name of the merger. 73 | */ 74 | public String getMerger() { 75 | return merger; 76 | } 77 | 78 | @Override 79 | public int hashCode() { 80 | final int prime = 31; 81 | int result = 1; 82 | result = prime * result + ((namespace == null) ? 0 : namespace.hashCode()); 83 | result = prime * result 84 | + ((shardingExpression == null) ? 0 : shardingExpression.hashCode()); 85 | result = prime * result + ((shards == null) ? 0 : shards.hashCode()); 86 | result = prime * result + ((sqlmap == null) ? 0 : sqlmap.hashCode()); 87 | return result; 88 | } 89 | 90 | @Override 91 | public boolean equals(Object obj) { 92 | if (this == obj) 93 | return true; 94 | if (obj == null) 95 | return false; 96 | if (getClass() != obj.getClass()) 97 | return false; 98 | InternalRule other = (InternalRule) obj; 99 | if (namespace == null) { 100 | if (other.namespace != null) 101 | return false; 102 | } else if (!namespace.equals(other.namespace)) 103 | return false; 104 | if (shardingExpression == null) { 105 | if (other.shardingExpression != null) 106 | return false; 107 | } else if (!shardingExpression.equals(other.shardingExpression)) 108 | return false; 109 | if (shards == null) { 110 | if (other.shards != null) 111 | return false; 112 | } else if (!shards.equals(other.shards)) 113 | return false; 114 | if (sqlmap == null) { 115 | if (other.sqlmap != null) 116 | return false; 117 | } else if (!sqlmap.equals(other.sqlmap)) 118 | return false; 119 | return true; 120 | } 121 | 122 | @Override 123 | public String toString() { 124 | return "InternalRule [namespace=" + namespace + ", shardingExpression=" 125 | + shardingExpression + ", shards=" + shards + ", sqlmap=" + sqlmap + "]"; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/config/vo/InternalRules.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.config.vo; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import com.thoughtworks.xstream.XStream; 22 | 23 | public class InternalRules { 24 | 25 | private List rules; 26 | 27 | public void setRules(List rules) { 28 | this.rules = rules; 29 | } 30 | 31 | public List getRules() { 32 | return rules; 33 | } 34 | 35 | public static void main(String[] args) { 36 | XStream xstream = new XStream(); 37 | xstream.alias("rules", InternalRules.class); 38 | xstream.alias("rule", InternalRule.class); 39 | xstream.addImplicitCollection(InternalRules.class, "rules"); 40 | xstream.useAttributeFor(InternalRule.class, "merger"); 41 | 42 | InternalRules rules = new InternalRules(); 43 | List rList = new ArrayList(); 44 | InternalRule r1 = new InternalRule(); 45 | r1.setNamespace("com.alibaba.cobar.client.entity.Follower"); 46 | r1.setShards("partition1"); 47 | rList.add(r1); 48 | InternalRule r2 = new InternalRule(); 49 | r2.setSqlmap("com.alibaba.cobar.client.entity.Follower.create"); 50 | r2.setShards("p1, p2"); 51 | rList.add(r2); 52 | InternalRule r3 = new InternalRule(); 53 | r3.setSqlmap("com.alibaba.cobar.client.entity.Follower.create"); 54 | r3.setShardingExpression("id>10000 and id< 20000"); 55 | r3.setShards("p1, p2"); 56 | rList.add(r3); 57 | InternalRule r4 = new InternalRule(); 58 | r4.setNamespace("com.alibaba.cobar.client.entity.Follower"); 59 | r4.setShardingExpression("id>10000 and id< 20000"); 60 | r4.setShards("p1, p2"); 61 | // r4.setMerger(Runnable.class); 62 | rList.add(r4); 63 | rules.setRules(rList); 64 | 65 | String xml = xstream.toXML(rules); 66 | System.out.println(xml); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/rules/AbstractEntityAttributeRule.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.rules; 17 | 18 | import org.apache.commons.lang.StringUtils; 19 | import org.apache.commons.lang.Validate; 20 | 21 | /** 22 | * horizontal partitioning oriented rule that matches against entity/table type and attribute values.
23 | * 24 | * @author fujohnwang 25 | * 26 | * @param 27 | * @param 28 | */ 29 | public abstract class AbstractEntityAttributeRule extends AbstractEntityTypeRule { 30 | private String attributePattern; 31 | 32 | public AbstractEntityAttributeRule(String typePattern, String action) 33 | { 34 | super(typePattern, action); 35 | } 36 | 37 | public AbstractEntityAttributeRule(String typePattern, String action, String attributePattern) 38 | { 39 | super(typePattern, action); 40 | Validate.notEmpty(StringUtils.trimToEmpty(attributePattern)); 41 | 42 | this.attributePattern = attributePattern; 43 | } 44 | 45 | public String getAttributePattern() { 46 | return attributePattern; 47 | } 48 | 49 | public void setAttributePattern(String attributePattern) { 50 | Validate.notEmpty(StringUtils.trimToEmpty(attributePattern)); 51 | this.attributePattern = attributePattern; 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | final int prime = 31; 57 | int result = super.hashCode(); 58 | result = prime * result + ((attributePattern == null) ? 0 : attributePattern.hashCode()); 59 | return result; 60 | } 61 | 62 | @Override 63 | public boolean equals(Object obj) { 64 | if (this == obj) 65 | return true; 66 | if (!super.equals(obj)) 67 | return false; 68 | if (getClass() != obj.getClass()) 69 | return false; 70 | AbstractEntityAttributeRule other = (AbstractEntityAttributeRule) obj; 71 | if (attributePattern == null) { 72 | if (other.attributePattern != null) 73 | return false; 74 | } else if (!attributePattern.equals(other.attributePattern)) 75 | return false; 76 | return true; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/rules/AbstractEntityTypeRule.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.rules; 17 | 18 | import org.apache.commons.lang.StringUtils; 19 | import org.apache.commons.lang.Validate; 20 | 21 | import com.alibaba.cobar.client.router.rules.ibatis.AbstractIBatisOrientedRule; 22 | 23 | /** 24 | * vertical partitioning oriented rule that matches against entity/table type.
25 | * 26 | * @author fujohnwang 27 | * @param , the fact type 28 | * @param , the action result type 29 | * @see AbstractIBatisOrientedRule 30 | */ 31 | public abstract class AbstractEntityTypeRule implements IRoutingRule { 32 | 33 | private String typePatten; // when 34 | private String action; // then, it's a more generic expression, although for us, a String[] is preferable. 35 | 36 | public AbstractEntityTypeRule(String pattern, String action) { 37 | Validate.notEmpty(StringUtils.trim(pattern)); 38 | Validate.notEmpty(StringUtils.trim(action)); 39 | 40 | this.typePatten = pattern; 41 | this.action = action; 42 | } 43 | 44 | public void setTypePattern(String leftExpression) { 45 | this.typePatten = leftExpression; 46 | } 47 | 48 | public String getTypePattern() { 49 | return typePatten; 50 | } 51 | 52 | public void setAction(String rightExpression) { 53 | this.action = rightExpression; 54 | } 55 | 56 | public String getAction() { 57 | return action; 58 | } 59 | 60 | @Override 61 | public int hashCode() { 62 | final int prime = 31; 63 | int result = 1; 64 | result = prime * result + ((action == null) ? 0 : action.hashCode()); 65 | result = prime * result + ((typePatten == null) ? 0 : typePatten.hashCode()); 66 | return result; 67 | } 68 | 69 | @Override 70 | public boolean equals(Object obj) { 71 | if (this == obj) 72 | return true; 73 | if (obj == null) 74 | return false; 75 | if (getClass() != obj.getClass()) 76 | return false; 77 | AbstractEntityTypeRule other = (AbstractEntityTypeRule) obj; 78 | if (action == null) { 79 | if (other.action != null) 80 | return false; 81 | } else if (!action.equals(other.action)) 82 | return false; 83 | if (typePatten == null) { 84 | if (other.typePatten != null) 85 | return false; 86 | } else if (!typePatten.equals(other.typePatten)) 87 | return false; 88 | return true; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/rules/IRoutingRule.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.rules; 17 | 18 | import com.alibaba.cobar.client.router.ICobarRouter; 19 | 20 | /** 21 | * a rule acts in a "when-then" behavior, in our case, when the fact 22 | * {@link #isDefinedAt(Object)} or matches, then we will return action result. 23 | * the {@link ICobarRouter} will decide how to use these action result. 24 | * 25 | * @author fujohnwang 26 | * @since 1.0 27 | */ 28 | public interface IRoutingRule { 29 | /** 30 | * @param , the type of the routing fact 31 | * @param routeFact, the fact to check against 32 | * @return 33 | */ 34 | boolean isDefinedAt(F routingFact); 35 | 36 | /** 37 | * if a update or delete will involve multiple data sources, we have to 38 | * return a group of data sources to use.
39 | * for rules the matches only one data source, return a set with size==1.
40 | * 41 | * @return 42 | */ 43 | T action(); 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/rules/ibatis/AbstractIBatisOrientedRule.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.rules.ibatis; 17 | 18 | import java.util.ArrayList; 19 | import java.util.HashMap; 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | import org.apache.commons.lang.StringUtils; 24 | import org.apache.commons.lang.Validate; 25 | 26 | import com.alibaba.cobar.client.router.rules.AbstractEntityAttributeRule; 27 | import com.alibaba.cobar.client.router.rules.IRoutingRule; 28 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 29 | import com.alibaba.cobar.client.support.utils.CollectionUtils; 30 | /** 31 | * super class for all of the {@link IRoutingRule} implementations that is oriented to be used to do routing with iBatis sqlmap. 32 | * 33 | * @author fujohnwang 34 | * @since 1.0 35 | */ 36 | public abstract class AbstractIBatisOrientedRule extends AbstractEntityAttributeRule> { 37 | public static final String DEFAULT_DATASOURCE_IDENTITY_SEPARATOR = ","; 38 | 39 | private Map functionMap = new HashMap(); 40 | 41 | private String actionPatternSeparator = DEFAULT_DATASOURCE_IDENTITY_SEPARATOR; 42 | 43 | private List dataSourceIds = new ArrayList(); 44 | 45 | public AbstractIBatisOrientedRule(String pattern, String action) { 46 | super(pattern, action); 47 | } 48 | 49 | public AbstractIBatisOrientedRule(String pattern, String action, String attributePattern) { 50 | super(pattern, action, attributePattern); 51 | } 52 | 53 | public synchronized List action() { 54 | if(CollectionUtils.isEmpty(dataSourceIds)) 55 | { 56 | List ids = new ArrayList(); 57 | for (String id : StringUtils.split(getAction(), getActionPatternSeparator())) { 58 | ids.add(StringUtils.trimToEmpty(id)); 59 | } 60 | setDataSourceIds(ids); 61 | } 62 | return dataSourceIds; 63 | } 64 | 65 | public void setDataSourceIds(List dataSourceIds) { 66 | this.dataSourceIds = dataSourceIds; 67 | } 68 | 69 | public List getDataSourceIds() { 70 | return dataSourceIds; 71 | } 72 | 73 | public void setActionPatternSeparator(String actionPatternSeparator) { 74 | Validate.notNull(actionPatternSeparator); 75 | this.actionPatternSeparator = actionPatternSeparator; 76 | } 77 | 78 | public String getActionPatternSeparator() { 79 | return actionPatternSeparator; 80 | } 81 | 82 | public void setFunctionMap(Map functionMap) { 83 | this.functionMap = functionMap; 84 | } 85 | 86 | public Map getFunctionMap() { 87 | return functionMap; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/rules/ibatis/IBatisNamespaceRule.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.rules.ibatis; 17 | 18 | import org.apache.commons.lang.StringUtils; 19 | import org.apache.commons.lang.Validate; 20 | 21 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 22 | /** 23 | * Vertical Partitioning Rule which maps iBatis's namespace in sqlmap file to entity/table type.
24 | * 25 | * @author fujohnwang 26 | * @since 1.0 27 | */ 28 | public class IBatisNamespaceRule extends AbstractIBatisOrientedRule { 29 | 30 | public IBatisNamespaceRule(String pattern, String action) { 31 | super(pattern, action); 32 | } 33 | 34 | public boolean isDefinedAt(IBatisRoutingFact routingFact) { 35 | Validate.notNull(routingFact); 36 | String namespace = StringUtils.substringBeforeLast(routingFact.getAction(), "."); 37 | return StringUtils.equals(namespace, getTypePattern()); 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "IBatisNamespaceRule [getAction()=" + getAction() + ", getTypePattern()=" 43 | + getTypePattern() + "]"; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/rules/ibatis/IBatisNamespaceShardingRule.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.rules.ibatis; 17 | 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | 21 | import org.apache.commons.lang.StringUtils; 22 | import org.apache.commons.lang.Validate; 23 | import org.mvel2.MVEL; 24 | import org.mvel2.integration.VariableResolverFactory; 25 | import org.mvel2.integration.impl.MapVariableResolverFactory; 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | 29 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 30 | 31 | public class IBatisNamespaceShardingRule extends AbstractIBatisOrientedRule { 32 | 33 | private transient final Logger logger = LoggerFactory 34 | .getLogger(IBatisNamespaceShardingRule.class); 35 | 36 | public IBatisNamespaceShardingRule(String pattern, String action, String attributePattern) { 37 | super(pattern, action, attributePattern); 38 | } 39 | 40 | public boolean isDefinedAt(IBatisRoutingFact routingFact) { 41 | Validate.notNull(routingFact); 42 | String namespace = StringUtils.substringBeforeLast(routingFact.getAction(), "."); 43 | boolean matches = StringUtils.equals(namespace, getTypePattern()); 44 | if (matches) { 45 | try { 46 | Map vrs = new HashMap(); 47 | vrs.putAll(getFunctionMap()); 48 | vrs.put("$ROOT", routingFact.getArgument()); // add top object reference for expression 49 | VariableResolverFactory vrfactory = new MapVariableResolverFactory(vrs); 50 | if (MVEL.evalToBoolean(getAttributePattern(), routingFact.getArgument(), vrfactory)) { 51 | return true; 52 | } 53 | } catch (Throwable t) { 54 | logger 55 | .info( 56 | "failed to evaluate attribute expression:'{}' with context object:'{}'\n{}", 57 | new Object[] { getAttributePattern(), routingFact.getArgument(), t }); 58 | } 59 | } 60 | return false; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return "IBatisNamespaceShardingRule [getAttributePattern()=" + getAttributePattern() 66 | + ", getAction()=" + getAction() + ", getTypePattern()=" + getTypePattern() + "]"; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/rules/ibatis/IBatisSqlActionRule.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.rules.ibatis; 17 | 18 | import org.apache.commons.lang.StringUtils; 19 | import org.apache.commons.lang.Validate; 20 | 21 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 22 | 23 | /** 24 | * iBatis SQL-Map specific vertical partitioning rule.
25 | * 26 | * @author fujohnwang 27 | * @since 1.0 28 | */ 29 | public class IBatisSqlActionRule extends AbstractIBatisOrientedRule { 30 | 31 | public IBatisSqlActionRule(String pattern, String action) { 32 | super(pattern, action); 33 | } 34 | 35 | public boolean isDefinedAt(IBatisRoutingFact routeFact) { 36 | Validate.notNull(routeFact); 37 | return StringUtils.equals(getTypePattern(), routeFact.getAction()); 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "IBatisSqlActionRule [getAction()=" + getAction() + ", getTypePattern()=" 43 | + getTypePattern() + "]"; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/rules/ibatis/IBatisSqlActionShardingRule.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.rules.ibatis; 17 | 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | 21 | import org.apache.commons.lang.StringUtils; 22 | import org.apache.commons.lang.Validate; 23 | import org.mvel2.MVEL; 24 | import org.mvel2.integration.VariableResolverFactory; 25 | import org.mvel2.integration.impl.MapVariableResolverFactory; 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | 29 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 30 | 31 | public class IBatisSqlActionShardingRule extends AbstractIBatisOrientedRule { 32 | 33 | private transient final Logger logger = LoggerFactory 34 | .getLogger(IBatisSqlActionShardingRule.class); 35 | 36 | public IBatisSqlActionShardingRule(String pattern, String action, String attributePattern) { 37 | super(pattern, action, attributePattern); 38 | } 39 | 40 | public boolean isDefinedAt(IBatisRoutingFact routingFact) { 41 | Validate.notNull(routingFact); 42 | boolean matches = StringUtils.equals(getTypePattern(), routingFact.getAction()); 43 | if (matches) { 44 | try { 45 | Map vrs = new HashMap(); 46 | vrs.putAll(getFunctionMap()); 47 | vrs.put("$ROOT", routingFact.getArgument()); // add top object reference for expression 48 | VariableResolverFactory vrfactory = new MapVariableResolverFactory(vrs); 49 | if (MVEL.evalToBoolean(getAttributePattern(), routingFact.getArgument(), vrfactory)) { 50 | return true; 51 | } 52 | } catch (Throwable t) { 53 | logger 54 | .info( 55 | "failed to evaluate attribute expression:'{}' with context object:'{}'\n{}", 56 | new Object[] { getAttributePattern(), routingFact.getArgument(), t }); 57 | } 58 | } 59 | 60 | return false; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return "IBatisSqlActionShardingRule [getAttributePattern()=" + getAttributePattern() 66 | + ", getAction()=" + getAction() + ", getTypePattern()=" + getTypePattern() + "]"; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/support/IBatisRoutingFact.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.support; 17 | 18 | /** 19 | * A Wrapper for ibatis-based routing fact. 20 | * 21 | * @author fujohnwang 22 | * @since 1.0 23 | */ 24 | public class IBatisRoutingFact { 25 | // SQL identity 26 | private String action; 27 | // the argument of SQL action 28 | private Object argument; 29 | 30 | public IBatisRoutingFact(){} 31 | public IBatisRoutingFact(String sql, Object arg){ 32 | this.action = sql; 33 | this.argument = arg; 34 | } 35 | 36 | public String getAction() { 37 | return action; 38 | } 39 | public void setAction(String action) { 40 | this.action = action; 41 | } 42 | public Object getArgument() { 43 | return argument; 44 | } 45 | public void setArgument(Object argument) { 46 | this.argument = argument; 47 | } 48 | @Override 49 | public int hashCode() { 50 | final int prime = 31; 51 | int result = 1; 52 | result = prime * result + ((action == null) ? 0 : action.hashCode()); 53 | result = prime * result 54 | + ((argument == null) ? 0 : argument.hashCode()); 55 | return result; 56 | } 57 | @Override 58 | public boolean equals(Object obj) { 59 | if (this == obj) 60 | return true; 61 | if (obj == null) 62 | return false; 63 | if (getClass() != obj.getClass()) 64 | return false; 65 | IBatisRoutingFact other = (IBatisRoutingFact) obj; 66 | if (action == null) { 67 | if (other.action != null) 68 | return false; 69 | } else if (!action.equals(other.action)) 70 | return false; 71 | if (argument == null) { 72 | if (other.argument != null) 73 | return false; 74 | } else if (!argument.equals(other.argument)) 75 | return false; 76 | return true; 77 | } 78 | @Override 79 | public String toString() { 80 | return "IBatisRoutingFact [action=" + action + ", argument=" + argument 81 | + "]"; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/router/support/RoutingResult.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.router.support; 17 | 18 | import java.util.List; 19 | 20 | import com.alibaba.cobar.client.merger.IMerger; 21 | 22 | /** 23 | * @author fujohnwang 24 | * @since 1.0 25 | */ 26 | public class RoutingResult { 27 | private List resourceIdentities; 28 | private IMerger merger; 29 | 30 | public List getResourceIdentities() { 31 | return resourceIdentities; 32 | } 33 | 34 | public void setResourceIdentities(List resourceIdentities) { 35 | this.resourceIdentities = resourceIdentities; 36 | } 37 | 38 | public void setMerger(IMerger merger) { 39 | this.merger = merger; 40 | } 41 | 42 | public IMerger getMerger() { 43 | return merger; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/support/LRUMap.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.support; 17 | 18 | import java.util.LinkedHashMap; 19 | 20 | public class LRUMap extends LinkedHashMap { 21 | 22 | private static final long serialVersionUID = -3700466745992492679L; 23 | 24 | private int coreSize; 25 | 26 | public LRUMap(int coreSize) { 27 | super(coreSize + 1, 1.1f, true); 28 | this.coreSize = coreSize; 29 | } 30 | 31 | @Override 32 | protected boolean removeEldestEntry(java.util.Map.Entry eldest) { 33 | return size() > coreSize; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/support/execution/ConcurrentRequest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.support.execution; 17 | 18 | import java.util.concurrent.ExecutorService; 19 | 20 | import javax.sql.DataSource; 21 | 22 | import org.springframework.orm.ibatis.SqlMapClientCallback; 23 | /** 24 | * {@link #action} will be executed on {@link #dataSource} with {@link #executor} asynchronously.
25 | * 26 | * @author fujohnwang 27 | * @since 1.0 28 | */ 29 | public class ConcurrentRequest { 30 | private SqlMapClientCallback action; 31 | private DataSource dataSource; 32 | private ExecutorService executor; 33 | 34 | public SqlMapClientCallback getAction() { 35 | return action; 36 | } 37 | 38 | public void setAction(SqlMapClientCallback action) { 39 | this.action = action; 40 | } 41 | 42 | public DataSource getDataSource() { 43 | return dataSource; 44 | } 45 | 46 | public void setDataSource(DataSource dataSource) { 47 | this.dataSource = dataSource; 48 | } 49 | 50 | public ExecutorService getExecutor() { 51 | return executor; 52 | } 53 | 54 | public void setExecutor(ExecutorService executor) { 55 | this.executor = executor; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/support/execution/IConcurrentRequestProcessor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.support.execution; 17 | 18 | import java.util.List; 19 | 20 | public interface IConcurrentRequestProcessor { 21 | List process(List requests); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/support/execution/RequestDepository.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.support.execution; 17 | 18 | import java.sql.Connection; 19 | 20 | /** 21 | * temporary status depository for request processing.
22 | * 23 | * @author fujohnwang 24 | * @since 1.0 25 | */ 26 | public class RequestDepository { 27 | private ConcurrentRequest originalRequest; 28 | private Connection connectionToUse; 29 | private boolean transactionAware; 30 | 31 | public ConcurrentRequest getOriginalRequest() { 32 | return originalRequest; 33 | } 34 | 35 | public void setOriginalRequest(ConcurrentRequest originalRequest) { 36 | this.originalRequest = originalRequest; 37 | } 38 | 39 | public Connection getConnectionToUse() { 40 | return connectionToUse; 41 | } 42 | 43 | public void setConnectionToUse(Connection connectionToUse) { 44 | this.connectionToUse = connectionToUse; 45 | } 46 | 47 | public boolean isTransactionAware() { 48 | return transactionAware; 49 | } 50 | 51 | public void setTransactionAware(boolean transactionAware) { 52 | this.transactionAware = transactionAware; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/support/utils/CollectionUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.support.utils; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collection; 20 | import java.util.Iterator; 21 | import java.util.List; 22 | 23 | public class CollectionUtils { 24 | @SuppressWarnings("rawtypes") 25 | public static Collection select(Collection inputCollection, Predicate predicate) { 26 | List answer = new ArrayList(inputCollection.size()); 27 | select(inputCollection, predicate, answer); 28 | return answer; 29 | } 30 | 31 | @SuppressWarnings({ "rawtypes", "unchecked" }) 32 | public static void select(Collection inputCollection, Predicate predicate, 33 | Collection outputCollection) { 34 | if (inputCollection != null && predicate != null) { 35 | for (Iterator iter = inputCollection.iterator(); iter.hasNext();) { 36 | Object item = iter.next(); 37 | if (predicate.evaluate(item)) { 38 | outputCollection.add(item); 39 | } 40 | } 41 | } 42 | } 43 | 44 | @SuppressWarnings("rawtypes") 45 | public static boolean isEmpty(Collection coll) { 46 | return (coll == null || coll.isEmpty()); 47 | } 48 | 49 | @SuppressWarnings("rawtypes") 50 | public static boolean isNotEmpty(Collection coll) { 51 | return !CollectionUtils.isEmpty(coll); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/support/utils/MapUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.support.utils; 17 | 18 | import java.util.Map; 19 | 20 | public abstract class MapUtils { 21 | 22 | public static boolean isEmpty(Map map) { 23 | return (map == null || map.isEmpty()); 24 | } 25 | 26 | public static boolean isNotEmpty(Map map) { 27 | return !MapUtils.isEmpty(map); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/support/utils/Predicate.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.support.utils; 17 | 18 | public interface Predicate { 19 | public boolean evaluate(Object object); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/support/vo/BatchInsertTask.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.support.vo; 17 | 18 | import java.util.Collection; 19 | 20 | public class BatchInsertTask { 21 | private Collection entities; 22 | 23 | public BatchInsertTask() { 24 | } 25 | 26 | public BatchInsertTask(Collection entitiesCol) { 27 | this.setEntities(entitiesCol); 28 | } 29 | 30 | public void setEntities(Collection entities) { 31 | this.entities = entities; 32 | } 33 | 34 | public Collection getEntities() { 35 | return entities; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/support/vo/CobarMRBase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.support.vo; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Arrays; 20 | import java.util.HashMap; 21 | import java.util.HashSet; 22 | import java.util.List; 23 | import java.util.Map; 24 | import java.util.Set; 25 | import java.util.concurrent.locks.Lock; 26 | import java.util.concurrent.locks.ReentrantLock; 27 | 28 | import com.alibaba.cobar.client.support.utils.CollectionUtils; 29 | /** 30 | * 31 | * TODO Comment of CobarHive 32 | * @author fujohnwang 33 | * 34 | */ 35 | public class CobarMRBase { 36 | 37 | private Map> resources = new HashMap>(); 38 | private Map locks = new HashMap(); 39 | private Set keys = new HashSet(); 40 | 41 | public CobarMRBase(String[] keys) { 42 | this(Arrays.asList(keys)); 43 | } 44 | 45 | public CobarMRBase(List keys) { 46 | if (CollectionUtils.isEmpty(keys)) { 47 | throw new IllegalArgumentException( 48 | "empty collection is invalid for hive to spawn data holders."); 49 | } 50 | this.keys.addAll(keys); 51 | initResourceHolders(); 52 | initResourceLocks(); 53 | } 54 | 55 | public CobarMRBase(Set keys) { 56 | if (CollectionUtils.isEmpty(keys)) { 57 | throw new IllegalArgumentException( 58 | "empty collection is invalid for hive to spawn data holders."); 59 | } 60 | this.keys.addAll(keys); 61 | initResourceHolders(); 62 | initResourceLocks(); 63 | } 64 | 65 | private void initResourceLocks() { 66 | for (String key : keys) { 67 | locks.put(key, new ReentrantLock()); 68 | } 69 | } 70 | 71 | private void initResourceHolders() { 72 | for (String key : keys) { 73 | resources.put(key, new ArrayList()); 74 | } 75 | } 76 | 77 | public Map> getResources() 78 | { 79 | return this.resources; 80 | } 81 | 82 | public void emit(String key, T entity) 83 | { 84 | Lock lock = locks.get(key); 85 | lock.lock(); 86 | try{ 87 | resources.get(key).add(entity); 88 | } 89 | finally 90 | { 91 | lock.unlock(); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/cobar/client/support/vo/Pair.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 1999-2011 Alibaba Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.alibaba.cobar.client.support.vo; 17 | 18 | /** 19 | * value object to model a Key-Value entity which similar to Map.Entry, but more generic.
20 | * you can use other alternatives too if you would like to. 21 | * 22 | * @author fujohnwang 23 | * 24 | * @param 25 | * @param 26 | */ 27 | public class Pair { 28 | private K key; 29 | private V value; 30 | 31 | public K getKey() { 32 | return key; 33 | } 34 | public void setKey(K key) { 35 | this.key = key; 36 | } 37 | public V getValue() { 38 | return value; 39 | } 40 | public void setValue(V value) { 41 | this.value = value; 42 | } 43 | @Override 44 | public int hashCode() { 45 | final int prime = 31; 46 | int result = 1; 47 | result = prime * result + ((key == null) ? 0 : key.hashCode()); 48 | result = prime * result + ((value == null) ? 0 : value.hashCode()); 49 | return result; 50 | } 51 | @Override 52 | public boolean equals(Object obj) { 53 | if (this == obj) 54 | return true; 55 | if (obj == null) 56 | return false; 57 | if (getClass() != obj.getClass()) 58 | return false; 59 | Pair other = (Pair) obj; 60 | if (key == null) { 61 | if (other.key != null) 62 | return false; 63 | } else if (!key.equals(other.key)) 64 | return false; 65 | if (value == null) { 66 | if (other.value != null) 67 | return false; 68 | } else if (!value.equals(other.value)) 69 | return false; 70 | return true; 71 | } 72 | @Override 73 | public String toString() { 74 | return "Pair [key=" + key + ", value=" + value + "]"; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/resources/rules.dtd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/test/java/META-INF/ibatis/sqlmap-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/test/java/META-INF/ibatis/sqlmap/followers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | insert into followers(name) values(#name#) 14 | 15 | SELECT LAST_INSERT_ID(); 16 | 17 | 18 | 19 | 20 | insert into followers(name) values 21 | 22 | (#[].name#) 23 | 24 | 25 | 26 | 27 | delete from followers where name=#name# 28 | 29 | 30 | 31 | update followers set name=#name# where id=#id# 32 | 33 | 34 | 37 | 38 | 41 | 42 | 45 | 46 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/test/java/META-INF/ibatis/sqlmap/offers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | INSERT INTO offers(memberId, subject, gmtUpdated) VALUES(#memberId#, #subject#, #gmtUpdated#) 16 | 17 | SELECT LAST_INSERT_ID(); 18 | 19 | 20 | 21 | 22 | INSERT INTO offers(memberId, subject, gmtUpdated) VALUES 23 | 24 | (#[].memberId#,#[].subject#, #[].gmtUpdated#) 25 | 26 | 27 | 28 | 29 | delete from offers where id=#value# 30 | 31 | 32 | 33 | delete from offers where memberId=#memberId# 34 | 35 | 36 | 37 | UPDATE offers SET subject=#subject#, gmtUpdated=#gmtUpdated# WHERE id=#id# 38 | 39 | 40 | 43 | 44 | 47 | 48 | 51 | 52 | 57 | 58 | 61 | 62 | -------------------------------------------------------------------------------- /src/test/java/META-INF/ibatis/sqlmap/tweets.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | insert into tweets(tweet) values(#tweet#) 14 | 15 | 16 | 17 | update tweets set tweet=#tweet# where id=#id# 18 | 19 | 20 | 23 | 24 | 27 | 28 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/test/java/META-INF/routing/ns-only-rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.alibaba.cobar.client.entities.Tweet 6 | partition1 7 | 8 | 9 | com.alibaba.cobar.client.entities.Follower 10 | partition2 11 | 12 | -------------------------------------------------------------------------------- /src/test/java/META-INF/routing/ns-sharding-rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.alibaba.cobar.client.entities.Follower 4 | 5 | partition1 6 | 7 | 8 | com.alibaba.cobar.client.entities.Follower 9 | 10 | partition2 11 | 12 | -------------------------------------------------------------------------------- /src/test/java/META-INF/routing/offer-sharding-rules-on-namespace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.alibaba.cobar.client.entities.Offer 4 | 5 | partition1 6 | 7 | 8 | com.alibaba.cobar.client.entities.Offer 9 | 10 | partition2 11 | 12 | -------------------------------------------------------------------------------- /src/test/java/META-INF/routing/offer-sql-action-rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.alibaba.cobar.client.entities.Offer.findAll 4 | partition1, partition2 5 | 6 | -------------------------------------------------------------------------------- /src/test/java/META-INF/routing/sqlaction-only-rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.alibaba.cobar.client.entities.Follower.finaByName 4 | partition2 5 | 6 | 7 | com.alibaba.cobar.client.entities.Follower.findAll 8 | partition1, partition2 9 | 10 | -------------------------------------------------------------------------------- /src/test/java/META-INF/routing/sqlaction-sharding-rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.alibaba.cobar.client.entities.Follower.create 4 | 5 | partition1 6 | 7 | 8 | com.alibaba.cobar.client.entities.Follower.create 9 | 10 | partition2 11 | 12 | 13 | com.alibaba.cobar.client.entities.Follower.batchInsert 14 | 15 | partition1 16 | 17 | 18 | com.alibaba.cobar.client.entities.Follower.batchInsert 19 | 20 | partition2 21 | 22 | -------------------------------------------------------------------------------- /src/test/java/META-INF/spring/cobar-client-appctx.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/test/java/META-INF/spring/cobar-client-custom-merger-appctx.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 42 | 43 | 44 | 45 | 46 | 47 | 128 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/test/java/META-INF/spring/cobar-client-offer-services-appctx.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/test/java/META-INF/spring/datasources-appctx.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/test/java/META-INF/spring/namespace-router-appctx.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/test/java/META-INF/spring/namespace-sharding-router-appctx.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/test/java/META-INF/spring/namespace-sqlaction-composed-router-appctx.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 128 21 | 22 | 23 | 24 | 25 | 26 | 27 | classpath:META-INF/routing/offer-sql-action-rules.xml 28 | classpath:META-INF/routing/offer-sharding-rules-on-namespace.xml 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | 39 | 128 40 | 41 | 42 | 43 | 44 | 45 | 46 | classpath:META-INF/routing/offer-sql-action-rules.xml 47 | classpath:META-INF/routing/offer-sharding-rules-on-namespace.xml 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/test/java/META-INF/spring/sqlaction-router-appctx.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/test/java/META-INF/spring/sqlaction-sharding-router-appctx.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/test/java/META-INF/sql/cobarha_schema.sql: -------------------------------------------------------------------------------- 1 | CREATE MEMORY TABLE IF NOT EXISTS cobarha( 2 | timeflag TIMESTAMP 3 | ); -------------------------------------------------------------------------------- /src/test/java/META-INF/sql/follower_schema.sql: -------------------------------------------------------------------------------- 1 | CREATE MEMORY TABLE IF NOT EXISTS followers( 2 | id BIGINT IDENTITY PRIMARY KEY, 3 | name VARCHAR(255) 4 | ); -------------------------------------------------------------------------------- /src/test/java/META-INF/sql/offer_schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS offers( 2 | id BIGINT(20) AUTO_INCREMENT PRIMARY KEY, 3 | memberId VARCHAR(32), 4 | subject VARCHAR(512), 5 | gmtUpdated TIMESTAMP default CURRENT_TIMESTAMP() 6 | ); -------------------------------------------------------------------------------- /src/test/java/META-INF/sql/tweets_schema.sql: -------------------------------------------------------------------------------- 1 | CREATE MEMORY TABLE IF NOT EXISTS tweets( 2 | id BIGINT IDENTITY PRIMARY KEY, 3 | tweet VARCHAR(140) 4 | ); 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/CobarSqlMapClientDaoSupportTestWithComposedRuleRouter.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client; 2 | 3 | import static org.testng.AssertJUnit.assertEquals; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Date; 7 | import java.util.List; 8 | 9 | import org.testng.annotations.BeforeTest; 10 | import org.testng.annotations.Test; 11 | 12 | import com.alibaba.cobar.client.entities.Offer; 13 | 14 | @Test(sequential = true) 15 | public class CobarSqlMapClientDaoSupportTestWithComposedRuleRouter extends 16 | AbstractTestNGCobarClientTest { 17 | 18 | private CobarSqlMapClientDaoSupport dao = new CobarSqlMapClientDaoSupport(); 19 | private Long[] memberIds = new Long[] { 1L, 129L, 257L, 2L, 130L, 258L, 20 | 386L }; 21 | 22 | public static final String CREATE_SQL = "com.alibaba.cobar.client.entities.Offer.create"; 23 | public static final String UPDATE_SQL = "com.alibaba.cobar.client.entities.Offer.update"; 24 | public static final String DELETE_SQL = "com.alibaba.cobar.client.entities.Offer.deleteByMemberId"; 25 | 26 | public CobarSqlMapClientDaoSupportTestWithComposedRuleRouter() { 27 | super(new String[] { "META-INF/spring/cobar-client-appctx.xml", 28 | "META-INF/spring/datasources-appctx.xml", 29 | "META-INF/spring/namespace-sqlaction-composed-router-appctx.xml" }); 30 | } 31 | 32 | @BeforeTest 33 | public void setupDaoSupport() { 34 | dao.setSqlMapClientTemplate(getSqlMapClientTemplate()); 35 | } 36 | 37 | public void testBatchInsertOnDaoSupport() { 38 | verifyNonExistenceOnPartitions(); 39 | List offers = createOffersWithMemberIds(memberIds); 40 | int result = dao.batchInsert(CREATE_SQL, offers); 41 | assertEquals(7, result); 42 | verifyExistenceOnPartitions(); 43 | } 44 | 45 | public void testBatchUpdateOnDaoSupport() { 46 | verifyNonExistenceOnPartitions(); 47 | List offers = createOffersWithMemberIds(memberIds); 48 | 49 | int updatedNumber = dao.batchUpdate(UPDATE_SQL, offers); 50 | assertEquals(0, updatedNumber); 51 | 52 | int result = dao.batchInsert(CREATE_SQL, offers); 53 | assertEquals(7, result); 54 | verifyExistenceOnPartitions(); 55 | 56 | for (Offer offer : offers) { 57 | offer.setSubject("_subject_to_update_"); 58 | } 59 | 60 | updatedNumber = dao.batchUpdate(UPDATE_SQL, offers); 61 | assertEquals(7, updatedNumber); 62 | } 63 | 64 | public void testBatchDeleteOnDaoSupport() { 65 | verifyNonExistenceOnPartitions(); 66 | 67 | List offers = createOffersWithMemberIds(memberIds); 68 | int result = dao.batchDelete(DELETE_SQL, offers); 69 | assertEquals(0, result); 70 | 71 | int insertCount = dao.batchInsert(CREATE_SQL, offers); 72 | assertEquals(7, insertCount); 73 | verifyExistenceOnPartitions(); 74 | 75 | int deleteCount = dao.batchDelete(DELETE_SQL, offers); 76 | assertEquals(7, deleteCount); 77 | verifyNonExistenceOnPartitions(); 78 | } 79 | 80 | private List createOffersWithMemberIds(Long[] memberIds) { 81 | List offers = new ArrayList(); 82 | for (Long mid : memberIds) { 83 | Offer offer = new Offer(); 84 | offer.setGmtUpdated(new Date()); 85 | offer.setMemberId(mid); 86 | offer.setSubject("fake offer"); 87 | offers.add(offer); 88 | } 89 | return offers; 90 | } 91 | 92 | private void verifyNonExistenceOnPartitions() { 93 | for (int i = 0; i < memberIds.length; i++) { 94 | String confirmSQL = "select subject from offers where memberId=" + memberIds[i]; 95 | if (i < 3) { 96 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1m); 97 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s); 98 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2m); 99 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s); 100 | } else { 101 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1m); 102 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s); 103 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2m); 104 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s); 105 | } 106 | } 107 | } 108 | 109 | private void verifyExistenceOnPartitions() { 110 | for (int i = 0; i < memberIds.length; i++) { 111 | String confirmSQL = "select subject from offers where memberId=" + memberIds[i]; 112 | if (i < 3) { 113 | verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt1m); 114 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s); 115 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2m); 116 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s); 117 | } else { 118 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1m); 119 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt1s); 120 | verifyEntityExistenceOnSpecificDataSource(confirmSQL, jt2m); 121 | verifyEntityNonExistenceOnSpecificDataSource(confirmSQL, jt2s); 122 | } 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/CobarSqlMapClientTemplateWithCustomMergerTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client; 2 | 3 | import static org.testng.AssertJUnit.assertEquals; 4 | import static org.testng.AssertJUnit.assertTrue; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import java.util.Comparator; 9 | import java.util.Date; 10 | import java.util.List; 11 | 12 | import org.springframework.orm.ibatis.SqlMapClientTemplate; 13 | import org.testng.annotations.Test; 14 | 15 | import com.alibaba.cobar.client.entities.Offer; 16 | import com.alibaba.cobar.client.support.utils.CollectionUtils; 17 | import com.alibaba.cobar.client.support.vo.BatchInsertTask; 18 | 19 | public class CobarSqlMapClientTemplateWithCustomMergerTest extends AbstractTestNGCobarClientTest { 20 | 21 | public CobarSqlMapClientTemplateWithCustomMergerTest() { 22 | super(new String[] { "META-INF/spring/datasources-appctx.xml", 23 | "META-INF/spring/cobar-client-appctx.xml", 24 | "META-INF/spring/cobar-client-custom-merger-appctx.xml" }); 25 | } 26 | 27 | @Test 28 | public void testQueryForListWithCustomMerger() { 29 | batchInsertOffersAsFixture(); 30 | 31 | SqlMapClientTemplate st = (SqlMapClientTemplate) getApplicationContext().getBean( 32 | "sqlMapClientTemplateWithMerger"); 33 | @SuppressWarnings("unchecked") 34 | List lst = st 35 | .queryForList("com.alibaba.cobar.client.entities.Offer.findAllWithOrderByOnSubject"); 36 | assertTrue(CollectionUtils.isNotEmpty(lst)); 37 | assertEquals(5, lst.size()); 38 | 39 | verifyOffersOrderBySubject(lst); 40 | 41 | } 42 | 43 | @SuppressWarnings("unchecked") 44 | private void verifyOffersOrderBySubject(List lst) { 45 | for (int i = 0; i < lst.size(); i++) { 46 | Offer offer = (Offer) lst.get(i); 47 | if (i == 0 || i == 1) { 48 | assertEquals(2, offer.getMemberId().longValue()); 49 | } else { 50 | assertEquals(1, offer.getMemberId().longValue()); 51 | } 52 | switch (i) { 53 | case 0: 54 | assertEquals("A", offer.getSubject()); 55 | break; 56 | case 1: 57 | assertEquals("D", offer.getSubject()); 58 | break; 59 | case 2: 60 | assertEquals("S", offer.getSubject()); 61 | break; 62 | case 3: 63 | assertEquals("X", offer.getSubject()); 64 | break; 65 | case 4: 66 | assertEquals("Z", offer.getSubject()); 67 | break; 68 | default: 69 | throw new IllegalArgumentException("unexpected condition."); 70 | } 71 | } 72 | } 73 | 74 | @Test 75 | @SuppressWarnings("unchecked") 76 | public void testQueryForListWithoutCustomMerger() { 77 | batchInsertOffersAsFixture(); 78 | 79 | List lst = getSqlMapClientTemplate().queryForList( 80 | "com.alibaba.cobar.client.entities.Offer.findAllWithOrderByOnSubject"); 81 | 82 | assertTrue(CollectionUtils.isNotEmpty(lst)); 83 | // contains all of the entities, but the order is not guaranteed. 84 | assertEquals(5, lst.size()); 85 | 86 | // sort in application code 87 | Comparator comparator = (Comparator) getApplicationContext().getBean( 88 | "comparator"); 89 | Collections.sort(lst, comparator); 90 | verifyOffersOrderBySubject(lst); 91 | } 92 | 93 | private void batchInsertOffersAsFixture() { 94 | BatchInsertTask task = new BatchInsertTask(); 95 | 96 | List offers = new ArrayList(); 97 | Offer offer = new Offer(); 98 | offer.setMemberId(1L); 99 | offer.setSubject("Z"); 100 | offer.setGmtUpdated(new Date()); 101 | offers.add(offer); 102 | 103 | offer = new Offer(); 104 | offer.setMemberId(1L); 105 | offer.setSubject("X"); 106 | offer.setGmtUpdated(new Date()); 107 | offers.add(offer); 108 | 109 | offer = new Offer(); 110 | offer.setMemberId(1L); 111 | offer.setSubject("S"); 112 | offer.setGmtUpdated(new Date()); 113 | offers.add(offer); 114 | 115 | offer = new Offer(); 116 | offer.setMemberId(2L); 117 | offer.setSubject("D"); 118 | offer.setGmtUpdated(new Date()); 119 | offers.add(offer); 120 | 121 | offer = new Offer(); 122 | offer.setMemberId(2L); 123 | offer.setSubject("A"); 124 | offer.setGmtUpdated(new Date()); 125 | offers.add(offer); 126 | 127 | task.setEntities(offers); 128 | 129 | getSqlMapClientTemplate().insert("com.alibaba.cobar.client.entities.Offer.batchInsert", 130 | task); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/CobarTestNGTestsRunner.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.apache.log4j.BasicConfigurator; 7 | import org.apache.log4j.Level; 8 | import org.apache.log4j.Logger; 9 | import org.testng.TestNG; 10 | 11 | public class CobarTestNGTestsRunner { 12 | 13 | /** 14 | * @param args 15 | */ 16 | public static void main(String[] args) { 17 | BasicConfigurator.configure(); 18 | Logger.getRootLogger().setLevel(Level.INFO); 19 | 20 | TestNG testng = new TestNG(); 21 | 22 | List suites = new ArrayList(); 23 | suites.add("src/test/resources/testng.xml"); 24 | testng.setTestSuites(suites); 25 | testng.setOutputDirectory("target/test-output"); 26 | testng.run(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/entities/Follower.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.entities; 2 | 3 | public class Follower { 4 | private Long id; 5 | private String name; 6 | 7 | public Follower(){} 8 | public Follower(String name) 9 | { 10 | this.name = name; 11 | } 12 | 13 | public Long getId() { 14 | return id; 15 | } 16 | public void setId(Long id) { 17 | this.id = id; 18 | } 19 | public String getName() { 20 | return name; 21 | } 22 | public void setName(String name) { 23 | this.name = name; 24 | } 25 | @Override 26 | public int hashCode() { 27 | final int prime = 31; 28 | int result = 1; 29 | result = prime * result + ((id == null) ? 0 : id.hashCode()); 30 | result = prime * result + ((name == null) ? 0 : name.hashCode()); 31 | return result; 32 | } 33 | @Override 34 | public boolean equals(Object obj) { 35 | if (this == obj) 36 | return true; 37 | if (obj == null) 38 | return false; 39 | if (getClass() != obj.getClass()) 40 | return false; 41 | Follower other = (Follower) obj; 42 | if (id == null) { 43 | if (other.id != null) 44 | return false; 45 | } else if (!id.equals(other.id)) 46 | return false; 47 | if (name == null) { 48 | if (other.name != null) 49 | return false; 50 | } else if (!name.equals(other.name)) 51 | return false; 52 | return true; 53 | } 54 | @Override 55 | public String toString() { 56 | return "Follower [id=" + id + ", name=" + name + "]"; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/entities/Offer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.entities; 2 | 3 | import java.util.Date; 4 | 5 | public class Offer { 6 | private Long id; 7 | private Long memberId; 8 | private String subject; 9 | private Date gmtUpdated = new Date(); 10 | 11 | public Long getId() { 12 | return id; 13 | } 14 | 15 | public void setId(Long id) { 16 | this.id = id; 17 | } 18 | 19 | public Long getMemberId() { 20 | return memberId; 21 | } 22 | 23 | public void setMemberId(Long memberId) { 24 | this.memberId = memberId; 25 | } 26 | 27 | public String getSubject() { 28 | return subject; 29 | } 30 | 31 | public void setSubject(String subject) { 32 | this.subject = subject; 33 | } 34 | 35 | public Date getGmtUpdated() { 36 | return gmtUpdated; 37 | } 38 | 39 | public void setGmtUpdated(Date gmtUpdated) { 40 | this.gmtUpdated = gmtUpdated; 41 | } 42 | 43 | @Override 44 | public int hashCode() { 45 | final int prime = 31; 46 | int result = 1; 47 | result = prime * result + ((gmtUpdated == null) ? 0 : gmtUpdated.hashCode()); 48 | result = prime * result + ((id == null) ? 0 : id.hashCode()); 49 | result = prime * result + ((memberId == null) ? 0 : memberId.hashCode()); 50 | result = prime * result + ((subject == null) ? 0 : subject.hashCode()); 51 | return result; 52 | } 53 | 54 | @Override 55 | public boolean equals(Object obj) { 56 | if (this == obj) 57 | return true; 58 | if (obj == null) 59 | return false; 60 | if (getClass() != obj.getClass()) 61 | return false; 62 | Offer other = (Offer) obj; 63 | if (gmtUpdated == null) { 64 | if (other.gmtUpdated != null) 65 | return false; 66 | } else if (!gmtUpdated.equals(other.gmtUpdated)) 67 | return false; 68 | if (id == null) { 69 | if (other.id != null) 70 | return false; 71 | } else if (!id.equals(other.id)) 72 | return false; 73 | if (memberId == null) { 74 | if (other.memberId != null) 75 | return false; 76 | } else if (!memberId.equals(other.memberId)) 77 | return false; 78 | if (subject == null) { 79 | if (other.subject != null) 80 | return false; 81 | } else if (!subject.equals(other.subject)) 82 | return false; 83 | return true; 84 | } 85 | 86 | @Override 87 | public String toString() { 88 | return "Offer [gmtUpdated=" + gmtUpdated + ", id=" + id + ", memberId=" + memberId 89 | + ", subject=" + subject + "]"; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/entities/Tweet.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.entities; 2 | 3 | public class Tweet { 4 | private Long id; 5 | private String tweet; 6 | 7 | public Tweet(){} 8 | 9 | public Tweet(String t){ 10 | tweet = t; 11 | } 12 | 13 | public Long getId() { 14 | return id; 15 | } 16 | public void setId(Long id) { 17 | this.id = id; 18 | } 19 | public String getTweet() { 20 | return tweet; 21 | } 22 | public void setTweet(String tweet) { 23 | this.tweet = tweet; 24 | } 25 | 26 | @Override 27 | public int hashCode() { 28 | final int prime = 31; 29 | int result = 1; 30 | result = prime * result + ((id == null) ? 0 : id.hashCode()); 31 | result = prime * result + ((tweet == null) ? 0 : tweet.hashCode()); 32 | return result; 33 | } 34 | 35 | @Override 36 | public boolean equals(Object obj) { 37 | if (this == obj) 38 | return true; 39 | if (obj == null) 40 | return false; 41 | if (getClass() != obj.getClass()) 42 | return false; 43 | Tweet other = (Tweet) obj; 44 | if (id == null) { 45 | if (other.id != null) 46 | return false; 47 | } else if (!id.equals(other.id)) 48 | return false; 49 | if (tweet == null) { 50 | if (other.tweet != null) 51 | return false; 52 | } else if (!tweet.equals(other.tweet)) 53 | return false; 54 | return true; 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return "Tweet [id=" + id + ", tweet=" + tweet + "]"; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/merger/ConcurrentSortMergerTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.merger; 2 | 3 | import static org.testng.AssertJUnit.assertEquals; 4 | import static org.testng.AssertJUnit.assertTrue; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.Comparator; 9 | import java.util.List; 10 | 11 | import org.testng.annotations.Test; 12 | 13 | @Test 14 | public class ConcurrentSortMergerTest { 15 | 16 | public void testMerge() throws Exception{ 17 | ConcurrentSortMerger merger = new ConcurrentSortMerger(); 18 | merger.setComparator(new Comparator() { 19 | public int compare(Integer o1, Integer o2) { 20 | return o1.intValue() - o2.intValue(); 21 | } 22 | }); 23 | merger.afterPropertiesSet(); 24 | List> entities = new ArrayList>(); 25 | entities.add(Arrays.asList(1, 2, 4)); 26 | entities.add(Arrays.asList(3, 5, 8, 10)); 27 | List result = merger.merge(entities); 28 | assertEquals(7, result.size()); 29 | assertTrue(Arrays.equals(new Integer[]{1,2,3,4,5,8,10}, result.toArray(new Integer[result.size()]))); 30 | merger.destroy(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/router/config/abnormal_rule_fixture1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.alibaba.cobar.client.entity.Follower 4 | id>10000 and id< 20000 5 | 6 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/router/config/abnormal_rule_fixture2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | id>10000 and id< 20000 4 | p1, p2 5 | 6 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/router/config/abnormal_rule_fixture3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.alibaba.cobar.client.entity.Follower 4 | com.alibaba.cobar.client.entity.Follower.create 5 | id>10000 and id< 20000 6 | p1, p2 7 | 8 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/router/config/abnormal_rule_fixture4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.alibaba.cobar.client.entity.Follower 4 | com.alibaba.cobar.client.entity.Follower.create 5 | id>10000 and id< 20000 6 | p1, p2 7 | 8 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/router/config/normal_rule_fixture.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.alibaba.cobar.client.entity.Follower 4 | partition1 5 | 6 | 7 | com.alibaba.cobar.client.entity.Follower.create 8 | p1, p2 9 | 10 | 11 | com.alibaba.cobar.client.entity.Follower.create 12 | id>10000 and id< 20000 13 | p1, p2 14 | 15 | 16 | com.alibaba.cobar.client.entity.Follower 17 | id>10000 and id< 20000 18 | p1, p2 19 | 20 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/router/config/normal_rule_fixture2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.alibaba.cobar.client.entity.Follower 4 | partition1 5 | 6 | 7 | com.alibaba.cobar.client.entity.Follower.create 8 | p1, p2 9 | 10 | 11 | com.alibaba.cobar.client.entity.Follower.create 12 | id>10000 and id< 20000 13 | p1, p2 14 | 15 | 16 | com.alibaba.cobar.client.entity.Follower 17 | id>10000 and id< 20000 18 | p1, p2 19 | 20 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/router/config/normal_rule_fixture3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.alibaba.cobar.client.entity.Follower 4 | partition1 5 | 6 | 7 | com.alibaba.cobar.client.entity.Follower.create 8 | p1, p2 9 | 10 | 11 | com.alibaba.cobar.client.entity.Follower.create 12 | id>10000 and id< 20000 13 | p1, p2 14 | 15 | 16 | com.alibaba.cobar.client.entity.Tweet 17 | id>10000 and id< 20000 18 | p1, p2 19 | 20 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/router/rules/IBatisNamespaceRuleTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.router.rules; 2 | 3 | import static org.testng.AssertJUnit.assertEquals; 4 | import static org.testng.AssertJUnit.assertFalse; 5 | import static org.testng.AssertJUnit.assertNotNull; 6 | import static org.testng.AssertJUnit.assertTrue; 7 | import static org.testng.AssertJUnit.fail; 8 | 9 | import java.util.List; 10 | 11 | import org.testng.annotations.Test; 12 | 13 | import com.alibaba.cobar.client.router.rules.ibatis.IBatisNamespaceRule; 14 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 15 | import com.alibaba.cobar.client.support.utils.CollectionUtils; 16 | 17 | @Test 18 | public class IBatisNamespaceRuleTest{ 19 | public void testNamespaceRuleNormally() { 20 | IBatisNamespaceRule rule = new IBatisNamespaceRule("com.alibaba.cobar.client.entity.Tweet", 21 | "p1, p2"); 22 | List shardIds = rule.action(); 23 | assertNotNull(shardIds); 24 | assertEquals(2, shardIds.size()); 25 | 26 | IBatisRoutingFact fact = new IBatisRoutingFact( 27 | "com.alibaba.cobar.client.entity.Tweet.update", null); 28 | assertTrue(rule.isDefinedAt(fact)); 29 | fact = new IBatisRoutingFact("com.alibaba.cobar.client.entity.Tweet.delete", null); 30 | assertTrue(rule.isDefinedAt(fact)); 31 | fact = new IBatisRoutingFact("com.alibaba.cobar.client.entity.Twet.delete", null); 32 | assertFalse(rule.isDefinedAt(fact)); 33 | } 34 | 35 | public void testNamespaceRuleNormallyWithCustomActionPatternSeparator() { 36 | IBatisNamespaceRule rule = new IBatisNamespaceRule("com.alibaba.cobar.client.entity.Tweet", 37 | "p1, p2"); 38 | rule.setActionPatternSeparator(";"); 39 | List shards = rule.action(); 40 | assertTrue(CollectionUtils.isNotEmpty(shards)); 41 | assertEquals(1, shards.size()); 42 | 43 | rule = new IBatisNamespaceRule("com.alibaba.cobar.client.entity.Tweet", "p1; p2"); 44 | rule.setActionPatternSeparator(";"); 45 | shards = null; 46 | shards = rule.action(); 47 | assertTrue(CollectionUtils.isNotEmpty(shards)); 48 | assertEquals(2, shards.size()); 49 | 50 | IBatisRoutingFact fact = new IBatisRoutingFact( 51 | "com.alibaba.cobar.client.entity.Tweet.update", null); 52 | assertTrue(rule.isDefinedAt(fact)); 53 | fact = new IBatisRoutingFact("com.alibaba.cobar.client.entity.Tweet.delete", null); 54 | assertTrue(rule.isDefinedAt(fact)); 55 | fact = new IBatisRoutingFact("com.alibaba.cobar.client.entity.Twet.delete", null); 56 | assertFalse(rule.isDefinedAt(fact)); 57 | } 58 | 59 | public void testNamespaceRuleAbnormally() { 60 | try { 61 | new IBatisNamespaceRule("", ""); 62 | fail(); 63 | } catch (IllegalArgumentException e) { 64 | // pass 65 | } 66 | 67 | try { 68 | new IBatisNamespaceRule("", null); 69 | fail(); 70 | } catch (IllegalArgumentException e) { 71 | // pass 72 | } 73 | 74 | try { 75 | new IBatisNamespaceRule(null, ""); 76 | fail(); 77 | } catch (IllegalArgumentException e) { 78 | // pass 79 | } 80 | 81 | try { 82 | new IBatisNamespaceRule(null, null); 83 | fail(); 84 | } catch (IllegalArgumentException e) { 85 | // pass 86 | } 87 | 88 | IBatisNamespaceRule rule = new IBatisNamespaceRule("com.alibaba.cobar.client.entity.Tweet", 89 | "p1, p2"); 90 | try { 91 | rule.setActionPatternSeparator(null); 92 | } catch (IllegalArgumentException e) { 93 | // pass 94 | } 95 | 96 | try { 97 | rule.isDefinedAt(null); 98 | fail(); 99 | } catch (IllegalArgumentException e) { 100 | // pass 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/router/rules/IBatisSqlActionRuleTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.router.rules; 2 | 3 | import static org.testng.AssertJUnit.assertEquals; 4 | import static org.testng.AssertJUnit.assertFalse; 5 | import static org.testng.AssertJUnit.assertTrue; 6 | import static org.testng.AssertJUnit.fail; 7 | 8 | import java.util.List; 9 | 10 | import org.apache.commons.lang.ArrayUtils; 11 | import org.testng.annotations.AfterMethod; 12 | import org.testng.annotations.BeforeMethod; 13 | import org.testng.annotations.Test; 14 | 15 | import com.alibaba.cobar.client.router.rules.ibatis.IBatisSqlActionRule; 16 | import com.alibaba.cobar.client.router.support.IBatisRoutingFact; 17 | import com.alibaba.cobar.client.support.utils.CollectionUtils; 18 | @Test 19 | public class IBatisSqlActionRuleTest { 20 | public static final String SQL_MAP_ACTION_ID = "com.alibaba.cobar.client.entity.Tweet.delete"; 21 | public static final String[] EXPECTED_SHARDS = { "shard1", "shard2", "shard3" }; 22 | 23 | private IBatisSqlActionRule rule; 24 | 25 | @BeforeMethod 26 | protected void setUp() throws Exception { 27 | rule = new IBatisSqlActionRule(SQL_MAP_ACTION_ID, "shard1, shard2, shard3"); 28 | } 29 | 30 | @AfterMethod 31 | protected void tearDown() throws Exception { 32 | rule = null; 33 | } 34 | 35 | public void testSqlActionRuleOnShardIdsNormally() { 36 | List shards = rule.action(); 37 | assertTrue(CollectionUtils.isNotEmpty(shards)); 38 | assertEquals(3, shards.size()); 39 | 40 | for (String shard : shards) { 41 | assertTrue(ArrayUtils.contains(EXPECTED_SHARDS, shard)); 42 | } 43 | } 44 | 45 | public void testSqlActionRuleOnShardIdsAbnormally() { 46 | try { 47 | new IBatisSqlActionRule(SQL_MAP_ACTION_ID, ""); 48 | } catch (IllegalArgumentException e) { 49 | // pass 50 | } 51 | 52 | try { 53 | new IBatisSqlActionRule(SQL_MAP_ACTION_ID, null); 54 | } catch (IllegalArgumentException e) { 55 | // pass 56 | } 57 | } 58 | 59 | public void testSqlActionRuleOnShardIdsWithCustomActionPatternSeparatorNormally() { 60 | rule.setActionPatternSeparator(";"); 61 | List shards = rule.action(); 62 | assertTrue(CollectionUtils.isNotEmpty(shards)); 63 | assertEquals(1, shards.size()); 64 | assertEquals("shard1, shard2, shard3", shards.get(0)); 65 | 66 | rule = new IBatisSqlActionRule(SQL_MAP_ACTION_ID, "shard1; shard2; shard3"); 67 | rule.setActionPatternSeparator(";"); 68 | shards = null; 69 | shards = rule.action(); 70 | assertTrue(CollectionUtils.isNotEmpty(shards)); 71 | assertEquals(3, shards.size()); 72 | 73 | for (String shard : shards) { 74 | assertTrue(ArrayUtils.contains(EXPECTED_SHARDS, shard)); 75 | } 76 | } 77 | 78 | public void testSqlActionRuleOnShardIdsWithCustomActionPatternSeparatorAbnormally() { 79 | try { 80 | rule.setActionPatternSeparator(null); 81 | } catch (IllegalArgumentException e) { 82 | // pass 83 | } 84 | } 85 | 86 | public void testSqlActionRuleOnTypePatternNormally() { 87 | IBatisRoutingFact fact = new IBatisRoutingFact(SQL_MAP_ACTION_ID, null); 88 | assertTrue(rule.isDefinedAt(fact)); 89 | 90 | fact = new IBatisRoutingFact("com.alibaba.cobar.client.entity.Tweet.del", null); 91 | assertFalse(rule.isDefinedAt(fact)); 92 | 93 | fact = new IBatisRoutingFact("com.alibaba.cobar.client.entity.Tweet", null); 94 | assertFalse(rule.isDefinedAt(fact)); 95 | 96 | fact = new IBatisRoutingFact(null, null); 97 | assertFalse(rule.isDefinedAt(fact)); 98 | } 99 | 100 | public void testSqlActionRuleOnTypePatternAbnormally(){ 101 | try{ 102 | rule.isDefinedAt(null); 103 | fail(); 104 | } 105 | catch(IllegalArgumentException e) 106 | { 107 | // pass 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/router/rules/support/IFunction2.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.router.rules.support; 2 | 3 | public interface IFunction2 { 4 | O apply(I input); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/router/rules/support/ModFunction.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.router.rules.support; 2 | 3 | import org.apache.commons.lang.Validate; 4 | 5 | public class ModFunction implements IFunction2 { 6 | private Long modDenominator; 7 | 8 | public ModFunction(Long modDenominator) 9 | { 10 | Validate.notNull(modDenominator); 11 | this.modDenominator = modDenominator; 12 | } 13 | 14 | public Long apply(Long input) { 15 | Validate.notNull(input); 16 | 17 | Long result = input % this.modDenominator; 18 | return result; 19 | } 20 | 21 | public void setModDenominator(Long modDenominator) { 22 | Validate.notNull(modDenominator); 23 | this.modDenominator = modDenominator; 24 | } 25 | 26 | public Long getModDenominator() { 27 | return modDenominator; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/support/OfferComparator.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.support; 2 | 3 | import java.util.Comparator; 4 | 5 | import com.alibaba.cobar.client.entities.Offer; 6 | 7 | public class OfferComparator implements Comparator { 8 | 9 | public int compare(Offer offer1, Offer offer2) { 10 | return offer1.getSubject().compareTo(offer2.getSubject()); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/test/services/AbnormalOfferService.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.test.services; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.transaction.annotation.Transactional; 6 | 7 | import com.alibaba.cobar.client.entities.Offer; 8 | import com.alibaba.cobar.client.support.vo.BatchInsertTask; 9 | 10 | public class AbnormalOfferService extends NormalOfferService { 11 | @Transactional 12 | public void createOffersInBatch(List offers) { 13 | getSqlMapClientTemplate().insert("com.alibaba.cobar.client.entities.Offer.batchInsert", new BatchInsertTask(offers)); 14 | throw new RuntimeException("exception to trigger rollback"); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/test/services/AbstractOfferService.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.test.services; 2 | 3 | import org.springframework.orm.ibatis.SqlMapClientTemplate; 4 | 5 | public abstract class AbstractOfferService implements IOfferService { 6 | private SqlMapClientTemplate sqlMapClientTemplate; 7 | 8 | public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) { 9 | this.sqlMapClientTemplate = sqlMapClientTemplate; 10 | } 11 | 12 | public SqlMapClientTemplate getSqlMapClientTemplate() { 13 | return sqlMapClientTemplate; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/test/services/IOfferService.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.test.services; 2 | 3 | import java.util.List; 4 | 5 | import com.alibaba.cobar.client.entities.Offer; 6 | 7 | public interface IOfferService { 8 | 9 | void createOffersInBatch(List offers); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/test/services/NormalOfferService.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.test.services; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.transaction.annotation.Transactional; 6 | 7 | import com.alibaba.cobar.client.entities.Offer; 8 | import com.alibaba.cobar.client.support.vo.BatchInsertTask; 9 | 10 | public class NormalOfferService extends AbstractOfferService { 11 | 12 | @Transactional 13 | public void createOffersInBatch(List offers) { 14 | getSqlMapClientTemplate().insert("com.alibaba.cobar.client.entities.Offer.batchInsert", new BatchInsertTask(offers)); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/cobar/client/transaction/MultipleDataSourcesTransactionManagerTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.cobar.client.transaction; 2 | 3 | import static org.testng.AssertJUnit.assertEquals; 4 | import static org.testng.AssertJUnit.assertNotNull; 5 | import static org.testng.AssertJUnit.assertNull; 6 | import static org.testng.AssertJUnit.assertTrue; 7 | import static org.testng.AssertJUnit.fail; 8 | 9 | import java.lang.reflect.Proxy; 10 | import java.util.ArrayList; 11 | import java.util.Date; 12 | import java.util.List; 13 | 14 | import org.springframework.transaction.PlatformTransactionManager; 15 | import org.springframework.transaction.TransactionStatus; 16 | import org.springframework.transaction.support.TransactionCallbackWithoutResult; 17 | import org.springframework.transaction.support.TransactionTemplate; 18 | import org.testng.annotations.Test; 19 | 20 | import com.alibaba.cobar.client.AbstractTestNGCobarClientTest; 21 | import com.alibaba.cobar.client.entities.Offer; 22 | import com.alibaba.cobar.client.test.services.IOfferService; 23 | 24 | /** 25 | * H2 In-Memory Database doesn't support transaction, so in this test case, we 26 | * need to turn to non-in-memory database to test the transaction.
27 | * 28 | * @author fujohnwang 29 | */ 30 | @Test(sequential=true) 31 | public class MultipleDataSourcesTransactionManagerTest extends AbstractTestNGCobarClientTest { 32 | 33 | String selectSqlActionTwo = "com.alibaba.cobar.client.entities.Offer.findByMemberId"; 34 | 35 | private Long[] memberIds = new Long[] { 1L, 129L, 257L, 2L, 130L, 36 | 258L, 386L }; 37 | 38 | public MultipleDataSourcesTransactionManagerTest() { 39 | super(new String[] { 40 | "META-INF/spring/cobar-client-appctx.xml", 41 | "META-INF/spring/datasources-appctx.xml", 42 | "META-INF/spring/namespace-sqlaction-composed-router-appctx.xml", 43 | "META-INF/spring/cobar-client-offer-services-appctx.xml" }); 44 | } 45 | 46 | public void testOfferCreationOnMultipleShardsWithTransactionRollback() { 47 | 48 | new TransactionTemplate(((PlatformTransactionManager) getApplicationContext() 49 | .getBean("transactionManager"))).execute(new TransactionCallbackWithoutResult() { 50 | @Override 51 | protected void doInTransactionWithoutResult(TransactionStatus status) { 52 | 53 | try { 54 | Offer offer = new Offer(); 55 | offer.setMemberId(1L); 56 | offer.setGmtUpdated(new Date()); 57 | offer.setSubject("o1"); 58 | getSqlMapClientTemplate().insert( 59 | "com.alibaba.cobar.client.entities.Offer.create", offer); 60 | 61 | offer = new Offer(); 62 | offer.setMemberId(2L); 63 | offer.setGmtUpdated(new Date()); 64 | offer.setSubject("o2"); 65 | getSqlMapClientTemplate().insert( 66 | "com.alibaba.cobar.client.entities.Offer.create", offer); 67 | 68 | } finally { 69 | status.setRollbackOnly(); 70 | } 71 | 72 | } 73 | }); 74 | 75 | Long[] mids = new Long[] { 1L, 2L }; 76 | for (Long mid : mids) { 77 | Offer parameter = new Offer(); 78 | parameter.setMemberId(mid); 79 | assertNull(getSqlMapClientTemplate().queryForObject(selectSqlActionTwo, parameter)); 80 | } 81 | } 82 | 83 | public void testOfferCreationOnMultipleShardsWithNormallyOfferService() { 84 | String selectSqlActionTwo = "com.alibaba.cobar.client.entities.Offer.findByMemberId"; 85 | 86 | for (Long mid : memberIds) { 87 | Offer parameter = new Offer(); 88 | parameter.setMemberId(mid); 89 | Offer offer = (Offer) getSqlMapClientTemplate().queryForObject(selectSqlActionTwo, 90 | parameter); 91 | assertNull(offer); 92 | } 93 | 94 | ((IOfferService) getApplicationContext().getBean("normalOfferService")) 95 | .createOffersInBatch(createOffersWithMemberIdsFrom(memberIds)); 96 | 97 | for (Long mid : memberIds) { 98 | Offer parameter = new Offer(); 99 | parameter.setMemberId(mid); 100 | Offer offer = (Offer) getSqlMapClientTemplate().queryForObject(selectSqlActionTwo, 101 | parameter); 102 | assertNotNull(offer); 103 | assertEquals(mid, offer.getMemberId()); 104 | } 105 | } 106 | 107 | /** 108 | * need data stores that support transaction to test this behavior. 109 | */ 110 | public void testOfferCreationOnMultipleShardsWithAbnormalOfferService() { 111 | String selectSqlActionTwo = "com.alibaba.cobar.client.entities.Offer.findByMemberId"; 112 | 113 | for (Long mid : memberIds) { 114 | Offer parameter = new Offer(); 115 | parameter.setMemberId(mid); 116 | Offer offer = (Offer) getSqlMapClientTemplate().queryForObject(selectSqlActionTwo, 117 | parameter); 118 | assertNull(offer); 119 | } 120 | 121 | try { 122 | Object offerService = getApplicationContext().getBean("abnormalOfferService"); 123 | assertTrue(offerService instanceof Proxy); 124 | ((IOfferService) offerService) 125 | .createOffersInBatch(createOffersWithMemberIdsFrom(memberIds)); 126 | fail(); 127 | } catch (RuntimeException e) { 128 | // pass 129 | } 130 | 131 | for (Long mid : memberIds) { 132 | Offer parameter = new Offer(); 133 | parameter.setMemberId(mid); 134 | assertNull(getSqlMapClientTemplate().queryForObject(selectSqlActionTwo, parameter)); 135 | } 136 | } 137 | 138 | public List createOffersWithMemberIdsFrom(Long[] mids) { 139 | List offers = new ArrayList(); 140 | for (Long mid : mids) { 141 | Offer offer = new Offer(); 142 | offer.setGmtUpdated(new Date()); 143 | offer.setMemberId(mid); 144 | offer.setSubject("anything"); 145 | offers.add(offer); 146 | } 147 | return offers; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/test/resources/testng-sequencial-tests.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/test/resources/testng.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | --------------------------------------------------------------------------------