001: /*
002:
003: Derby - Class org.apache.derby.client.net.NetConnection40
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.client.net;
023:
024: import java.sql.Array;
025: import org.apache.derby.client.am.SQLExceptionFactory;
026: import org.apache.derby.client.am.SqlException;
027: import java.sql.Blob;
028: import java.sql.Clob;
029: import java.sql.Connection;
030: import java.sql.NClob;
031: import java.sql.PreparedStatement;
032: import java.sql.ResultSet;
033: import java.sql.SQLClientInfoException;
034: import java.sql.SQLException;
035: import java.sql.SQLXML;
036: import java.sql.Struct;
037: import java.util.HashMap;
038: import java.util.Map;
039: import java.util.Properties;
040: import java.util.Enumeration;
041: import org.apache.derby.client.ClientPooledConnection;
042: import org.apache.derby.client.am.ClientMessageId;
043: import org.apache.derby.client.am.FailedProperties40;
044: import org.apache.derby.shared.common.reference.SQLState;
045:
046: public class NetConnection40 extends
047: org.apache.derby.client.net.NetConnection {
048: /**
049: * Prepared statement that is used each time isValid() is called on this
050: * connection. The statement is created the first time isValid is called
051: * and closed when the connection is closed (by the close call).
052: */
053: private PreparedStatement isValidStmt = null;
054:
055: /*
056: *-------------------------------------------------------
057: * JDBC 4.0
058: *-------------------------------------------------------
059: */
060:
061: public NetConnection40(NetLogWriter netLogWriter,
062: String databaseName, java.util.Properties properties)
063: throws SqlException {
064: super (netLogWriter, databaseName, properties);
065: }
066:
067: public NetConnection40(NetLogWriter netLogWriter,
068: org.apache.derby.jdbc.ClientBaseDataSource dataSource,
069: String user, String password) throws SqlException {
070: super (netLogWriter, dataSource, user, password);
071: }
072:
073: public NetConnection40(NetLogWriter netLogWriter,
074: int driverManagerLoginTimeout, String serverName,
075: int portNumber, String databaseName,
076: java.util.Properties properties) throws SqlException {
077: super (netLogWriter, driverManagerLoginTimeout, serverName,
078: portNumber, databaseName, properties);
079: }
080:
081: public NetConnection40(NetLogWriter netLogWriter, String user,
082: String password,
083: org.apache.derby.jdbc.ClientBaseDataSource dataSource,
084: int rmId, boolean isXAConn) throws SqlException {
085: super (netLogWriter, user, password, dataSource, rmId, isXAConn);
086: }
087:
088: public NetConnection40(NetLogWriter netLogWriter, String ipaddr,
089: int portNumber,
090: org.apache.derby.jdbc.ClientBaseDataSource dataSource,
091: boolean isXAConn) throws SqlException {
092: super (netLogWriter, ipaddr, portNumber, dataSource, isXAConn);
093: }
094:
095: /**
096: * The constructor for the NetConnection40 class which contains
097: * implementations of JDBC 4.0 specific methods in the java.sql.Connection
098: * interface. This constructor is called from the ClientPooledConnection object
099: * to enable the NetConnection to pass <code>this</code> on to the associated
100: * prepared statement object thus enabling the prepared statement object
101: * to inturn raise the statement events to the ClientPooledConnection object.
102: *
103: * @param netLogWriter NetLogWriter object associated with this connection.
104: * @param user user id for this connection.
105: * @param password password for this connection.
106: * @param dataSource The DataSource object passed from the PooledConnection
107: * object from which this constructor was called.
108: * @param rmId The Resource manager ID for XA Connections
109: * @param isXAConn true if this is a XA connection.
110: * @param cpc The ClientPooledConnection object from which this
111: * NetConnection constructor was called. This is used
112: * to pass StatementEvents back to the pooledConnection
113: * object.
114: * @throws SqlException
115: */
116:
117: public NetConnection40(NetLogWriter netLogWriter, String user,
118: String password,
119: org.apache.derby.jdbc.ClientBaseDataSource dataSource,
120: int rmId, boolean isXAConn, ClientPooledConnection cpc)
121: throws SqlException {
122: super (netLogWriter, user, password, dataSource, rmId, isXAConn,
123: cpc);
124: }
125:
126: public Array createArrayOf(String typeName, Object[] elements)
127: throws SQLException {
128: throw SQLExceptionFactory
129: .notImplemented("createArrayOf(String,Object[])");
130: }
131:
132: /**
133: * Constructs an object that implements the Clob interface. The object
134: * returned initially contains no data.
135: * @return An object that implements the Clob interface
136: * @throws SQLException if an object that implements the
137: * Clob interface can not be constructed.
138: *
139: */
140:
141: public Clob createClob() throws SQLException {
142: try {
143: checkForClosedConnection();
144: } catch (SqlException se) {
145: throw se.getSQLException();
146: }
147: org.apache.derby.client.am.Clob clob = new org.apache.derby.client.am.Clob(
148: this .agent_, "");
149: return clob;
150: }
151:
152: /**
153: * Constructs an object that implements the Clob interface. The object
154: * returned initially contains no data.
155: * @return An object that implements the Clob interface
156: * @throws SQLException if an object that implements the
157: * Clob interface can not be constructed.
158: *
159: */
160:
161: public Blob createBlob() throws SQLException {
162: try {
163: checkForClosedConnection();
164: } catch (SqlException se) {
165: throw se.getSQLException();
166: }
167: org.apache.derby.client.am.Blob blob = new org.apache.derby.client.am.Blob(
168: new byte[0], this .agent_, 0);
169: return blob;
170: }
171:
172: public NClob createNClob() throws SQLException {
173: throw SQLExceptionFactory.notImplemented("createNClob ()");
174: }
175:
176: public SQLXML createSQLXML() throws SQLException {
177: throw SQLExceptionFactory.notImplemented("createSQLXML ()");
178: }
179:
180: public Struct createStruct(String typeName, Object[] attributes)
181: throws SQLException {
182: throw SQLExceptionFactory
183: .notImplemented("createStruct(String,Object[])");
184: }
185:
186: /**
187: * Checks if the connection has not been closed and is still valid.
188: * The validity is checked by running a simple query against the
189: * database.
190: *
191: * The timeout specified by the caller is implemented as follows:
192: * On the server: uses the queryTimeout functionality to make the
193: * query time out on the server in case the server has problems or
194: * is highly loaded.
195: * On the client: uses a timeout on the socket to make sure that
196: * the client is not blocked forever in the cases where the server
197: * is "hanging" or not sending the reply.
198: *
199: * @param timeout The time in seconds to wait for the database
200: * operation used to validate the connection to complete. If the
201: * timeout period expires before the operation completes, this
202: * method returns false. A value of 0 indicates a timeout is not
203: * applied to the database operation.
204: * @return true if the connection is valid, false otherwise
205: * @exception SQLException if the parameter value is illegal or if a
206: * database error has occured
207: */
208: public boolean isValid(int timeout) throws SQLException {
209: // Validate that the timeout has a legal value
210: if (timeout < 0) {
211: throw new SqlException(
212: agent_.logWriter_,
213: new ClientMessageId(SQLState.INVALID_API_PARAMETER),
214: new Integer(timeout), "timeout",
215: "java.sql.Connection.isValid").getSQLException();
216: }
217:
218: // Check if the connection is closed
219: if (isClosed()) {
220: return false;
221: }
222:
223: // Do a simple query against the database
224: synchronized (this ) {
225: try {
226: // Save the current network timeout value
227: int oldTimeout = netAgent_.getTimeout();
228:
229: // Set the required timeout value on the network connection
230: netAgent_.setTimeout(timeout);
231:
232: // If this is the first time this method is called on this
233: // connection we prepare the query
234: if (isValidStmt == null) {
235: isValidStmt = prepareStatement("VALUES (1)");
236: }
237:
238: // Set the query timeout
239: isValidStmt.setQueryTimeout(timeout);
240:
241: // Run the query against the database
242: ResultSet rs = isValidStmt.executeQuery();
243: rs.close();
244:
245: // Restore the previous timeout value
246: netAgent_.setTimeout(oldTimeout);
247: } catch (SQLException e) {
248: // If an SQL exception is thrown the connection is not valid,
249: // we ignore the exception and return false.
250: return false;
251: }
252: }
253:
254: return true; // The connection is valid
255: }
256:
257: /**
258: * Close the connection and release its resources.
259: * @exception SQLException if a database-access error occurs.
260: */
261: synchronized public void close() throws SQLException {
262: // Release resources owned by the prepared statement used by isValid
263: if (isValidStmt != null) {
264: isValidStmt.close();
265: isValidStmt = null;
266: }
267: super .close();
268: }
269:
270: /**
271: * <code>setClientInfo</code> will always throw a
272: * <code>SQLClientInfoException</code> since Derby does not support
273: * any properties.
274: *
275: * @param name a property key <code>String</code>
276: * @param value a property value <code>String</code>
277: * @exception SQLException always.
278: */
279: public void setClientInfo(String name, String value)
280: throws SQLClientInfoException {
281: Properties p = FailedProperties40.makeProperties(name, value);
282: try {
283: checkForClosedConnection();
284: } catch (SqlException se) {
285: throw new SQLClientInfoException(se.getMessage(), se
286: .getSQLState(), new FailedProperties40(p)
287: .getProperties());
288: }
289:
290: if (name == null && value == null) {
291: return;
292: }
293: setClientInfo(p);
294: }
295:
296: /**
297: * <code>setClientInfo</code> will throw a
298: * <code>SQLClientInfoException</code> uless the <code>properties</code>
299: * paramenter is empty, since Derby does not support any
300: * properties. All the property keys in the
301: * <code>properties</code> parameter are added to failedProperties
302: * of the exception thrown, with REASON_UNKNOWN_PROPERTY as the
303: * value.
304: *
305: * @param properties a <code>Properties</code> object with the
306: * properties to set.
307: * @exception SQLClientInfoException unless the properties
308: * parameter is null or empty.
309: */
310: public void setClientInfo(Properties properties)
311: throws SQLClientInfoException {
312: FailedProperties40 fp = new FailedProperties40(properties);
313: try {
314: checkForClosedConnection();
315: } catch (SqlException se) {
316: throw new SQLClientInfoException(se.getMessage(), se
317: .getSQLState(), fp.getProperties());
318: }
319:
320: if (properties == null || properties.isEmpty()) {
321: return;
322: }
323:
324: SqlException se = new SqlException(agent_.logWriter_,
325: new ClientMessageId(
326: SQLState.PROPERTY_UNSUPPORTED_CHANGE), fp
327: .getFirstKey(), fp.getFirstValue());
328: throw new SQLClientInfoException(se.getMessage(), se
329: .getSQLState(), fp.getProperties());
330: }
331:
332: /**
333: * <code>getClientInfo</code> always returns a
334: * <code>null String</code> since Derby doesn't support
335: * ClientInfoProperties.
336: *
337: * @param name a <code>String</code> value
338: * @return a <code>null String</code> value
339: * @exception SQLException if the connection is closed.
340: */
341: public String getClientInfo(String name) throws SQLException {
342: try {
343: checkForClosedConnection();
344: return null;
345: } catch (SqlException se) {
346: throw se.getSQLException();
347: }
348: }
349:
350: /**
351: * <code>getClientInfo</code> always returns an empty
352: * <code>Properties</code> object since Derby doesn't support
353: * ClientInfoProperties.
354: *
355: * @return an empty <code>Properties</code> object.
356: * @exception SQLException if the connection is closed.
357: */
358: public Properties getClientInfo() throws SQLException {
359: try {
360: checkForClosedConnection();
361: return new Properties();
362: } catch (SqlException se) {
363: throw se.getSQLException();
364: }
365: }
366:
367: /**
368: * Returns the type map for this connection.
369: *
370: * @return type map for this connection
371: * @exception SQLException if a database access error occurs
372: */
373: public final Map<String, Class<?>> getTypeMap() throws SQLException {
374: // This method is already implemented with a non-generic
375: // signature in am/Connection. We could just use that method
376: // directly, but then we get a compiler warning (unchecked
377: // cast/conversion). Copy the map to avoid the compiler
378: // warning.
379: Map typeMap = super .getTypeMap();
380: if (typeMap == null)
381: return null;
382: Map<String, Class<?>> genericTypeMap = new HashMap<String, Class<?>>();
383: for (Object key : typeMap.keySet()) {
384: genericTypeMap.put((String) key, (Class) typeMap.get(key));
385: }
386: return genericTypeMap;
387: }
388:
389: /**
390: * Returns false unless <code>interfaces</code> is implemented
391: *
392: * @param interfaces a Class defining an interface.
393: * @return true if this implements the interface or
394: * directly or indirectly wraps an object
395: * that does.
396: * @throws java.sql.SQLException if an error occurs while determining
397: * whether this is a wrapper for an object
398: * with the given interface.
399: */
400: public boolean isWrapperFor(Class<?> interfaces)
401: throws SQLException {
402: try {
403: checkForClosedConnection();
404: } catch (SqlException se) {
405: throw se.getSQLException();
406: }
407: return interfaces.isInstance(this );
408: }
409:
410: /**
411: * Returns <code>this</code> if this class implements the interface
412: *
413: * @param interfaces a Class defining an interface
414: * @return an object that implements the interface
415: * @throws java.sql.SQLException if no object if found that implements the
416: * interface
417: */
418: public <T> T unwrap(java.lang.Class<T> interfaces)
419: throws SQLException {
420: try {
421: checkForClosedConnection();
422: return interfaces.cast(this );
423: } catch (ClassCastException cce) {
424: throw new SqlException(null, new ClientMessageId(
425: SQLState.UNABLE_TO_UNWRAP), interfaces)
426: .getSQLException();
427: } catch (SqlException se) {
428: throw se.getSQLException();
429: }
430: }
431:
432: }
|