Atomikos Forum

Data source proxy

I am using Atomikos 3.6.5 with Spring, Hibernate and Derby. Derby is used as a temporary database in embedded mode. The purpose is to provide each user session with a temp copy of the app's permanent db. The temp db contains a base schema, which holds the tables, from which temp schemas are created, each temp schema holding a copy of the base schema. Each user is assigned a temp schema when a session starts. A SchemaAwareDataSourceProxy class, extension of another Spring proxy class, overrides the getConnection() method on the data source. The temp schema is first assigned, and when getConnection() is called, it calls super.getConnection(), uses it to set the temp schema, and returns the conn. I had this working once, and somewhere along the line in adding various services to this app it stopped working. I thought I had it working after I added Atomikos to the mix.

I hope this expl is clear. The proxying is apparently not reaching deep enough into Atomikos's doings. I need some equivalent way of intercepting a connection for an XA data source, among the suite of XAs Atomikos is keeping track of.

Here is the overridden method. Below that is the Spring config, and below that the driver for my test. The sample config has only the one XA data source; the full app has two other XA DSes. Thanks for any advice.

===
/**
  * override of getConnection
  */
  public Connection getConnection() throws SQLException {
    Connection con = super.getConnection(); 
   
    String schemaName = (String) schemaHolder.getSchemaName();
   
    if (schemaName == null)
      throw new IllegalStateException("SchemaName not set. Call setSchemaName before doing any database access");
     
    setSchemaOnConnection(con, schemaName);
   
    return con;
  }
===
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
"http://www.springframework.org/dtd/spring-beans.dtd">
 
<!--<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">-->
 
<beans> 
 
  <bean id="daoGetter" class="com.kve.vanguard.model.orm.dao.GetDao"/>

  <bean id="tempDBInitializer" class="com.kve.vanguard.model.orm.temp.TempDBInitDriver"/>

  <bean id="vanguardTempDataSource" class="com.kve.vanguard.model.orm.dao.SchemaAwareDataSourceProxy">
    <property name="targetDataSource"><ref local="vanguardTempDataSourceTarget"/></property>
    <property name="schemaName"><value>APP</value></property>
  </bean>

  <bean id="vanguardTempDataSourceTarget" class="com.atomikos.jdbc.AtomikosDataSourceBean">
    <property name="uniqueResourceName" value="VANGUARDTEMP" />
    <property name="xaDataSourceClassName">
      <value>org.apache.derby.jdbc.EmbeddedXADataSource40</value>
    </property>
    <property name="xaProperties">
      <props>     
        <prop key="databaseName">vanguard</prop>
        <prop key="connectionAttributes">create=true;</prop>
      </props>
    </property>   
    <property name="poolSize" value="3" />
  </bean>

  <bean id="vanguardTempInitializer" class="org.springframework.jdbc.datasource.init.DataSourceInitializer">
    <property name="dataSource" ref="vanguardTempDataSource"/>
    <property name="enabled" value="true"/>
    <property name="databasePopulator">
    <bean class="org.springframework.jdbc.datasource.init.ResourceDatabasePopulator">
        <property name="continueOnError" value="true"/>
        <property name="ignoreFailedDrops" value="true"/>
        <property name="sqlScriptEncoding" value="UTF-8"/>
        <property name="scripts">
          <list>
            <value type="org.springframework.core.io.Resource">
              classpath:init_tempdb.sql
            </value>
          </list>
        </property>
      </bean>
    </property>
  </bean>

  <bean id="tempSessionFactory"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="packagesToScan" value="com.kve.vanguard.model.orm.domain, com.kve.vanguard.model.arrays" />   
    <property name="dataSource" ref="vanguardTempDataSource" />
    <property name="configLocation">
      <value>classpath:temp-hibernate.cfg.xml</value>
    </property>
    <property  name="configurationClass">
      <value>org.hibernate.cfg.AnnotationConfiguration</value>
    </property>       
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.connection.url">jdbc:derby:vanguard</prop>
        <prop key="hibernate.default_schema">vanguardtemp</prop>
        <prop key="hibernate.transaction.factory_class">com.atomikos.icatch.jta.hibernate3.AtomikosJTATransactionFactory</prop>
        <prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop> 
        <prop key="hibernate.current_session_context_class">jta</prop>
        <prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop>           
        <prop key="hibernate.show_sql">false</prop>
        <prop key="hibernate.cache.use_second_level_cache">false</prop>
      </props>
  </property>
  </bean>

  <bean id="userTransactionService"  class="com.atomikos.icatch.config.UserTransactionServiceImp" 
    init-method="init" destroy-method="shutdownForce">
    <constructor-arg>
        <props>
            <prop key="com.atomikos.icatch.service">
              com.atomikos.icatch.standalone.UserTransactionServiceFactory
            </prop>
            <prop key="com.atomikos.icatch.automatic_resource_registration">true</prop>
            <prop key="com.atomikos.icatch.console_log_level">DEBUG</prop>
        </props>
    </constructor-arg>   
  </bean>

  <bean id="AtomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" 
    init-method="init" destroy-method="close" 
    depends-on="userTransactionService">
    <property name="forceShutdown" value="false" />
  </bean>
 
  <bean id="AtomikosUserTransaction" 
      class="com.atomikos.icatch.jta.UserTransactionImp"
      depends-on="userTransactionService">
    <property name="transactionTimeout" value="300" />
  </bean>

  <bean id="JtaTransactionManager" 
      class="org.springframework.transaction.jta.JtaTransactionManager" 
      depends-on="userTransactionService">
    <property name="transactionManager" ref="AtomikosTransactionManager" />
    <property name="userTransaction" ref="AtomikosUserTransaction" />
  </bean>

  <import resource="temp-dao-config.xml"/>
   
