001: /*
002:
003: Derby - Class org.apache.derby.client.ClientPooledConnection
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: package org.apache.derby.client;
022:
023: import java.sql.PreparedStatement;
024: import java.sql.SQLException;
025: import org.apache.derby.client.net.NetXAConnection;
026: import org.apache.derby.jdbc.ClientBaseDataSource;
027: import org.apache.derby.jdbc.ClientDataSource;
028: import org.apache.derby.jdbc.ClientDriver;
029: import org.apache.derby.client.am.ClientMessageId;
030: import org.apache.derby.client.am.SqlException;
031: import org.apache.derby.client.net.NetLogWriter;
032: import org.apache.derby.shared.common.reference.SQLState;
033:
034: public class ClientPooledConnection implements
035: javax.sql.PooledConnection {
036: private boolean newPC_ = true;
037:
038: private java.util.Vector listeners_ = null;
039: org.apache.derby.client.am.Connection physicalConnection_ = null;
040: org.apache.derby.client.net.NetConnection netPhysicalConnection_ = null;
041: org.apache.derby.client.net.NetXAConnection netXAPhysicalConnection_ = null;
042:
043: org.apache.derby.client.am.LogicalConnection logicalConnection_ = null;
044:
045: protected org.apache.derby.client.am.LogWriter logWriter_ = null;
046:
047: protected int rmId_ = 0;
048:
049: // Cached stuff from constructor
050: private ClientBaseDataSource ds_;
051: private String user_;
052: private String password_;
053:
054: // Constructor for Non-XA pooled connections.
055: // Using standard Java APIs, a CPDS is passed in.
056: // user/password overrides anything on the ds.
057: public ClientPooledConnection(ClientBaseDataSource ds,
058: org.apache.derby.client.am.LogWriter logWriter,
059: String user, String password) throws SQLException {
060: try {
061: logWriter_ = logWriter;
062: ds_ = ds;
063: user_ = user;
064: password_ = password;
065: listeners_ = new java.util.Vector();
066:
067: //pass the client pooled connection instance to this
068: //instance of the NetConnection object
069: //this object is then used to pass the close and the error events
070: //that occur in the PreparedStatement object back to the
071: //PooledConnection which will then raise the events
072: //on the listeners
073:
074: netPhysicalConnection_ = (org.apache.derby.client.net.NetConnection) ClientDriver
075: .getFactory().newNetConnection(
076: (NetLogWriter) logWriter_, user, password,
077: ds, -1, false, this );
078:
079: physicalConnection_ = netPhysicalConnection_;
080: } catch (SqlException se) {
081: throw se.getSQLException();
082: }
083: }
084:
085: // Constructor for XA pooled connections only.
086: // Using standard Java APIs, a CPDS is passed in.
087: // user/password overrides anything on the ds.
088: public ClientPooledConnection(ClientBaseDataSource ds,
089: org.apache.derby.client.am.LogWriter logWriter,
090: String user, String password, int rmId) throws SQLException {
091: try {
092: logWriter_ = logWriter;
093: ds_ = ds;
094: user_ = user;
095: password_ = password;
096: rmId_ = rmId;
097: listeners_ = new java.util.Vector();
098: netXAPhysicalConnection_ = getNetXAConnection(ds,
099: (NetLogWriter) logWriter_, user, password, rmId);
100: physicalConnection_ = netXAPhysicalConnection_
101: .getNetConnection();
102: } catch (SqlException se) {
103: throw se.getSQLException();
104: }
105: }
106:
107: public ClientPooledConnection(ClientBaseDataSource ds,
108: org.apache.derby.client.am.LogWriter logWriter)
109: throws SQLException {
110: logWriter_ = logWriter;
111: ds_ = ds;
112: listeners_ = new java.util.Vector();
113: try {
114: netPhysicalConnection_ = (org.apache.derby.client.net.NetConnection) ClientDriver
115: .getFactory().newNetConnection(
116: (NetLogWriter) logWriter_, null, null, ds,
117: -1, false);
118:
119: physicalConnection_ = netPhysicalConnection_;
120: } catch (SqlException se) {
121: throw se.getSQLException();
122: }
123: }
124:
125: protected void finalize() throws java.lang.Throwable {
126: if (logWriter_ != null) {
127: logWriter_.traceEntry(this , "finalize");
128: }
129: close();
130: }
131:
132: public synchronized void close() throws SQLException {
133: try {
134: if (logWriter_ != null) {
135: logWriter_.traceEntry(this , "close");
136: }
137:
138: if (logicalConnection_ != null) {
139: logicalConnection_.nullPhysicalConnection();
140: logicalConnection_ = null;
141: }
142:
143: if (physicalConnection_ == null) {
144: return;
145: }
146:
147: // Even if the physcial connection is marked closed (in the pool),
148: // this will close its underlying resources.
149: physicalConnection_.closeResources();
150: } finally {
151: physicalConnection_ = null;
152: }
153: }
154:
155: // This is the standard API for getting a logical connection handle for a pooled connection.
156: // No "resettable" properties are passed, so user, password, and all other properties may not change.
157: public synchronized java.sql.Connection getConnection()
158: throws SQLException {
159: try {
160: if (logWriter_ != null) {
161: logWriter_.traceEntry(this , "getConnection");
162: }
163: createLogicalConnection();
164:
165: if (!newPC_) {
166: // DERBY-1144 changed the last parameter of this method to true
167: // to reset the connection state to the default on
168: // PooledConnection.getConnection() otherwise the
169: // isolation level and holdability was not correct and out of sync with the server.
170: physicalConnection_.reset(logWriter_, user_, password_,
171: ds_, true);
172: } else {
173: physicalConnection_.lightReset(); //poolfix
174: }
175: newPC_ = false;
176:
177: if (logWriter_ != null) {
178: logWriter_.traceExit(this , "getConnection",
179: logicalConnection_);
180: }
181: return logicalConnection_;
182: } catch (SqlException se) {
183: throw se.getSQLException();
184: }
185: }
186:
187: private void createLogicalConnection() throws SqlException {
188: if (physicalConnection_ == null) {
189: throw new SqlException(logWriter_, new ClientMessageId(
190: SQLState.NOGETCONN_ON_CLOSED_POOLED_CONNECTION));
191: }
192:
193: // Roll back any pending transactions. Otherwise we get an exception
194: // when we try to close the connection (even for re-use), with an error
195: // saying we can't close the connection with active transactions
196: // (this fixes DERBY-1004)
197: try {
198: if (physicalConnection_.transactionInProgress()) {
199: physicalConnection_.rollback();
200: }
201: } catch (SQLException sqle) {
202: throw new SqlException(sqle);
203: }
204:
205: // Not the usual case, but if we have an existing logical connection, then we must close it by spec.
206: // We close the logical connection without notifying the pool manager that this pooled connection is availabe for reuse.
207: if (logicalConnection_ != null) {
208: logicalConnection_.closeWithoutRecyclingToPool();
209: }
210: logicalConnection_ = ClientDriver.getFactory()
211: .newLogicalConnection(physicalConnection_, this );
212: }
213:
214: public synchronized void addConnectionEventListener(
215: javax.sql.ConnectionEventListener listener) {
216: if (logWriter_ != null) {
217: logWriter_.traceEntry(this , "addConnectionEventListener",
218: listener);
219: }
220: listeners_.addElement(listener);
221: }
222:
223: public synchronized void removeConnectionEventListener(
224: javax.sql.ConnectionEventListener listener) {
225: if (logWriter_ != null) {
226: logWriter_.traceEntry(this ,
227: "removeConnectionEventListener", listener);
228: }
229: listeners_.removeElement(listener);
230: }
231:
232: // Not public, but needs to be visible to am.LogicalConnection
233: public void recycleConnection() {
234: if (physicalConnection_.agent_.loggingEnabled()) {
235: physicalConnection_.agent_.logWriter_.traceEntry(this ,
236: "recycleConnection");
237: }
238:
239: for (java.util.Enumeration e = listeners_.elements(); e
240: .hasMoreElements();) {
241: javax.sql.ConnectionEventListener listener = (javax.sql.ConnectionEventListener) e
242: .nextElement();
243: javax.sql.ConnectionEvent event = new javax.sql.ConnectionEvent(
244: this );
245: listener.connectionClosed(event);
246: }
247: }
248:
249: // Not public, but needs to be visible to am.LogicalConnection
250: public void trashConnection(SqlException exception) {
251: for (java.util.Enumeration e = listeners_.elements(); e
252: .hasMoreElements();) {
253: javax.sql.ConnectionEventListener listener = (javax.sql.ConnectionEventListener) e
254: .nextElement();
255: java.sql.SQLException sqle = exception.getSQLException();
256: javax.sql.ConnectionEvent event = new javax.sql.ConnectionEvent(
257: this , sqle);
258: listener.connectionErrorOccurred(event);
259: }
260: }
261:
262: // Used by LogicalConnection close when it disassociates itself from the ClientPooledConnection
263: public synchronized void nullLogicalConnection() {
264: logicalConnection_ = null;
265: }
266:
267: /*-----------------------------------------------------------------*/
268: /*
269: * These methods are needed to provide StatementEvent support for
270: * derby.
271: * They are actually implemented in EmbedPooledConnection40 but have
272: * a dummy implementation here
273: */
274:
275: /**
276: *
277: * The onStatementClose contains the logic for raising the Statement Closed
278: * events. This method has a dummy implementation here to avoid error when
279: * this class is compiled with jdk1.4. The class the actual implementation
280: * in ClientPooledConnection40.
281: *
282: * @param statement The PreparedStatement that was closed
283: *
284: */
285: public void onStatementClose(PreparedStatement statement) {
286:
287: }
288:
289: /**
290: * The method contains the logic for raising the Statement error occurred
291: * events. This method has a dummy implementation here to avoid error when
292: * this class is compiled with jdk1.4. The class the actual implementation
293: * in ClientPooledConnection40.
294: *
295: * @param statement The PreparedStatement that was closed
296: * @param sqle The SQLException associated with the error that caused
297: * the invalidation of this PreparedStatement
298: */
299: public void onStatementErrorOccurred(PreparedStatement statement,
300: SQLException sqle) {
301:
302: }
303:
304: /**
305: * creates and returns NetXAConnection.
306: * Overwrite this method to create different version of NetXAConnection
307: * @param ds
308: * @param logWriter
309: * @param user
310: * @param password
311: * @param rmId
312: * @return NetXAConnection
313: */
314: protected NetXAConnection getNetXAConnection(
315: ClientBaseDataSource ds, NetLogWriter logWriter,
316: String user, String password, int rmId) throws SqlException {
317: return new NetXAConnection(logWriter, user, password, ds, rmId,
318: true, this);
319:
320: }
321: }
|