/*
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;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import jepl.JEPLConnection;
import jepl.JEPLConnectionListener;
import jepl.JEPLDataSource;
import jepl.JEPLTransaction;
import jepl.impl.query.JEPLBeanPropertyDescriptorImpl;
import jepl.impl.query.JEPLUpdateColumnPropertyInfoList;
/**
*
* @author jmarranz
*/
public abstract class JEPLConnectionImpl implements JEPLConnection
{
protected JEPLDataSourceImpl ds;
protected Connection con;
protected Map<String,JEPLPreparedStatementImpl> cachedStatements = null;
protected LinkedList<JEPLTaskExecContextInConnectionImpl<?>> taskList = new LinkedList<JEPLTaskExecContextInConnectionImpl<?>>();
protected JEPLUserDataMonoThreadImpl userData = new JEPLUserDataMonoThreadImpl();
protected JEPLCurrentTransactionImpl currentTxn;
protected Map<String,JEPLUpdateColumnPropertyInfoList> updateBeanInfoMap;
public JEPLConnectionImpl(JEPLDataSourceImpl ds,Connection con)
{
this.ds = ds;
this.con = con;
}
public JEPLUpdateColumnPropertyInfoList getJEPLUpdateColumnPropertyInfoList(String tableNameLowerCase,Map<String,JEPLBeanPropertyDescriptorImpl> propertyMap) throws SQLException
{
// En cada momento sólo opera un sólo hilo en la conexión
if (updateBeanInfoMap == null)
this.updateBeanInfoMap = new HashMap<String,JEPLUpdateColumnPropertyInfoList>();
JEPLUpdateColumnPropertyInfoList updateBeanInfo = updateBeanInfoMap.get(tableNameLowerCase);
if (updateBeanInfo == null)
{
updateBeanInfo = getJEPLDataSourceImpl().getJEPLUpdateColumnPropertyInfoList(this, tableNameLowerCase, propertyMap);
// Hacemos nuestra propia copia caché para evitar sincronizar hilos como ocurre en JEPLDataSourceImpl.getJEPLUpdateColumnPropertyInfoList
updateBeanInfoMap.put(tableNameLowerCase,updateBeanInfo);
}
return updateBeanInfo;
}
@Override
public String[] getUserDataNames()
{
return userData.getUserDataNames();
}
@Override
public boolean containsName(String name)
{
return userData.containsName(name);
}
@Override
public Object getUserData(String name)
{
return userData.getUserData(name);
}
@Override
public <T> T getUserData(String name, Class<T> returnType)
{
return userData.getUserData(name, returnType);
}
@Override
public Object setUserData(String name, Object value)
{
return userData.setUserData(name, value);
}
@Override
public Object removeUserData(String name)
{
return userData.removeUserData(name);
}
@Override
public <T> T removeUserData(String name, Class<T> returnType)
{
return userData.removeUserData(name, returnType);
}
@Override
public JEPLDataSource getJEPLDataSource()
{
return ds;
}
public JEPLDataSourceImpl getJEPLDataSourceImpl()
{
return ds;
}
@Override
public Connection getConnection()
{
return con;
}
@Override
public JEPLTransaction getJEPLTransaction()
{
return getJEPLCurrentTransactionImpl();
}
public JEPLCurrentTransactionImpl getJEPLCurrentTransactionImpl()
{
return currentTxn;
}
public boolean isEmptyOfJEPLTasks()
{
return taskList.isEmpty();
}
public JEPLTaskExecContextInConnectionImpl<?> getCurrentJEPLTaskContext()
{
return taskList.getFirst(); // El último insertado realmente es el primero de la lista (se usó push)
}
public JEPLTaskExecContextInConnectionImpl<?> popJEPLTaskExecContex()
{
return taskList.pop(); // Quita del ppio
}
public void pushJEPLTaskExecContex(JEPLTaskExecContextInConnectionImpl<?> task)
{
taskList.push(task); // Pone en el ppio
}
public JEPLPreparedStatementImpl prepareJEPLStatement(JEPLDALImpl dal,String sql,int autoGeneratedKeys) throws SQLException
{
// http://download.oracle.com/javase/tutorial/jdbc/basics/prepared.html
JEPLDataSourceImpl ds = getJEPLDataSourceImpl();
if (ds.isPreparedStatementCached())
{
if (cachedStatements == null) cachedStatements = new HashMap<String,JEPLPreparedStatementImpl>();
String key = autoGeneratedKeys + "-" + sql;
JEPLPreparedStatementImpl jstmt = cachedStatements.get(key);
if (jstmt != null)
{
boolean closed = false;
if (!ds.isC3PO())
{
try { closed = jstmt.getPreparedStatement().isClosed(); } catch(AbstractMethodError ex) { closed = false; ds.setIsC3PO(true); } // Caso de C3PO 0.9.1.2 que no implementa isClosed()
}
if (closed) // Así nos aseguramos que no utilizamos un statement cerrado
cachedStatements.remove(jstmt.getKey()); // No vale la descartamos
else
return jstmt;
}
PreparedStatement stmt = prepareStatement(sql, autoGeneratedKeys);
jstmt = createJEPLPreparedStatement(dal,stmt,key);
cachedStatements.put(key,jstmt);
return jstmt;
}
else
{
PreparedStatement stmt = prepareStatement(sql, autoGeneratedKeys);
return createJEPLPreparedStatement(dal,stmt,null);
}
}
protected PreparedStatement prepareStatement(String sql,int autoGeneratedKeys) throws SQLException
{
return con.prepareStatement(sql, autoGeneratedKeys);
}
protected JEPLPreparedStatementImpl createJEPLPreparedStatement(JEPLDALImpl dal,PreparedStatement stmt,String key) throws SQLException
{
return new JEPLPreparedStatementDefaultImpl(this,dal,stmt,key);
}
public void releaseJEPLPreparedStatement(JEPLPreparedStatementImpl jstmt) throws SQLException
{
PreparedStatement stmt = jstmt.getPreparedStatement();
if (getJEPLDataSourceImpl().isPreparedStatementCached())
{
//try
//{
stmt.clearParameters(); // Así queda limpio para el siguiente uso y no se mezclan parámetros (muy raro porque el número es siempre el mismo pero por si acaso)
//}
//catch(SQLException ex)
//{
// Parece que MySQL cierra automáticamente el PreparedStatement si se supera el límite interno de PreparedStatements cacheado
// https://community.jboss.org/thread/170092?_sscc=t
//cachedStatements.remove(jstmt.getKey());
//}
}
else
{
stmt.close();
}
}
public void closePreparedStatements() throws SQLException
{
if (cachedStatements == null) return;
for(Map.Entry<String,JEPLPreparedStatementImpl> entry : cachedStatements.entrySet())
{
JEPLPreparedStatementImpl stmt = entry.getValue();
stmt.getPreparedStatement().close();
}
this.cachedStatements = null;
}
public <T> JEPLConnectionListener<T> getJEPLConnectionListener(JEPLDALImpl dal,JEPLListenerListImpl paramListener)
{
JEPLConnectionListener<T> listener;
if (paramListener != null)
{
listener = paramListener.getJEPLConnectionListener();
if (listener != null)
return listener;
}
// dal PUEDE ser nulo
if (dal != null)
{
listener = dal.getJEPLListenerList().getJEPLConnectionListener();
if (listener != null)
return listener;
}
listener = ds.getJEPLListenerList().getJEPLConnectionListener();
if (listener != null)
return listener;
return null;
}
}