/* 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; } }