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:
051: /**
052: */
053: public class JDBC4ConnectionWrapper extends ConnectionWrapper {
054:
055: /**
056: * Construct a new LogicalHandle and set instance variables
057: *
058: * @param mysqlPooledConnection
059: * reference to object that instantiated this object
060: * @param mysqlConnection
061: * physical connection to db
062: *
063: * @throws SQLException
064: * if an error occurs.
065: */
066: public JDBC4ConnectionWrapper(
067: MysqlPooledConnection mysqlPooledConnection,
068: ConnectionImpl mysqlConnection, boolean forXa)
069: throws SQLException {
070: super (mysqlPooledConnection, mysqlConnection, forXa);
071: }
072:
073: public void close() throws SQLException {
074: try {
075: super .close();
076: } finally {
077: this .unwrappedInterfaces = null;
078: }
079: }
080:
081: public SQLXML createSQLXML() throws SQLException {
082: checkClosed();
083:
084: try {
085: return ((java.sql.Connection) this .mc).createSQLXML();
086: } catch (SQLException sqlException) {
087: checkAndFireConnectionError(sqlException);
088: }
089:
090: return null; // never reached, but compiler can't tell
091: }
092:
093: public java.sql.Array createArrayOf(String typeName,
094: Object[] elements) throws SQLException {
095: checkClosed();
096:
097: try {
098: return ((java.sql.Connection) this .mc).createArrayOf(
099: typeName, elements);
100: } catch (SQLException sqlException) {
101: checkAndFireConnectionError(sqlException);
102: }
103:
104: return null; // never reached, but compiler can't tell
105: }
106:
107: public Struct createStruct(String typeName, Object[] attributes)
108: throws SQLException {
109: checkClosed();
110:
111: try {
112: return ((java.sql.Connection) this .mc).createStruct(
113: typeName, attributes);
114: } catch (SQLException sqlException) {
115: checkAndFireConnectionError(sqlException);
116: }
117:
118: return null; // never reached, but compiler can't tell
119: }
120:
121: public Properties getClientInfo() throws SQLException {
122: checkClosed();
123:
124: try {
125: return ((java.sql.Connection) this .mc).getClientInfo();
126: } catch (SQLException sqlException) {
127: checkAndFireConnectionError(sqlException);
128: }
129:
130: return null; // never reached, but compiler can't tell
131: }
132:
133: public String getClientInfo(String name) throws SQLException {
134: checkClosed();
135:
136: try {
137: return ((java.sql.Connection) this .mc).getClientInfo(name);
138: } catch (SQLException sqlException) {
139: checkAndFireConnectionError(sqlException);
140: }
141:
142: return null; // never reached, but compiler can't tell
143: }
144:
145: /**
146: * Returns true if the connection has not been closed and is still valid.
147: * The driver shall submit a query on the connection or use some other
148: * mechanism that positively verifies the connection is still valid when
149: * this method is called.
150: * <p>
151: * The query submitted by the driver to validate the connection shall be
152: * executed in the context of the current transaction.
153: *
154: * @param timeout -
155: * The time in seconds to wait for the database operation used to
156: * validate the connection to complete. If the timeout period
157: * expires before the operation completes, this method returns
158: * false. A value of 0 indicates a timeout is not applied to the
159: * database operation.
160: * <p>
161: * @return true if the connection is valid, false otherwise
162: * @exception SQLException
163: * if the value supplied for <code>timeout</code> is less
164: * then 0
165: * @since 1.6
166: */
167: public synchronized boolean isValid(int timeout)
168: throws SQLException {
169: try {
170: return ((java.sql.Connection) this .mc).isValid(timeout);
171: } catch (SQLException sqlException) {
172: checkAndFireConnectionError(sqlException);
173: }
174:
175: return false; // never reached, but compiler can't tell
176: }
177:
178: public void setClientInfo(Properties properties)
179: throws SQLClientInfoException {
180: try {
181: checkClosed();
182:
183: ((java.sql.Connection) this .mc).setClientInfo(properties);
184: } catch (SQLException sqlException) {
185: try {
186: checkAndFireConnectionError(sqlException);
187: } catch (SQLException sqlEx2) {
188: SQLClientInfoException clientEx = new SQLClientInfoException();
189: clientEx.initCause(sqlEx2);
190:
191: throw clientEx;
192: }
193: }
194: }
195:
196: public void setClientInfo(String name, String value)
197: throws SQLClientInfoException {
198: try {
199: checkClosed();
200:
201: ((java.sql.Connection) this .mc).setClientInfo(name, value);
202: } catch (SQLException sqlException) {
203: try {
204: checkAndFireConnectionError(sqlException);
205: } catch (SQLException sqlEx2) {
206: SQLClientInfoException clientEx = new SQLClientInfoException();
207: clientEx.initCause(sqlEx2);
208:
209: throw clientEx;
210: }
211: }
212: }
213:
214: /**
215: * Returns true if this either implements the interface argument or is
216: * directly or indirectly a wrapper for an object that does. Returns false
217: * otherwise. If this implements the interface then return true, else if
218: * this is a wrapper then return the result of recursively calling
219: * <code>isWrapperFor</code> on the wrapped object. If this does not
220: * implement the interface and is not a wrapper, return false. This method
221: * should be implemented as a low-cost operation compared to
222: * <code>unwrap</code> so that callers can use this method to avoid
223: * expensive <code>unwrap</code> calls that may fail. If this method
224: * returns true then calling <code>unwrap</code> with the same argument
225: * should succeed.
226: *
227: * @param interfaces
228: * a Class defining an interface.
229: * @return true if this implements the interface or directly or indirectly
230: * wraps an object that does.
231: * @throws java.sql.SQLException
232: * if an error occurs while determining whether this is a
233: * wrapper for an object with the given interface.
234: * @since 1.6
235: */
236: public boolean isWrapperFor(Class<?> iface) throws SQLException {
237: checkClosed();
238:
239: boolean isInstance = iface.isInstance(this );
240:
241: if (isInstance) {
242: return true;
243: }
244:
245: return (iface.getName().equals("com.mysql.jdbc.Connection") || iface
246: .getName()
247: .equals("com.mysql.jdbc.ConnectionProperties"));
248: }
249:
250: /**
251: * Returns an object that implements the given interface to allow access to
252: * non-standard methods, or standard methods not exposed by the proxy. The
253: * result may be either the object found to implement the interface or a
254: * proxy for that object. If the receiver implements the interface then that
255: * is the object. If the receiver is a wrapper and the wrapped object
256: * implements the interface then that is the object. Otherwise the object is
257: * the result of calling <code>unwrap</code> recursively on the wrapped
258: * object. If the receiver is not a wrapper and does not implement the
259: * interface, then an <code>SQLException</code> is thrown.
260: *
261: * @param iface
262: * A Class defining an interface that the result must implement.
263: * @return an object that implements the interface. May be a proxy for the
264: * actual implementing object.
265: * @throws java.sql.SQLException
266: * If no object found that implements the interface
267: * @since 1.6
268: */
269: public synchronized <T> T unwrap(java.lang.Class<T> iface)
270: throws java.sql.SQLException {
271: try {
272: if ("java.sql.Connection".equals(iface.getName())
273: || "java.sql.Wrapper.class".equals(iface.getName())) {
274: return iface.cast(this );
275: }
276:
277: if (unwrappedInterfaces == null) {
278: unwrappedInterfaces = new HashMap();
279: }
280:
281: Object cachedUnwrapped = unwrappedInterfaces.get(iface);
282:
283: if (cachedUnwrapped == null) {
284: cachedUnwrapped = Proxy.newProxyInstance(this .mc
285: .getClass().getClassLoader(),
286: new Class[] { iface },
287: new ConnectionErrorFiringInvocationHandler(
288: this .mc));
289: unwrappedInterfaces.put(iface, cachedUnwrapped);
290: }
291:
292: return iface.cast(cachedUnwrapped);
293: } catch (ClassCastException cce) {
294: throw SQLError.createSQLException("Unable to unwrap to "
295: + iface.toString(),
296: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
297: }
298: }
299:
300: /**
301: * @see java.sql.Connection#createBlob()
302: */
303: public Blob createBlob() throws SQLException {
304: checkClosed();
305:
306: try {
307: return ((java.sql.Connection) this .mc).createBlob();
308: } catch (SQLException sqlException) {
309: checkAndFireConnectionError(sqlException);
310: }
311:
312: return null; // never reached, but compiler can't tell
313: }
314:
315: /**
316: * @see java.sql.Connection#createClob()
317: */
318: public Clob createClob() throws SQLException {
319: checkClosed();
320:
321: try {
322: return ((java.sql.Connection) this .mc).createClob();
323: } catch (SQLException sqlException) {
324: checkAndFireConnectionError(sqlException);
325: }
326:
327: return null; // never reached, but compiler can't tell
328: }
329:
330: /**
331: * @see java.sql.Connection#createNClob()
332: */
333: public NClob createNClob() throws SQLException {
334: checkClosed();
335:
336: try {
337: return ((java.sql.Connection) this .mc).createNClob();
338: } catch (SQLException sqlException) {
339: checkAndFireConnectionError(sqlException);
340: }
341:
342: return null; // never reached, but compiler can't tell
343: }
344: }
|