/* * File : ConnectionBean.java * Created : 21-oct-2003 18:11 * By : fbusquets * * JClic - Authoring and playing system for educational activities * * Copyright (C) 2000 - 2005 Francesc Busquets & Departament * d'Educacio de la Generalitat de Catalunya * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details (see the LICENSE file). */ package edu.xtec.util.db; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * This class stores an SQL {@link java.sql.Connection} and provides methods to * obtain {@link java.sql.PreparedStatement} objects from it. * <CODE>ConnectionBean</CODE> can also store a collection containing all the * <CODE>PreparedStatement</CODE> objects, allowing client applications to reuse them. * @author Francesc Busquets (fbusquets@xtec.cat) * @version 13.09.16 */ public class ConnectionBean { private Connection con; private Map<String, PreparedStatement> statements; private Date born; private Date lastUsed; private String lastStatement; private Date closed; /** * This field is used by {@link edu.xtec.util.db.ConnectionBeanProvider} to count * the number of times a ConectionBean has been used. */ public int usageCount; /** * Creates a new instance of ConnectionBean * @param con {@link java.sql.Connection} object in wich this ConnectionBean will be based. * @param mapStatements When set to <I>true</I>, PreparedStatement objects will be stored and reused. */ public ConnectionBean(Connection con, boolean mapStatements) { this.con=con; if(mapStatements) statements=new HashMap<String, PreparedStatement>(); born=new Date(); } /** * Provides information about the current state of the ConnectionBean. * @return Information string, formatted in HTML. */ public String getInfo(){ StringBuilder sb=new StringBuilder(); sb.append("ConnectionBean ").append(hashCode()); if(statements!=null){ sb.append(" (").append(statements.size()).append(" statements)"); } sb.append("<br>\n"); sb.append("Created: ").append(born).append("<br>\n"); sb.append("Usage count: ").append(usageCount).append("<br>\n"); if(lastUsed==null) sb.append("Not yet used!<br>\n"); else{ sb.append("Last used: ").append(lastUsed).append("<br>\n"); sb.append("Last statement: ").append(lastStatement).append("<br>\n"); } if(closed!=null){ sb.append("Closed: ").append(closed).append("<br>\n"); } return sb.toString(); } /** * Provides direct access to the {@link java.sql.Connection} object. * @return The {@link java.sql.Connection} object used in this ConnectionBean. */ public Connection getConnection(){ lastUsed=new Date(); return con; } /** * Creates a PreparedStatement based on the current connection and the provided SQL expression.<BR> * <B>Important:</B> Never call the <B>close()</B> method on Prepared statements obtained * from <CODE>ConnectionBean</CODE> objects created with the <CODE>mapStatements</CODE> option. * @param sql The SQL statement. * @throws SQLException If something goes wrong * @return The {@link java.sql.PreparedStatement} object.<BR> */ public PreparedStatement getPreparedStatement(String sql) throws SQLException{ if(closed!=null) throw new SQLException("Connection closed!"); lastUsed=new Date(); lastStatement=sql; PreparedStatement stmt=(statements==null) ? null : (PreparedStatement)statements.get(sql); if(stmt==null){ stmt=con.prepareStatement(sql); if(statements!=null) statements.put(sql, stmt); } else{ try{ // try - catch because // odbc.jdbc driver throws NullPoiterException on // PreparedStatement.clearParameters // stmt.clearParameters(); } catch(Exception ex){ // eat exception } } return stmt; } /** * Creates a PreparedStatement based on the current connection and the provided SQL expression.<BR> * <B>Important:</B> Never call the <B>close()</B> method on Prepared statements obtained * from <CODE>ConnectionBean</CODE> objects created with the <CODE>mapStatements</CODE> option. * @return The {@link java.sql.PreparedStatement} object.<BR> * @param resultSetType A resultSet type. See {@link java.sql.ResultSet}. * @param resultSetConcurrency A concurrency type. See {@link java.sql.ResultSet}. * @param sql The SQL sentence of the PreparedStatemnt. * @throws SQLException If something goes wrong */ public PreparedStatement getPreparedStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException{ if(closed!=null) throw new SQLException("Connection closed!"); lastUsed=new Date(); lastStatement=sql; PreparedStatement stmt=(statements==null) ? null : (PreparedStatement)statements.get(sql); if(stmt==null){ stmt=con.prepareStatement(sql, resultSetType, resultSetConcurrency); if(statements!=null) statements.put(sql, stmt); } else{ try{ // try - catch because // odbc.jdbc driver throws NullPoiterException on PreparedStatement.clearParameters // stmt.clearParameters(); } catch(Exception ex){ // eat exception } } return stmt; } /** * Closes a {@link java.sql.PreparedStatement} object supplied by a previous call * to <CODE>getPreparedStatement()</CODE>. Applications should always call this method * when the <CODE>PreparedStatement</CODE> is no longer needed, and never directly * call <CODE>close()</CODE> in the <CODE>PreparedStatement</CODE>. * @param stmt The <CODE>PreparedStatement</CODE> to be closed. */ public void closeStatement(PreparedStatement stmt){ closeStatement(stmt, false); } /** * <CODE>ConnectionBeans</CODE> created with the <CODE>mapStatements</CODE> tag set * to <I>true</I> can reuse {@link java.sql.PreparedStatement} objects between calls. * This method is functionally identical to <CODE>closeStatement(PreparedStatement)</CODE>, but * has a param that allows to specify if the statement must be really closed. * @param stmt The <CODE>PreparedStatement</CODE> to be closed. * @param forceClose When <I>true</I>, the statement will be effectively closed. */ public void closeStatement(PreparedStatement stmt, boolean forceClose){ if(stmt!=null){ if(forceClose || statements==null){ try{ stmt.close(); } catch(Exception ex){ System.err.println("Error closing statement: "+stmt); } } if(statements!=null && forceClose){ for(String s : statements.keySet()){ PreparedStatement ps = statements.get(s); if(ps!=null && ps==stmt){ statements.remove(s); break; } } } } } /** * Clears all the stored {@link java.sql.PreparedStatement} objects (if any) and closes * the {@link java.sql.Connection}. * @throws SQLException If something goes wrong. */ public void closeConnection() throws SQLException{ if(closed==null){ closed=new Date(); if(statements!=null){ for(String s : statements.keySet()){ PreparedStatement stmt=statements.get(s); if (stmt != null) { try { stmt.close(); } catch (Exception ex) { // Eat Exception } } } statements.clear(); } con.close(); } } /** * Getter for property lastStatement. * @return Value of property lastStatement. */ public java.lang.String getLastStatement() { return lastStatement; } /** * Returns the number of {@link java.sql.PreparedStatement} objects stored by this * <CODE>ConnectionBean</CODE>. Used only in connection beans created with the <CODE>mapStatements</CODE> * param set to <CODE>true</CODE>. * @return The number of stored statements. */ public int getNumStatements(){ return statements==null ? 0 : statements.size(); } }