package com.venky.swf.db; import java.io.Serializable; import java.sql.SQLException; import java.util.HashSet; import java.util.Set; import com.venky.core.checkpoint.Checkpoint; import com.venky.core.checkpoint.MergeableMap; import com.venky.core.log.ExtendedLevel; import com.venky.core.log.SWFLogger; import com.venky.core.log.TimerStatistics.Timer; import com.venky.swf.db.jdbc.SWFSavepoint; import com.venky.swf.db.model.Model; import com.venky.swf.db.model.reflection.ModelReflector; import com.venky.swf.db.table.QueryCache; import com.venky.swf.routing.Config; public class Transaction implements _IDatabase._ITransaction { public SWFSavepoint getSavepoint() { return savepoint; } private SWFSavepoint savepoint = null; private int transactionNo = -1 ; private Checkpoint<MergeableMap<String,Object>> checkpoint = null; public Transaction(int transactionNo, Checkpoint<MergeableMap<String,Object>> cp) { this.transactionNo = transactionNo; checkpoint = cp; savepoint = new SWFSavepoint(String.valueOf(transactionNo)); setSavepoint(); Config.instance().getLogger(Database.class.getName()).fine("Transaction:"+transactionNo+" Started : " + Database.getCaller()); } public int getTransactionNo(){ return transactionNo; } public Checkpoint<MergeableMap<String,Object>> getCheckpoint(){ return checkpoint; } SWFLogger cat = Config.instance().getLogger(getClass().getName()); public void setSavepoint(){ try { for (String pool : getActivePools()){ //Set in all pools cat.fine("Set Save point on pool " + pool ); savepoint.addSavepoint(pool); } } catch (SQLException e) { throw new RuntimeException(e); } } public void releaseSavepoint(){ try { for (String pool :getActivePools()) { savepoint.removeSavepoint(pool); } } catch (SQLException e) { throw new RuntimeException(e); } } public void rollbackToSavePoint(){ try { for (String pool : getActivePools()) { savepoint.rollback(pool); } } catch (SQLException e) { throw new RuntimeException(e); } } public void registerCommit() { Config.instance().getLogger(Database.class.getName()).fine("Transaction:"+transactionNo+" .registerCommit : " + Database.getCaller()); Database.getInstance().getTransactionManager().registerCommit(this); } public void commit() { String ctx = cat.isLoggable(ExtendedLevel.TIMER) ? "Transaction:"+transactionNo+ " commit " + Database.getCaller() : null; Timer t = cat.startTimer(ctx,Config.instance().isTimerAdditive()); try { Database.getInstance().getTransactionManager().commit(this); }finally{ t.stop(); } } public void rollback(Throwable th) { String ctx = cat.isLoggable(ExtendedLevel.TIMER) ? "Transaction:"+transactionNo+ " rollback " + Database.getCaller() : null; Timer t = cat.startTimer(ctx,Config.instance().isTimerAdditive()); try { Database.getInstance().getTransactionManager().rollback(this,th); }finally{ t.stop(); } } public <M extends Model> QueryCache getCache(ModelReflector<M> ref) { String tableName = ref.getTableName(); QueryCache queryCache = (QueryCache)getAttribute(QueryCache.class.getName()+".for."+tableName); if (queryCache == null){ queryCache = new QueryCache(tableName); } setAttribute(QueryCache.class.getName() + ".for." + tableName, queryCache); return queryCache; } public void setAttribute(String name,Object value){ checkpoint.getValue().put(name, value); if (value != null && !(value instanceof Serializable) && !(value instanceof Cloneable)){ Config.instance().getLogger(Database.class.getName()).warning(value.getClass().getName() + " not Serializable or Cloneable. Checkpointing in nested transactions may exhibit unexpected behaviour!"); } } @SuppressWarnings("unchecked") public <A> A getAttribute(String name){ return (A)checkpoint.getValue().get(name); } public Set<String> getActivePools(){ Set<String> activePools = getAttribute("active.connection.pools"); if (activePools == null){ activePools = new HashSet<String>(10); setAttribute("active.connection.pools", activePools); } return activePools; } public void registerActivePool(String pool){ if (getActivePools().add(pool)){ try { savepoint.addSavepoint(pool); } catch (SQLException e) { throw new RuntimeException(e); } } } public void registerTableDataChanged(String tableName){ getTablesChanged().add(tableName); } public Set<String> getTablesChanged(){ Set<String> models = getAttribute("tables.modified"); if (models == null){ models = new HashSet<String>(); setAttribute("tables.modified", models); } return models; } }