content: package com.alibaba.cobar.client.transaction;
  
  import static org.testng.AssertJUnit.assertEquals;
  import static org.testng.AssertJUnit.assertNotNull;
  import static org.testng.AssertJUnit.assertNull;
  import static org.testng.AssertJUnit.assertTrue;
  import static org.testng.AssertJUnit.fail;
  
  import java.lang.reflect.Proxy;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.List;
  
  import org.springframework.transaction.PlatformTransactionManager;
  import org.springframework.transaction.TransactionStatus;
  import org.springframework.transaction.support.TransactionCallbackWithoutResult;
  import org.springframework.transaction.support.TransactionTemplate;
  import org.testng.annotations.Test;
  
  import com.alibaba.cobar.client.AbstractTestNGCobarClientTest;
  import com.alibaba.cobar.client.entities.Offer;
  import com.alibaba.cobar.client.test.services.IOfferService;
  
  /**
   * H2 In-Memory Database doesn't support transaction, so in this test case, we
   * need to turn to non-in-memory database to test the transaction.<br>
   * 
   * @author fujohnwang
   */
  @Test(sequential=true)
  public class MultipleDataSourcesTransactionManagerTest extends AbstractTestNGCobarClientTest {
  
      String                       selectSqlActionTwo    = "com.alibaba.cobar.client.entities.Offer.findByMemberId";
  
      private Long[]               memberIds             = new Long[] { 1L, 129L, 257L, 2L, 130L,
              258L, 386L                                };
  
      public MultipleDataSourcesTransactionManagerTest() {
          super(new String[] {
                  "META-INF/spring/cobar-client-appctx.xml",
                  "META-INF/spring/datasources-appctx.xml",
                  "META-INF/spring/namespace-sqlaction-composed-router-appctx.xml",
                  "META-INF/spring/cobar-client-offer-services-appctx.xml" });
      }
  
      public void testOfferCreationOnMultipleShardsWithTransactionRollback() {
  
          new TransactionTemplate(((PlatformTransactionManager) getApplicationContext()
                  .getBean("transactionManager"))).execute(new TransactionCallbackWithoutResult() {
              @Override
              protected void doInTransactionWithoutResult(TransactionStatus status) {
  
                  try {
                      Offer offer = new Offer();
                      offer.setMemberId(1L);
                      offer.setGmtUpdated(new Date());
                      offer.setSubject("o1");
                      getSqlMapClientTemplate().insert(
                              "com.alibaba.cobar.client.entities.Offer.create", offer);
  
                      offer = new Offer();
                      offer.setMemberId(2L);
                      offer.setGmtUpdated(new Date());
                      offer.setSubject("o2");
                      getSqlMapClientTemplate().insert(
                              "com.alibaba.cobar.client.entities.Offer.create", offer);
  
                  } finally {
                      status.setRollbackOnly();
                  }
  
              }
          });
  
          Long[] mids = new Long[] { 1L, 2L };
          for (Long mid : mids) {
              Offer parameter = new Offer();
              parameter.setMemberId(mid);
              assertNull(getSqlMapClientTemplate().queryForObject(selectSqlActionTwo, parameter));
          }
      }
  
      public void testOfferCreationOnMultipleShardsWithNormallyOfferService() {
          String selectSqlActionTwo = "com.alibaba.cobar.client.entities.Offer.findByMemberId";
  
          for (Long mid : memberIds) {
              Offer parameter = new Offer();
              parameter.setMemberId(mid);
              Offer offer = (Offer) getSqlMapClientTemplate().queryForObject(selectSqlActionTwo,
                      parameter);
              assertNull(offer);
          }
  
          ((IOfferService) getApplicationContext().getBean("normalOfferService"))
                  .createOffersInBatch(createOffersWithMemberIdsFrom(memberIds));
  
          for (Long mid : memberIds) {
              Offer parameter = new Offer();
              parameter.setMemberId(mid);
              Offer offer = (Offer) getSqlMapClientTemplate().queryForObject(selectSqlActionTwo,
                      parameter);
              assertNotNull(offer);
              assertEquals(mid, offer.getMemberId());
          }
      }
  
      /**
       * need data stores that support transaction to test this behavior.
       */
      public void testOfferCreationOnMultipleShardsWithAbnormalOfferService() {
          String selectSqlActionTwo = "com.alibaba.cobar.client.entities.Offer.findByMemberId";
  
          for (Long mid : memberIds) {
              Offer parameter = new Offer();
              parameter.setMemberId(mid);
              Offer offer = (Offer) getSqlMapClientTemplate().queryForObject(selectSqlActionTwo,
                      parameter);
              assertNull(offer);
          }
  
          try {
              Object offerService = getApplicationContext().getBean("abnormalOfferService");
              assertTrue(offerService instanceof Proxy);
              ((IOfferService) offerService)
                      .createOffersInBatch(createOffersWithMemberIdsFrom(memberIds));
              fail();
          } catch (RuntimeException e) {
              // pass
          }
  
          for (Long mid : memberIds) {
              Offer parameter = new Offer();
              parameter.setMemberId(mid);
              assertNull(getSqlMapClientTemplate().queryForObject(selectSqlActionTwo, parameter));
          }
      }
  
      public List<Offer> createOffersWithMemberIdsFrom(Long[] mids) {
          List<Offer> offers = new ArrayList<Offer>();
          for (Long mid : mids) {
              Offer offer = new Offer();
              offer.setGmtUpdated(new Date());
              offer.setMemberId(mid);
              offer.setSubject("anything");
              offers.add(offer);
          }
          return offers;
      }
  }
  