/*
Copyright 2011 Jose Maria Arranz Santamaria
Licensed 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.
*/
package jepl.impl.jta;
import jepl.impl.jta.dsmgr.JEPLJTAMultipleDataSourceImpl;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import jepl.JEPLBootJTA;
import jepl.JEPLException;
import jepl.JEPLJTADataSource;
import jepl.JEPLListener;
import jepl.JEPLTask;
import jepl.JEPLTransactionPropagation;
import jepl.impl.JEPLConnectionImpl;
import jepl.impl.JEPLDALImpl;
import jepl.impl.JEPLDataSourceImpl;
import jepl.impl.JEPLListenerListImpl;
import jepl.impl.JEPLTaskOneExecWithConnectionImpl;
import jepl.impl.JEPLTaskOneExecWithConnectionWrapperImpl;
/**
*
* @author jmarranz
*/
public abstract class JEPLJTADataSourceImpl extends JEPLDataSourceImpl implements JEPLJTADataSource
{
protected JEPLTransactionPropagation defaultTransactionPropagation;
protected ThreadLocal<JEPLConnectionImpl> connByThreadOfDataSourceMgr = new ThreadLocal<JEPLConnectionImpl>();
public JEPLJTADataSourceImpl(JEPLBootJTAImpl boot,DataSource ds)
{
super(boot,ds);
this.defaultTransactionPropagation = boot.getJEPLJTAMultipleDataSourceImpl().getDefaultJEPLTransactionPropagation();
}
public JEPLJTAMultipleDataSourceImpl getJEPLJTAMultipleDataSourceImpl()
{
return getJEPLBootJTAImpl().getJEPLJTAMultipleDataSourceImpl();
}
public JEPLBootJTA getJEPLBootJTA()
{
return (JEPLBootJTAImpl)boot;
}
public JEPLBootJTAImpl getJEPLBootJTAImpl()
{
return (JEPLBootJTAImpl)boot;
}
public UserTransaction getUserTransaction()
{
return getJEPLBootJTAImpl().getUserTransaction();
}
public TransactionManager getTransactionManager()
{
return getJEPLBootJTAImpl().getTransactionManager();
}
public JEPLTransactionPropagation getDefaultJEPLTransactionPropagation()
{
return defaultTransactionPropagation;
}
public void setDefaultJEPLTransactionPropagation(JEPLTransactionPropagation defaultTransactionPropagation)
{
checkIsInUse();
this.defaultTransactionPropagation = defaultTransactionPropagation;
}
public JEPLJTAConnectionImpl getCurrentJEPLJTAConnectionImpl()
{
return (JEPLJTAConnectionImpl)getCurrentJEPLConnectionImpl(); // Puede ser null
}
public JEPLTransactionPropagation getCurrentJEPLTransactionPropagation()
{
JEPLJTAConnectionImpl jcon = getCurrentJEPLJTAConnectionImpl();
if (jcon == null) return null;
JEPLTaskExecContextInConnectionJTAImpl taskCtx = (JEPLTaskExecContextInConnectionJTAImpl)jcon.getCurrentJEPLTaskContext();
if (taskCtx == null) return null; // Yo creo que nunca es null pero por si acaso
return taskCtx.getJEPLTransactionPropagation();
}
@Override
public JEPLConnectionImpl createJEPLConnection(Connection con)
{
return new JEPLJTAConnectionDefaultImpl(this,con); // Este constructor no dará nunca error
}
@Override
public JEPLConnectionImpl getCurrentJEPLConnectionImpl()
{
if (!getJEPLJTAMultipleDataSourceImpl().hasCurrentJEPLTask())
return super.getCurrentJEPLConnectionImpl();
else
return connByThreadOfDataSourceMgr.get();
}
@Override
public JEPLConnectionImpl getJEPLConnectionFromPool() throws SQLException
{
if (!getJEPLJTAMultipleDataSourceImpl().hasCurrentJEPLTask())
return getJEPLConnectionFromPoolEffective();
else
return connByThreadOfDataSourceMgr.get();
}
@Override
public void returnJEPLConnectionToPool(JEPLConnectionImpl jcon) throws SQLException
{
if (!getJEPLJTAMultipleDataSourceImpl().hasCurrentJEPLTask())
returnJEPLConnectionToPoolEffective(jcon);
else
{
//int i = 1;
}
// En caso contrario no hacer nada, pues se cierra cuando se cierre la última task del task manager
}
public void getJEPLConnectionFromPoolByDataSourceMgr() throws SQLException
{
JEPLConnectionImpl jcon = getJEPLConnectionFromPoolEffective();
connByThreadOfDataSourceMgr.set(jcon);
}
public void returnJEPLConnectionToPoolByDataSourceMgr() throws SQLException
{
JEPLConnectionImpl jcon = connByThreadOfDataSourceMgr.get();
connByThreadOfDataSourceMgr.set(null);
returnJEPLConnectionToPoolEffective(jcon);
}
protected JEPLConnectionImpl getJEPLConnectionFromPoolEffective() throws SQLException
{
return super.getJEPLConnectionFromPool();
}
protected void returnJEPLConnectionToPoolEffective(JEPLConnectionImpl jcon) throws SQLException
{
//jcon.getConnection().setAutoCommit(false);
super.returnJEPLConnectionToPool(jcon);
}
@Override
public <T> T exec(JEPLTask<T> task)
{
return exec(task,null,null);
}
@Override
public <T> T exec(JEPLTask<T> task,JEPLListener listener)
{
return exec(task,listener,null);
}
@Override
public <T> T exec(JEPLTask<T> task,JEPLTransactionPropagation txnProp)
{
return exec(task,null,txnProp);
}
@Override
public <T> T exec(JEPLTask<T> task,JEPLListener paramListener,JEPLTransactionPropagation txnProp)
{
// El valor del JEPLTransactionPropagation no puede ser determinado por el posible
// JEPLConnectionListener pasado por el usuario, pues la propagación está claramente
// asociada al ámbito del método persistente es decir la task por lo que no puede/debe
// ser cambiada en cualquier momento o fase.
try
{
JEPLTaskOneExecWithConnectionWrapperImpl<T> taskWrap = new JEPLTaskOneExecWithConnectionWrapperImpl<T>(task);
return execInternal(taskWrap,null,JEPLListenerListImpl.getJEPLListenerList(paramListener),txnProp);
}
catch (JEPLException ex)
{
throw ex;
}
catch (Exception ex)
{
throw new JEPLException(ex);
}
}
@Override
public <T> T execInternal(JEPLTaskOneExecWithConnectionImpl<T> task,JEPLDALImpl dal,JEPLListenerListImpl paramListener) throws Exception
{
return execInternal(task,dal,paramListener,null);
}
public <T> T execInternal(JEPLTaskOneExecWithConnectionImpl<T> task,final JEPLDALImpl dal,final JEPLListenerListImpl paramListener,JEPLTransactionPropagation txnPropParam) throws Exception
{
JEPLTask<T> originalTask = task.getInnerJEPLTask();
final JEPLTransactionPropagation txnProp = TransactionJTAExecutor.getJEPLTransactionPropagation(txnPropParam, originalTask, getDefaultJEPLTransactionPropagation()); // Este es finalmente el que se usa (si se usa)
final JEPLTaskExecContextInConnectionJTAImpl<T> taskCtx = new JEPLTaskExecContextInConnectionJTAImpl<T>(task,txnProp);
//HACER JTA bueno y Fake, no olvidar de quitar la transacción dentro de JEPLJTAConnectionImpl
//eliminando finalmente TransactionJTAUtil
UserTransaction userTxn = getUserTransaction();
TransactionManager txnMgr = getTransactionManager();
if (userTxn instanceof UserTransactionJDBC)
{
// Fake UserTransaction (pure JDBC based)
// Necesitamos obtener antes la conexión antes de iniciar la transacción
final JEPLJTAConnectionImpl conWrap = (JEPLJTAConnectionImpl)pushJEPLTask(taskCtx);
try
{
TransactionJTAExecutor<T> jtaTxn = new TransactionJTAExecutor<T>()
{
@Override
public T onExecute() throws Exception
{
return conWrap.execTask(taskCtx,dal,paramListener,txnProp);
}
};
return jtaTxn.execute(txnProp,userTxn,txnMgr);
}
finally
{
popJEPLTask(taskCtx);
}
}
else
{
// Iniciamos la transacción antes de obtener la conexión
// el UserTransaction detectará las conexiones (si son XA) que se abran
// y las añadirá a la transacción, en JOTM y Atomikos podría ser en el orden
// inverso pues los DataSource XA están ya "preregistrados" pero esto no estándar
TransactionJTAExecutor<T> jtaTxn = new TransactionJTAExecutor<T>()
{
@Override
public T onExecute() throws Exception
{
JEPLJTAConnectionImpl conWrap = (JEPLJTAConnectionImpl)pushJEPLTask(taskCtx);
try
{
return conWrap.execTask(taskCtx,dal,paramListener,txnProp);
}
finally
{
popJEPLTask(taskCtx);
}
}
};
return jtaTxn.execute(txnProp, userTxn,txnMgr);
}
}
}