</beans> 
=======
package com.kve.vanguard.main;


import org.springframework.context.ApplicationContext;
import org.springframework.transaction.jta.JtaTransactionManager;


import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.atomikos.icatch.jta.UserTransactionImp;

import com.kve.vanguard.model.orm.domain.*;
import com.kve.vanguard.model.orm.dao.*;


public class Main {

  /**
  * @param args
  */
  public static void main(String[] args) {
    ApplicationContext context =
      new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"});
   
    JtaTransactionManager txmgr = (JtaTransactionManager)
      context.getBean("JtaTransactionManager"); 
   
    /*SchemaAwareDataSourceProxy sads = (SchemaAwareDataSourceProxy)
      context.getBean("vanguardTempDataSource");
   
    sads.setSchemaName("TEMP01");*/ 
   
    UserTransactionImp tx = (UserTransactionImp) txmgr.getUserTransaction(); 

    try {

      tx.begin(); 
     
      SchemaAwareDataSourceProxy sads = (SchemaAwareDataSourceProxy)
        context.getBean("vanguardTempDataSource");
   
      sads.setSchemaName("TEMP01"); 
     
      Dao locDaoTemp = GetDao.LocationTemp();     
      Location locTemp = new Location() ;
      locTemp.setLocationId("MAINL");
      locTemp.setCurrencyCodeMaster_FK("CD$");
      String locId = (String) locDaoTemp.create(locTemp);     
     
      tx.commit();
      System.out.println("Location created: " + locId);   
   
    }
    catch (Exception e) {
      System.out.println("Main Exception: " + e.getMessage() +  " " + e.getCause());
    };
  }
}
Harry Clark Send private email
Thursday, August 19, 2010
 
 
PS--under debug, the overridden getConnection() method is called as expected, when the tx is committed. The schema is duly set, from the value passed to setSchema(), in setSchemaOnConnection(). It just doesn't take with Atomikos somehow. Is the schema setting stmt actually executed or is it deferred because of JTA and executed with the SQL comprising the tx, and thus the schema is somehow not in effect?

private void setSchemaOnConnection(Connection con, String schemaName) throws SQLException {
    if (logger.isDebugEnabled())
      logger.debug("Setting schema to " + schemaName + " on connection " + con);
     
    Statement stmt = con.createStatement();
    try {
      stmt.execute("set schema = '" + schemaName + "'");
    }
    catch (Exception e) {
      System.out.println("Exception in setSchema: " + e.getMessage() + e.getCause());
    }
    finally {
      stmt.close();
    }
  }
Harry Clark Send private email
Thursday, August 19, 2010
 
 
Here is the call stack at the setSchemaOnConnection() breakpoint. It look like Hibernate until near the top (?)

Thread [main] (Suspended (breakpoint at line 63 in SchemaAwareDataSourceProxy))        SchemaAwareDataSourceProxy.setSchemaOnConnection(Connection, String) line: 63    SchemaAwareDataSourceProxy.getConnection() line:47        TransactionAwareDataSourceConnectionProvider(LocalDataSourceConnectionProvider).getConnection() line: 81    
ConnectionManager.openConnection() line: 446    
ConnectionManager.getConnection() line: 167        NonBatchingBatcher(AbstractBatcher).prepareStatement(String, boolean) line: 116        NonBatchingBatcher(AbstractBatcher).prepareStatement(String) line: 109        NonBatchingBatcher(AbstractBatcher).prepareBatchStatement(String) line: 244        SingleTableEntityPersister(AbstractEntityPersister).insert(Serializable, Object[], boolean[], int, String, Object, SessionImplementor) line: 2252        SingleTableEntityPersister(AbstractEntityPersister).insert(Serializable, Object[], Object, SessionImplementor) line: 2688    
EntityInsertAction.execute() line: 79    
ActionQueue.execute(Executable) line: 279    
ActionQueue.executeActions(List) line: 263    
ActionQueue.executeActions() line: 167    DefaultFlushEventListener(AbstractFlushingEventListener).performExecutions(EventSource) line: 321    
DefaultFlushEventListener.onFlush(FlushEvent) line: 50    
SessionImpl.flush() line: 1027    
SessionImpl.managedFlush() line: 365    
CacheSynchronization.beforeCompletion() line: 88    
Sync2Sync.beforeCompletion() line: 73    
TxActiveStateHandler(TransactionStateHandler).commit() line: 253    
CompositeTransactionImp.doCommit() line: 511    
CompositeTerminatorImp.commit() line: 138    
TransactionImp.commit() line: 298    
TransactionManagerImp.commit() line: 612    
UserTransactionImp.commit() line: 168    
Main.main(String[]) line: 50
Harry Clark Send private email
Thursday, August 19, 2010
 
 
Hi,

Can you send a tm.out in INFO mode to support at atomikos dot com?

Thanks
Guy Pardon Send private email
Friday, August 20, 2010
 
 
I fixed this, my fault. I had somehow put a default schema on the temporary data source config, the base temp schema from which the other temp schemas were created. That is where the record was inserted, despite selecting a different schema. When I removed the default schema from the config, the schema selection worked and the record was inserted in the correct table in the correct temp schema.

The SchemaAwareDataSource I used was from the Spring forums, useful way of distinguishing multiple schemas in a single data source, by overriding the getConnection() method and setting the schema, using a value stored in a ThreadLocal variable set on previous call.
Harry Clark Send private email
Tuesday, August 24, 2010
 
 
Hi,

Ok, thanks for the update. Either way, i find the schema proxy interesting.

Cheers
Guy Pardon Send private email
Tuesday, August 24, 2010
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics