/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
/*
 * CacheJUnitTest.java JUnit based test
 *
 * Created on March 28, 2005, 10:59 AM
 */
package org.apache.geode.internal.jta.functional;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.sql.DataSource;
import javax.transaction.UserTransaction;

import org.apache.logging.log4j.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheException;
import org.apache.geode.cache.CacheExistsException;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.CacheLoader;
import org.apache.geode.cache.CacheLoaderException;
import org.apache.geode.cache.LoaderHelper;
import org.apache.geode.cache.Region;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.internal.jta.CacheUtils;
import org.apache.geode.internal.jta.JTAUtils;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.test.junit.categories.IntegrationTest;

/**
 * This JUnit version is created from class org.apache.geode.internal.jta.functional.CacheTest1.
 * Tests functional behavior. Assumes that CacheUtils.java always creates table(s) and inserts data
 * in the form: 1 => name1, 2 => name2, 3 => name3...as the values of ID and name fields
 * respectively. Test # 15 & 16 has the dependency to run on CloudScape database only due to
 * variations in DDL.
 *
 */
@Category(IntegrationTest.class)
public class CacheJUnitTest {

  private static final Logger logger = LogService.getLogger();

  private Region currRegion;
  private Cache cache;
  private int tblIDFld;
  private String tblNameFld;
  private String tblName;

  @Before
  public void setUp() throws Exception {
    this.tblName = CacheUtils.init("CacheJUnitTest");
    assertFalse(this.tblName == null || this.tblName.equals(""));

    this.cache = CacheUtils.getCache();
    assertNotNull(this.cache);

    this.currRegion = this.cache.getRegion("root");
    assertTrue(this.currRegion.getFullPath().equals("/root"));
  }

  @After
  public void tearDown() throws java.lang.Exception {
    try {
      CacheUtils.closeCache();
      CacheUtils.destroyTable(this.tblName);
    } finally {
      InternalDistributedSystem ids = InternalDistributedSystem.getAnyInstance();
      if (ids != null) {
        ids.disconnect();
      }
    }
  }

