001: /*
002: Copyright (C) 2002-2007 MySQL AB
003:
004: This program is free software; you can redistribute it and/or modify
005: it under the terms of version 2 of the GNU General Public License as
006: published by the Free Software Foundation.
007:
008: There are special exceptions to the terms and conditions of the GPL
009: as it is applied to this software. View the full text of the
010: exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
011: software distribution.
012:
013: This program is distributed in the hope that it will be useful,
014: but WITHOUT ANY WARRANTY; without even the implied warranty of
015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: GNU General Public License for more details.
017:
018: You should have received a copy of the GNU General Public License
019: along with this program; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021:
022:
023:
024: */
025: package com.mysql.jdbc.jdbc2.optional;
026:
027: import java.lang.reflect.InvocationHandler;
028: import java.lang.reflect.InvocationTargetException;
029: import java.lang.reflect.Method;
030: import java.lang.reflect.Proxy;
031: import java.sql.Array;
032: import java.sql.Blob;
033: import java.sql.Clob;
034: import java.sql.Connection;
035: import java.sql.NClob;
036: import java.sql.SQLClientInfoException;
037: import java.sql.SQLException;
038: import java.sql.SQLXML;
039: import java.sql.Savepoint;
040: import java.sql.Statement;
041: import java.sql.Struct;
042: import java.util.ArrayList;
043: import java.util.HashMap;
044: import java.util.List;
045: import java.util.Map;
046: import java.util.Properties;
047:
048: import com.mysql.jdbc.ConnectionImpl;
049: import com.mysql.jdbc.SQLError;
050: import com.mysql.jdbc.jdbc2.optional.ConnectionWrapper;
051: import com.mysql.jdbc.jdbc2.optional.MysqlPooledConnection;
052:
053: /**
054: */
055: public class JDBC4StatementWrapper extends StatementWrapper {
056:
057: protected JDBC4StatementWrapper(ConnectionWrapper c,
058: MysqlPooledConnection conn, Statement toWrap) {
059: super (c, conn, toWrap);
060: }
061:
062: public void close() throws SQLException {
063: try {
064: super .close();
065: } finally {
066: this .unwrappedInterfaces = null;
067: }
068: }
069:
070: public boolean isClosed() throws SQLException {
071: try {
072: if (this .wrappedStmt != null) {
073: return this .wrappedStmt.isClosed();
074: } else {
075: throw SQLError.createSQLException(
076: "Statement already closed",
077: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
078: }
079: } catch (SQLException sqlEx) {
080: checkAndFireConnectionError(sqlEx);
081: }
082:
083: return false; // We never get here, compiler can't tell
084: }
085:
086: public void setPoolable(boolean poolable) throws SQLException {
087: try {
088: if (this .wrappedStmt != null) {
089: this .wrappedStmt.setPoolable(poolable);
090: } else {
091: throw SQLError.createSQLException(
092: "Statement already closed",
093: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
094: }
095: } catch (SQLException sqlEx) {
096: checkAndFireConnectionError(sqlEx);
097: }
098: }
099:
100: public boolean isPoolable() throws SQLException {
101: try {
102: if (this .wrappedStmt != null) {
103: return this .wrappedStmt.isPoolable();
104: } else {
105: throw SQLError.createSQLException(
106: "Statement already closed",
107: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
108: }
109: } catch (SQLException sqlEx) {
110: checkAndFireConnectionError(sqlEx);
111: }
112:
113: return false; // We never get here, compiler can't tell
114: }
115:
116: /**
117: * Returns true if this either implements the interface argument or is
118: * directly or indirectly a wrapper for an object that does. Returns false
119: * otherwise. If this implements the interface then return true, else if
120: * this is a wrapper then return the result of recursively calling
121: * <code>isWrapperFor</code> on the wrapped object. If this does not
122: * implement the interface and is not a wrapper, return false. This method
123: * should be implemented as a low-cost operation compared to
124: * <code>unwrap</code> so that callers can use this method to avoid
125: * expensive <code>unwrap</code> calls that may fail. If this method
126: * returns true then calling <code>unwrap</code> with the same argument
127: * should succeed.
128: *
129: * @param interfaces
130: * a Class defining an interface.
131: * @return true if this implements the interface or directly or indirectly
132: * wraps an object that does.
133: * @throws java.sql.SQLException
134: * if an error occurs while determining whether this is a
135: * wrapper for an object with the given interface.
136: * @since 1.6
137: */
138: public boolean isWrapperFor(Class<?> iface) throws SQLException {
139:
140: boolean isInstance = iface.isInstance(this );
141:
142: if (isInstance) {
143: return true;
144: }
145:
146: String interfaceClassName = iface.getName();
147:
148: return (interfaceClassName.equals("com.mysql.jdbc.Statement")
149: || interfaceClassName.equals("java.sql.Statement") || interfaceClassName
150: .equals("java.sql.Wrapper"));
151: }
152:
153: /**
154: * Returns an object that implements the given interface to allow access to
155: * non-standard methods, or standard methods not exposed by the proxy. The
156: * result may be either the object found to implement the interface or a
157: * proxy for that object. If the receiver implements the interface then that
158: * is the object. If the receiver is a wrapper and the wrapped object
159: * implements the interface then that is the object. Otherwise the object is
160: * the result of calling <code>unwrap</code> recursively on the wrapped
161: * object. If the receiver is not a wrapper and does not implement the
162: * interface, then an <code>SQLException</code> is thrown.
163: *
164: * @param iface
165: * A Class defining an interface that the result must implement.
166: * @return an object that implements the interface. May be a proxy for the
167: * actual implementing object.
168: * @throws java.sql.SQLException
169: * If no object found that implements the interface
170: * @since 1.6
171: */
172: public synchronized <T> T unwrap(java.lang.Class<T> iface)
173: throws java.sql.SQLException {
174: try {
175: if ("java.sql.Statement".equals(iface.getName())
176: || "java.sql.Wrapper.class".equals(iface.getName())) {
177: return iface.cast(this );
178: }
179:
180: if (unwrappedInterfaces == null) {
181: unwrappedInterfaces = new HashMap();
182: }
183:
184: Object cachedUnwrapped = unwrappedInterfaces.get(iface);
185:
186: if (cachedUnwrapped == null) {
187: cachedUnwrapped = Proxy.newProxyInstance(
188: this .wrappedStmt.getClass().getClassLoader(),
189: new Class[] { iface },
190: new ConnectionErrorFiringInvocationHandler(
191: this .wrappedStmt));
192: unwrappedInterfaces.put(iface, cachedUnwrapped);
193: }
194:
195: return iface.cast(cachedUnwrapped);
196: } catch (ClassCastException cce) {
197: throw SQLError.createSQLException("Unable to unwrap to "
198: + iface.toString(),
199: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
200: }
201: }
202: }
|