diff --git a/src/java/com/samskivert/jdbc/AutoCloseOperation.java b/src/java/com/samskivert/jdbc/AutoCloseOperation.java new file mode 100644 index 00000000..0d6f9d6d --- /dev/null +++ b/src/java/com/samskivert/jdbc/AutoCloseOperation.java @@ -0,0 +1,85 @@ +// +// $Id$ +// +// samskivert library - useful routines for java programs +// Copyright (C) 2001-2009 Michael Bayne +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.jdbc; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +import java.util.ArrayList; +import java.util.List; + +import com.samskivert.io.PersistenceException; + +/** + * An {@link Repository.Operation} wrapper that automatically closes all statements opened by the + * operation. + * + * @author Charlie Groves + */ +public abstract class AutoCloseOperation + implements Repository.Operation +{ + /** + * See {@link Repository.Operation#invoke}. Any Statement or PreparedStatement objects created + * during the invocation of this method will automatically be closed. + */ + public abstract V cleanInvoke (Connection conn, DatabaseLiaison liason) + throws SQLException, PersistenceException; + + /** + * Invokes {@link #cleanInvoke} and then closes any statements opened by that call. + */ + public final V invoke (final Connection conn, DatabaseLiaison liaison) + throws SQLException, PersistenceException + { + // create a proxy to conn that collects any returned instances of Statement in stmts + final List stmts = new ArrayList(1); + Connection proxy = (Connection)Proxy.newProxyInstance( + Connection.class.getClassLoader(), PROXY_IFACES, new InvocationHandler() { + public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { + Object result = method.invoke(conn, args); + if (result instanceof Statement) { + stmts.add((Statement)result); + } + return result; + } + }); + + try { + return cleanInvoke(proxy, liaison); + } finally { + // if closing a statement throws an SQLException, we don't attempt to close the rest of + // the statements -- an SQLException thrown on close is a problem with the underlying + // connection and the SimpleRepository closes the connection when it gets an exception + // like that; the resources for the remaining statements will be collected in that case + for (Statement stmt : stmts) { + JDBCUtil.close(stmt); + } + } + } + + protected static Class[] PROXY_IFACES = { Connection.class }; +}