  /**
   * Test of testScenario1 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Tests a simple User Transaction with Cache lookup.
   */
  @Test
  public void testScenario1() throws Exception {
    this.tblIDFld = 1;
    this.tblNameFld = "test1";
    JTAUtils jtaObj = new JTAUtils(cache, currRegion);

    jtaObj.deleteRows(this.tblName);

    Context ctx = cache.getJNDIContext();
    UserTransaction ta = (UserTransaction) ctx.lookup("java:/UserTransaction");
    Connection conn = null;

    try {
      ta.begin();

      DataSource da = (DataSource) ctx.lookup("java:/XAPooledDataSource");

      conn = da.getConnection();

      Statement stmt = conn.createStatement();

      String sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);

      stmt.close();
      ta.commit();
      conn.close();
    } catch (NamingException e) {
      ta.rollback();
      fail(" failed " + e.getMessage());
    } catch (SQLException e) {
      ta.rollback();
      fail(" failed " + e.getMessage());
    } catch (Exception e) {
      ta.rollback();
      fail(" failed " + e.getMessage());
    } finally {
      if (conn != null)
        try {
          conn.close();
        } catch (SQLException ex) {
          fail("SQL exception: " + ex.getMessage());
        }
    }
  }

  /**
   * Test of testScenario2 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Tests a simple User Transaction with Cache lookup but closing the Connection object before
   * committing the Transaction.
   */
  @Test
  public void testScenario2() throws Exception {
    this.tblIDFld = 2;
    this.tblNameFld = "test2";
    boolean rollback_chances = true;

    JTAUtils jtaObj = new JTAUtils(cache, currRegion);

    jtaObj.deleteRows(this.tblName);

    Context ctx = cache.getJNDIContext();
    System.out.print(" looking up UserTransaction... ");
    UserTransaction ta = (UserTransaction) ctx.lookup("java:/UserTransaction");
    Connection conn = null;

    try {
      ta.begin();

      DataSource da = (DataSource) ctx.lookup("java:/XAPooledDataSource");

      conn = da.getConnection();

      Statement stmt = conn.createStatement();

      String sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);

      stmt.close();
      conn.close();
      ta.commit();

      rollback_chances = false;

      int ifAnyRows = jtaObj.getRows(this.tblName);
      if (ifAnyRows == 0) {
        // no rows are there !!! failure :)
        fail(" no rows retrieved even after txn commit after conn close.");
      }

    } catch (NamingException e) {
      if (rollback_chances)
        ta.rollback();
      fail(" failed " + e.getMessage());
    } catch (SQLException e) {
      if (rollback_chances)
        ta.rollback();
      fail(" failed " + e.getMessage());
    } catch (Exception e) {
      ta.rollback();
      fail(" failed " + e.getMessage());
    } finally {
      if (conn != null)
        try {
          conn.close();
        } catch (SQLException e) {
        }
    }
  }

  /**
   * Test of testScenario3 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Tests whether a user transaction with cache lookup and with XAPooledDataSOurce supports Cache
   * put and get operations accordingly. Put and get are done within the transaction block and also
   * db updates are done. After committing we check whether commit is proper in db and also in
   * Cache.
   */
  @Test
  public void testScenario3() throws Exception {
    this.tblIDFld = 3;
    this.tblNameFld = "test3";
    boolean rollback_chances = true;
    final String DEFAULT_RGN = "root";

    JTAUtils jtaObj = new JTAUtils(cache, currRegion);

    jtaObj.deleteRows(this.tblName);

    Context ctx = cache.getJNDIContext();
    UserTransaction ta = (UserTransaction) ctx.lookup("java:/UserTransaction");
    Connection conn = null;

    try {
      /** begin the transaction **/
      ta.begin();

      String current_region = jtaObj.currRegion.getName();
      assertEquals("the default region is not root", DEFAULT_RGN, current_region);

      jtaObj.getRegionFromCache("region1");

      String current_fullpath = jtaObj.currRegion.getFullPath();
      assertEquals("failed retrieving current region fullpath", "/" + DEFAULT_RGN + "/region1",
          current_fullpath);

      jtaObj.put("key1", "value1");

      String str = jtaObj.get("key1");
      String tok = jtaObj.parseGetValue(str);
      assertEquals("get failed for corresponding put", "\"value1\"", tok);

      current_fullpath = jtaObj.currRegion.getFullPath();
      assertEquals("failed retrieving current region fullpath", "/" + DEFAULT_RGN + "/region1",
          current_fullpath);

      DataSource da = (DataSource) ctx.lookup("java:/XAPooledDataSource");

      conn = da.getConnection();

      Statement stmt = conn.createStatement();

      String sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);

      stmt.close();
      ta.commit();
      conn.close();

      rollback_chances = false;

      current_fullpath = jtaObj.currRegion.getFullPath();
      assertEquals("failed retrieving current region fullpath after txn commit",
          "/" + DEFAULT_RGN + "/region1", current_fullpath);

      int ifAnyRows = jtaObj.getRows(this.tblName);
      assertEquals("rows retrieved is:" + ifAnyRows, 1, ifAnyRows);
      /*
       * if (ifAnyRows == 0) { fail (" DB FAILURE: no rows retrieved even after txn commit."); }
       */
      // after jdbc commit cache value in region1 for key1 must retain...
      str = jtaObj.get("key1");
      tok = jtaObj.parseGetValue(str);
      assertEquals("cache put didn't commit, value retrieved is: " + tok, "\"value1\"", tok);
    } catch (CacheExistsException e) {
      ta.rollback();
      fail(" test 3 failed ");
    } catch (NamingException e) {
      if (rollback_chances)
        ta.rollback();
      fail(" test 3 failed " + e.getMessage());
    } catch (SQLException e) {
      if (rollback_chances)
        ta.rollback();
      fail(" test 3 failed " + e.getMessage());
    } catch (Exception e) {
      if (rollback_chances)
        ta.rollback();
      fail(" test 3 failed " + e.getMessage());
    } finally {
      if (conn != null)
        try {
          conn.close();
        } catch (SQLException e) {
        }
    }
  }

  /**
   * Test of testScenario4 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Tests whether a user transaction with cache lookup and with XAPooledDataSOurce supports Cache
   * put and get operations accordingly along with JTA behavior. Put and get are done within the
   * transaction block and also db updates are done. After rollback the transaction explicitly we
   * check whether it was proper in db and also in Cache, which should also rollback.
   */
  @Test
  public void testScenario4() throws Exception {
    this.tblIDFld = 4;
    this.tblNameFld = "test4";
    boolean rollback_chances = true;
    final String DEFAULT_RGN = "root";

    JTAUtils jtaObj = new JTAUtils(cache, currRegion);

    jtaObj.deleteRows(this.tblName);

    Context ctx = cache.getJNDIContext();
    UserTransaction ta = (UserTransaction) ctx.lookup("java:/UserTransaction");
    Connection conn = null;

    try {
      String current_region = jtaObj.currRegion.getName();
      assertEquals("default region is not root", DEFAULT_RGN, current_region);

      jtaObj.getRegionFromCache("region1");
      String current_fullpath = jtaObj.currRegion.getFullPath();
      assertEquals(
          "failed retrieving current region fullpath after doing getRegionFromCache(region1)",
          "/" + DEFAULT_RGN + "/region1", current_fullpath);

      jtaObj.put("key1", "test");
      ta.begin();

      jtaObj.put("key1", "value1");
      String str = jtaObj.get("key1");
      String tok = jtaObj.parseGetValue(str);
      assertEquals("get value do not match with the put", "\"value1\"", tok);

      current_fullpath = jtaObj.currRegion.getFullPath();
      assertEquals("failed retrieving current region fullpath", "/" + DEFAULT_RGN + "/region1",
          current_fullpath);

      DataSource da = (DataSource) ctx.lookup("java:/XAPooledDataSource");

      conn = da.getConnection();
      Statement stmt = conn.createStatement();

      String sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);

      stmt.close();
      ta.rollback();
      conn.close();

      rollback_chances = false;

      current_fullpath = jtaObj.currRegion.getFullPath();
      assertEquals("failed retirieving current region fullpath after txn rollback",
          "/" + DEFAULT_RGN + "/region1", current_fullpath);

      int ifAnyRows = jtaObj.getRows(this.tblName);
      assertEquals("rows retrieved is: " + ifAnyRows, 0, ifAnyRows);
      /*
       * if (ifAnyRows != 0) { fail (" DB FAILURE"); }
       */
      str = jtaObj.get("key1");
      tok = jtaObj.parseGetValue(str);
      assertEquals("value existing in cache is: " + tok, "\"test\"", tok);
    } catch (CacheExistsException e) {
      ta.rollback();
      fail(" failed " + e.getMessage());
    } catch (NamingException e) {
      if (rollback_chances)
        ta.rollback();
      fail(" failed " + e.getMessage());
    } catch (SQLException e) {
      if (rollback_chances)
        ta.rollback();
      fail(" failed " + e.getMessage());
    } catch (Exception e) {
      if (rollback_chances)
        ta.rollback();
      fail(" failed " + e.getMessage());
    } finally {
      if (conn != null)
        try {
          conn.close();
        } catch (SQLException e) {
        }
    }
  }

  /**
   * Test of testScenario5 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Tests whether a user transaction with cache lookup and with XAPooledDataSOurce supports Cache
   * put and get operations accordingly along with JTA behavior. Put and get are done within the
   * transaction block and also db updates are done. We try to rollback the transaction by violating
   * primary key constraint in db table, nad then we check whether rollback was proper in db and
   * also in Cache, which should also rollback.
   */
  @Test
  public void testScenario5() throws Exception {
    this.tblIDFld = 5;
    this.tblNameFld = "test5";
    boolean rollback_chances = false;
    final String DEFAULT_RGN = "root";

    JTAUtils jtaObj = new JTAUtils(cache, currRegion);

    jtaObj.deleteRows(this.tblName);

    Context ctx = cache.getJNDIContext();
    UserTransaction ta = (UserTransaction) ctx.lookup("java:/UserTransaction");
    Connection conn = null;

    try {
      String current_region = jtaObj.currRegion.getName();
      assertEquals("default region is not root", DEFAULT_RGN, current_region);

      // trying to create a region 'region1' under /root, if it doesn't exist.
      // And point to the new region...
      jtaObj.getRegionFromCache("region1");

      // now current region should point to region1, as done from within
      // getRegionFromCache method...
      String current_fullpath = jtaObj.currRegion.getFullPath();
      assertEquals("failed retirieving current fullpath", "/" + DEFAULT_RGN + "/region1",
          current_fullpath);

      jtaObj.put("key1", "test");
      ta.begin();

      jtaObj.put("key1", "value1");

      String str = jtaObj.get("key1");
      String tok = jtaObj.parseGetValue(str);
      assertEquals("get value mismatch with put", "\"value1\"", tok);

      current_fullpath = jtaObj.currRegion.getFullPath();
      assertEquals("failed retrieving current fullpath, current fullpath: " + current_fullpath,
          "/" + DEFAULT_RGN + "/region1", current_fullpath);

      DataSource da = (DataSource) ctx.lookup("java:/XAPooledDataSource");

      conn = da.getConnection();
      Statement stmt = conn.createStatement();

      String sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);

      rollback_chances = true;

      // capable of throwing SQLException during insert operation
      sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);

      stmt.close();
      ta.commit();
      conn.close();
    } catch (CacheExistsException e) {
      ta.rollback();
      fail("test failed " + e.getMessage());
    } catch (NamingException e) {
      ta.rollback();
      fail("test failed " + e.getMessage());
    } catch (SQLException e) {
      // exception thrown during inserts are handeled as below by rollback
      if (rollback_chances) {
        try {
          ta.rollback();
        } catch (Exception ex) {
          fail("failed: " + ex.getMessage());
        }

        // intended error is checked w.r.t database first
        int ifAnyRows = 0;
        try {
          ifAnyRows = jtaObj.getRows(this.tblName);
        } catch (Exception ex) {
          fail(" failed: " + ex.getMessage());
        }
        assertEquals("rows found after rollback is: " + ifAnyRows, 0, ifAnyRows);
        /*
         * if (ifAnyRows != 0) { fail (" DB FAILURE"); }
         */
        // intended error is checked w.r.t. cache second
        String current_fullpath = jtaObj.currRegion.getFullPath();
        assertEquals(
            "failed retrieving current fullpath after rollback, fullpath is: " + current_fullpath,
            "/" + DEFAULT_RGN + "/region1", current_fullpath);

        // after jdbc rollback, cache value in region1 for key1 must vanish...
        String str1 = null;
        try {
          str1 = jtaObj.get("key1");
        } catch (CacheException ex) {
          fail("failed getting value for 'key1': " + ex.getMessage());
        }

        String tok1 = jtaObj.parseGetValue(str1);
        assertEquals("value found in cache: " + tok1 + ", after rollback", "\"test\"", tok1);
      } else {
        fail(" failed: " + e.getMessage());
        ta.rollback();
      }
    } catch (Exception e) {
      ta.rollback();
      fail(" failed: " + e.getMessage());
    } finally {
      if (conn != null)
        try {
          conn.close();
        } catch (SQLException ex) {
          fail("Exception: " + ex.getMessage());
        }
    }
  }

  /**
   * Test of testScenario7 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Tests a user transaction with cache lookup and with XAPooledDataSource lookup. It does get and
   * put operations on the cache within the transaction block and checks whether these operations
   * are committed once the transaction is committed.
   */
  @Test
  public void testScenario7() throws Exception {
    this.tblIDFld = 7;
    this.tblNameFld = "test7";
    boolean rollback_chances = true;
    final String DEFAULT_RGN = "root";

    JTAUtils jtaObj = new JTAUtils(cache, currRegion);

    jtaObj.deleteRows(this.tblName);

    Context ctx = cache.getJNDIContext();
    UserTransaction ta = (UserTransaction) ctx.lookup("java:/UserTransaction");
    Connection conn = null;

    try {
      ta.begin();

      String current_region = jtaObj.currRegion.getName();
      assertEquals("default region is not root", DEFAULT_RGN, current_region);

      jtaObj.getRegionFromCache("region1");

      // now current region should point to region1, as done from within
      // getRegionFromCache method...
      String current_fullpath = jtaObj.currRegion.getFullPath();
      assertEquals("failed retrieving the current region fullpath", "/" + DEFAULT_RGN + "/region1",
          current_fullpath);

      jtaObj.put("key1", "value1");

      // try to get value1 from key1 in the same region
      String str = jtaObj.get("key1");
      String tok = jtaObj.parseGetValue(str);
      assertEquals("get value mismatch with put", "\"value1\"", tok);

      current_fullpath = jtaObj.currRegion.getFullPath();
      assertEquals("failed retrieving current region fullpath", "/" + DEFAULT_RGN + "/region1",
          current_fullpath);

      DataSource da = (DataSource) ctx.lookup("java:/XAPooledDataSource");

      conn = da.getConnection();
      ta.commit();
      conn.close();

      rollback_chances = false;

      current_fullpath = jtaObj.currRegion.getFullPath();
      assertEquals("failed retrieving current region fullpath after txn commit, fullpath is: "
          + current_region, "/" + DEFAULT_RGN + "/region1", current_fullpath);

      str = jtaObj.get("key1");
      tok = jtaObj.parseGetValue(str);
      assertEquals("cache value found is: " + tok, "\"value1\"", tok);

    } catch (CacheExistsException e) {
      if (rollback_chances)
        ta.rollback();
      fail(" failed due to: " + e.getMessage());
    } catch (NamingException e) {
      ta.rollback();
      fail(" failed due to: " + e.getMessage());
    } catch (SQLException e) {
      ta.rollback();
      fail(" failed due to: " + e.getMessage());
    } catch (Exception e) {
      if (rollback_chances)
        ta.rollback();
      fail(" failed due to: " + e.getMessage());
    } finally {
      if (conn != null)
        try {
          conn.close();
        } catch (Exception e) {
        }
    }
  }

  /**
   * Test of testScenario9 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Tests a user transaction with cache lookup and with XAPooledDataSource lookup performing a db
   * update within the transaction block and committing the transaction. Then agin we perform
   * another db update with the same DataSource and finally close the Connection. The first update
   * only should be committed in db and the second will not participate in transaction throwing an
   * SQLException.
   */
  @Test
  public void testScenario9() throws Exception {
    this.tblIDFld = 9;
    this.tblNameFld = "test9";
    boolean rollback_chances = true;
    int first_field = this.tblIDFld;

    JTAUtils jtaObj = new JTAUtils(cache, currRegion);

    // delete the rows inserted from CacheUtils createTable, otherwise conflict
    // in PK's
    jtaObj.deleteRows(this.tblName);

    Context ctx = cache.getJNDIContext();
    UserTransaction ta = (UserTransaction) ctx.lookup("java:/UserTransaction");
    Connection conn = null;

    try {
      ta.begin();

      DataSource da = (DataSource) ctx.lookup("java:/XAPooledDataSource");
      conn = da.getConnection();
      Statement stmt = conn.createStatement();

      String sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);
      ta.commit();

      rollback_chances = false;

      // intended test for failure-- capable of throwing SQLException
      this.tblIDFld += 1;
      sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);

      stmt.close();
      conn.close();

      rollback_chances = true;
    } catch (NamingException e) {
      fail(" failed due to: " + e.getMessage());
      ta.rollback();
    } catch (SQLException e) {
      if (!rollback_chances) {
        int ifAnyRows = jtaObj.getRows(this.tblName);
        assertEquals("rows found is: " + ifAnyRows, 1, ifAnyRows);
        boolean matched = jtaObj.checkTableAgainstData(this.tblName, first_field + ""); // first
                                                                                        // field
                                                                                        // must
                                                                                        // be
                                                                                        // there.
        assertEquals("first entry to db is not found", true, matched);
      } else {
        ta.rollback();
        fail(" failed due to: " + e.getMessage());
      }
    } catch (Exception e) {
      fail(" failed due to: " + e.getMessage());
      if (rollback_chances) {
        ta.rollback();
      }
    } finally {
      if (conn != null)
        try {
          conn.close();
        } catch (SQLException e) {
        }
    }
  }

  /**
   * Test of testScenario10 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Test a user transaction with cache lookup and with XAPooledDataSource for multiple JDBC
   * Connections. This should not be allowed for Facets datasource. For other relational DB the
   * behaviour will be DB specific. For Oracle DB, n connections in a tranxn can be used provided ,
   * n-1 connections are closed before opening nth connection.
   */
  @Test
  public void testScenario10() throws Exception {
    this.tblIDFld = 10;
    this.tblNameFld = "test10";
    int rows_inserted = 0;
    int ifAnyRows = 0;
    int field1 = this.tblIDFld, field2 = 0;

    JTAUtils jtaObj = new JTAUtils(cache, currRegion);

    jtaObj.deleteRows(this.tblName);

    Context ctx = cache.getJNDIContext();
    UserTransaction ta = (UserTransaction) ctx.lookup("java:/UserTransaction");
    Connection conn1 = null;
    Connection conn2 = null;

    try {
      ta.begin();
      DataSource da = (DataSource) ctx.lookup("java:/XAPooledDataSource");
      conn1 = da.getConnection(); // the first Connection

      Statement stmt = conn1.createStatement();

      String sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);
      rows_inserted += 1;

      conn1.close();

      conn2 = da.getConnection(); // the second Connection
      stmt = conn2.createStatement();

      this.tblIDFld += 1;
      field2 = this.tblIDFld;
      sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";

      stmt.executeUpdate(sqlSTR);
      rows_inserted += 1;

      stmt.close();
      conn2.close();
      ta.commit();

      // if we reach here check for proper entries in db
      ifAnyRows = jtaObj.getRows(this.tblName);
      if (ifAnyRows == rows_inserted) {
        boolean matched1 = jtaObj.checkTableAgainstData(this.tblName, (field1 + ""));
        boolean matched2 = jtaObj.checkTableAgainstData(this.tblName, (field2 + ""));

        if (matched1)
          System.out.print("(PK " + field1 + "found ");
        else
          System.out.print("(PK " + field1 + "not found ");
        if (matched2)
          System.out.print("PK " + field2 + "found)");
        else
          System.out.print("PK " + field2 + "not found)");

        if (matched1 & matched2) {
          System.out.println("ok");
        } else {
          fail(" inserted data not found in DB !... failed");
        }
      } else {
        fail(" test interrupted, rows found=" + ifAnyRows + ", rows inserted=" + rows_inserted);
      }
    } catch (NamingException e) {
      ta.rollback();
    } catch (SQLException e) {
      ta.rollback();
    } catch (Exception e) {
      ta.rollback();
    } finally {
      if (conn1 != null)
        try {
          conn1.close();
        } catch (SQLException e) {
        }

      if (conn2 != null)
        try {
          conn2.close();
        } catch (SQLException e) {
        }
    }

  }

  /**
   * Test of testScenario11 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Tests Simple DataSource lookup within a transaction. Things should not participate in the
   * transaction.
   */
  @Test
  public void testScenario11() throws Exception {
    this.tblIDFld = 11;
    this.tblNameFld = "test11";
    boolean rollback_chances = false;

    JTAUtils jtaObj = new JTAUtils(cache, currRegion);

    jtaObj.deleteRows(this.tblName);

    Context ctx = cache.getJNDIContext();
    UserTransaction ta = (UserTransaction) ctx.lookup("java:/UserTransaction");
    Connection conn = null;

    try {
      ta.begin();
      DataSource da = (DataSource) ctx.lookup("java:/SimpleDataSource");

      conn = da.getConnection();
      Statement stmt = conn.createStatement();

      String sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);

      rollback_chances = true;

      // try insert the same data once more and see if all info gets rolled
      // back...
      // capable of throwing SQLException
      sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);

      stmt.close();
      ta.commit();
      conn.close();
    } catch (NamingException e) {
      ta.rollback();
    } catch (SQLException e) {
      if (rollback_chances) {
        try {
          ta.rollback();
        } catch (Exception ex) {
          fail("failed due to : " + ex.getMessage());
        }

        // try to check in the db whether any rows (the first one) are there
        // now...
        int ifAnyRows = jtaObj.getRows(this.tblName);
        assertEquals("first row not found in case of Simple Datasource", 1, ifAnyRows); // one
                                                                                        // row--
                                                                                        // the
                                                                                        // first
                                                                                        // one
                                                                                        // shud
                                                                                        // be
                                                                                        // there.
        boolean matched = jtaObj.checkTableAgainstData(this.tblName, this.tblIDFld + ""); // checking
                                                                                          // the
                                                                                          // existence
                                                                                          // of
                                                                                          // first
                                                                                          // row
        assertEquals("first row PK didn't matched", true, matched);
      } else {
        ta.rollback();
      }

    } catch (Exception e) {
      fail(" failed due to: " + e.getMessage());
      ta.rollback();
    } finally {
      if (conn != null)
        try {
          conn.close();
        } catch (SQLException e) {
        }
    }

  }

  /**
   * Test of testScenario14 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Tests a local Cache Loader with XADataSource lookup to get the connection. The Connection
   * should not participate in the transaction and commit/rollback should take affect accordingly
   * along with cache.
   */
  @Test
  public void testScenario14() throws Exception {
    final String TABLEID = "2";
    // final String TABLEFLD = "name2";
    JTAUtils jtaObj = new JTAUtils(cache, currRegion);

    Context ctx = cache.getJNDIContext();
    UserTransaction utx = (UserTransaction) ctx.lookup("java:/UserTransaction");
    utx.begin();
    AttributesFactory fac = new AttributesFactory(currRegion.getAttributes());
    fac.setCacheLoader(new XACacheLoaderTxn(this.tblName));
    Region re = currRegion.createSubregion("employee", fac.create());
    String retVal = (String) re.get(TABLEID); // TABLEID correspondes to
                                              // "name1".
    if (!retVal.equals("newname"))
      fail("Uncommitted value 'newname' not read by cacheloader name = " + retVal);
    utx.rollback();

    DataSource ds = (DataSource) ctx.lookup("java:/XAPooledDataSource");
    Connection conn = ds.getConnection();
    Statement stm = conn.createStatement();
    String str = "select name from " + tblName + "  where id= (2)";
    ResultSet rs = stm.executeQuery(str);
    rs.next();
    String str1 = rs.getString(1);
    if (!str1.equals("name2"))
      fail("Rollback not occurred on XAConnection got in a cache loader");
  }

  /**
   * Test of testScenario15 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Tests performing DDL operations by looking up a XAPooledDataSource and without transaction.
   */
  @Test
  public void testScenario15() throws Exception {
    this.tblIDFld = 15;
    this.tblNameFld = "test15";
    String tbl = "";
    boolean row_num = true;
    int ddl_return = 1;

    JTAUtils jtaObj = new JTAUtils(cache, currRegion);
    // delete the rows inserted from CacheUtils createTable, otherwise conflict
    // in PK's. Basically not needed for this test
    jtaObj.deleteRows(this.tblName);

    Context ctx = cache.getJNDIContext();
    // UserTransaction ta = null;
    Connection conn = null;
    Statement stmt = null;
    /*
     * try { ta = (UserTransaction)ctx.lookup("java:/UserTransaction");
     *
     * } catch (NamingException e) { fail ("user txn lookup failed: " + e.getMessage ()); }
     */

    try {
      DataSource da = (DataSource) ctx.lookup("java:/XAPooledDataSource");
      conn = da.getConnection();
      stmt = conn.createStatement();

      // Do some DDL stuff
      String time = new Long(System.currentTimeMillis()).toString();
      tbl = "my_table" + time;
      // String sql = "create table " + tbl +
      // " (my_id number primary key, my_name varchar2(50))";
      String sql = "create table " + tbl
          + " (my_id integer NOT NULL, my_name varchar(50), CONSTRAINT my_keyx PRIMARY KEY(my_id))";
      ddl_return = stmt.executeUpdate(sql);

      // check whether the table was created properly
      sql = "select * from " + tbl;
      ResultSet rs = null;
      rs = stmt.executeQuery(sql);
      row_num = rs.next();
      rs.close();
      if (ddl_return == 0 && !row_num) {
        sql = "drop table " + tbl;
        try {
          stmt = conn.createStatement();
          stmt.executeUpdate(sql);
        } catch (SQLException e) {
          fail(" failed to drop, " + e.getMessage());
        }
      } else
        fail("unable to create table");

      /** Code meant for Oracle DB **/
      /*
       * tbl = tbl.toUpperCase(); sql = "select * from tab where tname like '%tbl%'"; ResultSet rs =
       * null; rs = stmt.executeQuery(sql); rs.close(); sql = "drop table "+tbl; stmt =
       * conn.createStatement(); stmt.execute(sql); System.out.println (this.space + "ok");
       */
      stmt.close();
      conn.close();

    } catch (NamingException e) {
      fail("failed, " + e.getMessage());
    } catch (SQLException e) {
      fail("failed, " + e.getMessage());
    } catch (Exception e) {
      fail("failed, " + e.getMessage());
    } finally {
      if (conn != null)
        conn.close();
    }
  }

  /**
   * Test of testScenario16 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Tests DDL operations on XAPooledDataSOurce lookup, without transaction but making auto commit
   * false just before performing DDL queries and making it true before closing the Connection. The
   * operations should be committed.
   */
  @Test
  public void testScenario16() throws Exception {
    this.tblIDFld = 16;
    this.tblNameFld = "test16";
    String tbl = "";
    int ddl_return = 1;
    boolean row_num = true;

    JTAUtils jtaObj = new JTAUtils(cache, currRegion);

    jtaObj.deleteRows(this.tblName);

    Context ctx = cache.getJNDIContext();
    Connection conn = null;
    Statement stmt = null;

    try {
      DataSource da = (DataSource) ctx.lookup("java:/XAPooledDataSource");
      conn = da.getConnection();
      conn.setAutoCommit(false);
      stmt = conn.createStatement();

      String time = new Long(System.currentTimeMillis()).toString();
      tbl = "my_table" + time;
      // String sql = "create table " + tbl +
      // " (my_id number primary key, my_name varchar2(50))";
      String sql = "create table " + tbl
          + " (my_id integer NOT NULL, my_name varchar(50), CONSTRAINT my_key PRIMARY KEY(my_id))";
      ddl_return = stmt.executeUpdate(sql);

      sql = "select * from " + tbl;
      ResultSet rs = null;
      rs = stmt.executeQuery(sql);
      row_num = rs.next();
      rs.close();
      if (ddl_return == 0 && !row_num) {
        sql = "drop table " + tbl;
        try {
          stmt = conn.createStatement();
          stmt.executeUpdate(sql);
        } catch (SQLException e) {
          fail(" failed to drop, " + e.getMessage());
        }
      } else
        fail("table do not exists");

      /*** Code meant for Oracle DB ***/
      /*
       * tbl = tbl.toUpperCase(); sql = "select * from tab where tname like '%tbl%'"; ResultSet rs =
       * null; rs = stmt.executeQuery(sql); rs.close(); sql = "drop table "+tbl; stmt =
       * conn.createStatement(); stmt.executeUpdate(sql); System.out.println (this.space + "ok");
       */
      conn.setAutoCommit(true);
      stmt.close();
      conn.close();
    } catch (NamingException e) {
      fail("failed, " + e.getMessage());
    } catch (SQLException e) {
      fail("failed, " + e.getMessage());
    } catch (Exception e) {
      fail("failed, " + e.getMessage());
    } finally {
      if (conn != null)
        try {
          conn.close();
        } catch (SQLException e) {
        }
    }
  }

  /**
   * Test of testScenario18 method, of class org.apache.geode.internal.jta.functional.CacheTest1.
   * Get a connection (conn1) outside a transaction with pooled datasource lookup and another
   * connection (conn2) within the same transaction with XAPooled datasource lookup. After making
   * updates we do a rollback on the transaction and close both connections in the order of opening
   * them. The connection opened within transaction will only participate in the transaction.
   */
  @Test
  public void testScenario18() throws Exception {
    this.tblIDFld = 18;
    this.tblNameFld = "test18";
    boolean rollback_chances = true;
    int ifAnyRows = 0;

    JTAUtils jtaObj = new JTAUtils(cache, currRegion);

    jtaObj.deleteRows(this.tblName);

    Context ctx = cache.getJNDIContext();

    Connection conn2 = null; // connection within txn

    DataSource da = (DataSource) ctx.lookup("java:/PooledDataSource");
    Connection conn1 = da.getConnection(); // connection outside txn
    UserTransaction ta = (UserTransaction) ctx.lookup("java:/UserTransaction");

    try {
      ta.begin();
      Statement stmt = conn1.createStatement();
      String sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);
      stmt.close();

      ifAnyRows = jtaObj.getRows(this.tblName);
      if (ifAnyRows == 0) {
        fail("failed no rows are there...");
      }
      // tryin a XAPooled lookup for second connection
      da = (DataSource) ctx.lookup("java:/XAPooledDataSource");
      conn2 = da.getConnection();
      stmt = conn2.createStatement();

      this.tblIDFld += 1;
      sqlSTR = "insert into " + this.tblName + " values (" + this.tblIDFld + "," + "'"
          + this.tblNameFld + "'" + ")";
      stmt.executeUpdate(sqlSTR);
      ta.rollback(); // intensional rollback

      stmt.close();
      conn2.close();
      conn1.close();

      rollback_chances = false;
      // if we reach here check whether the rollback was success for conn1 and
      // conn2
      ifAnyRows = jtaObj.getRows(this.tblName);
      assertEquals("at least one row not retained after rollback", 1, ifAnyRows);

      boolean matched = jtaObj.checkTableAgainstData(this.tblName, this.tblIDFld + ""); // checking
                                                                                        // conn2's
                                                                                        // field
      if (matched) { // data is still in db
        fail(", PK " + this.tblIDFld + " found in db)" + "   " + "rollback for conn #2 failed");
      }
    } finally {
      if (conn1 != null)
        try {
          conn1.close();
        } catch (SQLException ex) {
          fail(" Exception: " + ex.getMessage());
        }
      if (conn2 != null)
        try {
          conn2.close();
        } catch (SQLException ex) {
          fail(" Exception: " + ex.getMessage());
        }
    }
  }

  /**
   * required for test # 14
   */
  static class XACacheLoaderTxn implements CacheLoader {

    String tableName;

    /** Creates a new instance of XACacheLoaderTxn */
    public XACacheLoaderTxn(String str) {
      this.tableName = str;
    }

    public Object load(LoaderHelper helper) throws CacheLoaderException {
      System.out.println("In Loader.load for" + helper.getKey());
      return loadFromDatabase(helper.getKey());
    }

    private Object loadFromDatabase(Object ob) {
      Object obj = null;
      try {
        Context ctx = CacheFactory.getAnyInstance().getJNDIContext();
        DataSource ds = (DataSource) ctx.lookup("java:/XAPooledDataSource");
        Connection conn = ds.getConnection();
        Statement stm = conn.createStatement();
        String str = "update " + tableName + " set name ='newname' where id = ("
            + (new Integer(ob.toString())).intValue() + ")";
        stm.executeUpdate(str);
        ResultSet rs = stm.executeQuery("select name from " + tableName + " where id = ("
            + (new Integer(ob.toString())).intValue() + ")");
        rs.next();
        obj = rs.getString(1);
        stm.close();
        conn.close();
        return obj;
      } catch (Exception e) {
        throw new Error(e);
      }
    }

    public void close() {}
  }
}
