1 | /* |
2 | |
3 | Derby - Class org.apache.derby.client.ClientPooledConnection |
4 | |
5 | Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | package org.apache.derby.client; |
21 | |
22 | import java.sql.PreparedStatement; |
23 | import java.sql.SQLException; |
24 | import org.apache.derby.client.net.NetXAConnection; |
25 | import org.apache.derby.jdbc.ClientBaseDataSource; |
26 | import org.apache.derby.jdbc.ClientDataSource; |
27 | import org.apache.derby.jdbc.ClientDriver; |
28 | import org.apache.derby.client.am.ClientMessageId; |
29 | import org.apache.derby.client.am.SqlException; |
30 | import org.apache.derby.client.net.NetLogWriter; |
31 | import org.apache.derby.shared.common.reference.SQLState; |
32 | |
33 | public class ClientPooledConnection implements javax.sql.PooledConnection { |
34 | private boolean newPC_ = true; |
35 | |
36 | private java.util.Vector listeners_ = null; |
37 | org.apache.derby.client.am.Connection physicalConnection_ = null; |
38 | org.apache.derby.client.net.NetConnection netPhysicalConnection_ = null; |
39 | org.apache.derby.client.net.NetXAConnection netXAPhysicalConnection_ = null; |
40 | |
41 | org.apache.derby.client.am.LogicalConnection logicalConnection_ = null; |
42 | |
43 | protected org.apache.derby.client.am.LogWriter logWriter_ = null; |
44 | |
45 | protected int rmId_ = 0; |
46 | |
47 | // Cached stuff from constructor |
48 | private ClientBaseDataSource ds_; |
49 | private String user_; |
50 | private String password_; |
51 | |
52 | // Constructor for Non-XA pooled connections. |
53 | // Using standard Java APIs, a CPDS is passed in. |
54 | // user/password overrides anything on the ds. |
55 | public ClientPooledConnection(ClientBaseDataSource ds, |
56 | org.apache.derby.client.am.LogWriter logWriter, |
57 | String user, |
58 | String password) throws SQLException { |
59 | try |
60 | { |
61 | logWriter_ = logWriter; |
62 | ds_ = ds; |
63 | user_ = user; |
64 | password_ = password; |
65 | listeners_ = new java.util.Vector(); |
66 | |
67 | //pass the client pooled connection instance to this |
68 | //instance of the NetConnection object |
69 | //this object is then used to pass the close and the error events |
70 | //that occur in the PreparedStatement object back to the |
71 | //PooledConnection which will then raise the events |
72 | //on the listeners |
73 | |
74 | netPhysicalConnection_ = (org.apache.derby.client.net.NetConnection) |
75 | ClientDriver.getFactory().newNetConnection( |
76 | (NetLogWriter) logWriter_, |
77 | user, |
78 | password, |
79 | ds, |
80 | -1, |
81 | false, |
82 | this); |
83 | |
84 | physicalConnection_ = netPhysicalConnection_; |
85 | } |
86 | catch ( SqlException se ) |
87 | { |
88 | throw se.getSQLException(); |
89 | } |
90 | } |
91 | |
92 | // Constructor for XA pooled connections only. |
93 | // Using standard Java APIs, a CPDS is passed in. |
94 | // user/password overrides anything on the ds. |
95 | public ClientPooledConnection(ClientBaseDataSource ds, |
96 | org.apache.derby.client.am.LogWriter logWriter, |
97 | String user, |
98 | String password, |
99 | int rmId) throws SQLException { |
100 | try { |
101 | logWriter_ = logWriter; |
102 | ds_ = ds; |
103 | user_ = user; |
104 | password_ = password; |
105 | rmId_ = rmId; |
106 | listeners_ = new java.util.Vector(); |
107 | netXAPhysicalConnection_ = getNetXAConnection(ds, |
108 | (NetLogWriter) logWriter_, |
109 | user, |
110 | password, |
111 | rmId); |
112 | physicalConnection_ = netXAPhysicalConnection_.getNetConnection(); |
113 | } catch ( SqlException se ) { |
114 | throw se.getSQLException(); |
115 | } |
116 | } |
117 | |
118 | public ClientPooledConnection(ClientBaseDataSource ds, |
119 | org.apache.derby.client.am.LogWriter logWriter) throws SQLException { |
120 | logWriter_ = logWriter; |
121 | ds_ = ds; |
122 | listeners_ = new java.util.Vector(); |
123 | try { |
124 | netPhysicalConnection_ = (org.apache.derby.client.net.NetConnection) |
125 | ClientDriver.getFactory().newNetConnection( |
126 | (NetLogWriter) logWriter_, |
127 | null, |
128 | null, |
129 | ds, |
130 | -1, |
131 | false); |
132 | |
133 | physicalConnection_ = netPhysicalConnection_; |
134 | } |
135 | catch (SqlException se) |
136 | { |
137 | throw se.getSQLException(); |
138 | } |
139 | } |
140 | |
141 | protected void finalize() throws java.lang.Throwable { |
142 | if (logWriter_ != null) { |
143 | logWriter_.traceEntry(this, "finalize"); |
144 | } |
145 | close(); |
146 | } |
147 | |
148 | public synchronized void close() throws SQLException { |
149 | try |
150 | { |
151 | if (logWriter_ != null) { |
152 | logWriter_.traceEntry(this, "close"); |
153 | } |
154 | |
155 | if (logicalConnection_ != null) { |
156 | logicalConnection_.nullPhysicalConnection(); |
157 | logicalConnection_ = null; |
158 | } |
159 | |
160 | if (physicalConnection_ == null) { |
161 | return; |
162 | } |
163 | |
164 | // Even if the physcial connection is marked closed (in the pool), |
165 | // this will close its underlying resources. |
166 | physicalConnection_.closeResources(); |
167 | } |
168 | finally |
169 | { |
170 | physicalConnection_ = null; |
171 | } |
172 | } |
173 | |
174 | // This is the standard API for getting a logical connection handle for a pooled connection. |
175 | // No "resettable" properties are passed, so user, password, and all other properties may not change. |
176 | public synchronized java.sql.Connection getConnection() throws SQLException { |
177 | try |
178 | { |
179 | if (logWriter_ != null) { |
180 | logWriter_.traceEntry(this, "getConnection"); |
181 | } |
182 | createLogicalConnection(); |
183 | |
184 | |
185 | if (!newPC_) { |
186 | // DERBY-1144 changed the last parameter of this method to true |
187 | // to reset the connection state to the default on |
188 | // PooledConnection.getConnection() otherwise the |
189 | // isolation level and holdability was not correct and out of sync with the server. |
190 | physicalConnection_.reset(logWriter_, user_, password_, ds_, true); |
191 | } |
192 | else { |
193 | physicalConnection_.lightReset(); //poolfix |
194 | } |
195 | newPC_ = false; |
196 | |
197 | if (logWriter_ != null) { |
198 | logWriter_.traceExit(this, "getConnection", logicalConnection_); |
199 | } |
200 | return logicalConnection_; |
201 | } |
202 | catch (SqlException se) |
203 | { |
204 | throw se.getSQLException(); |
205 | } |
206 | } |
207 | |
208 | private void createLogicalConnection() throws SqlException { |
209 | if (physicalConnection_ == null) { |
210 | throw new SqlException(logWriter_, |
211 | new ClientMessageId(SQLState.NOGETCONN_ON_CLOSED_POOLED_CONNECTION)); |
212 | } |
213 | |
214 | // Roll back any pending transactions. Otherwise we get an exception |
215 | // when we try to close the connection (even for re-use), with an error |
216 | // saying we can't close the connection with active transactions |
217 | // (this fixes DERBY-1004) |
218 | try { |
219 | if ( physicalConnection_.transactionInProgress() ) { |
220 | physicalConnection_.rollback(); |
221 | } |
222 | } catch ( SQLException sqle ) { |
223 | throw new SqlException(sqle); |
224 | } |
225 | |
226 | // Not the usual case, but if we have an existing logical connection, then we must close it by spec. |
227 | // We close the logical connection without notifying the pool manager that this pooled connection is availabe for reuse. |
228 | if (logicalConnection_ != null) { |
229 | logicalConnection_.closeWithoutRecyclingToPool(); |
230 | } |
231 | logicalConnection_ = ClientDriver.getFactory().newLogicalConnection( |
232 | physicalConnection_, |
233 | this); |
234 | } |
235 | |
236 | public synchronized void addConnectionEventListener(javax.sql.ConnectionEventListener listener) { |
237 | if (logWriter_ != null) { |
238 | logWriter_.traceEntry(this, "addConnectionEventListener", listener); |
239 | } |
240 | listeners_.addElement(listener); |
241 | } |
242 | |
243 | public synchronized void removeConnectionEventListener(javax.sql.ConnectionEventListener listener) { |
244 | if (logWriter_ != null) { |
245 | logWriter_.traceEntry(this, "removeConnectionEventListener", listener); |
246 | } |
247 | listeners_.removeElement(listener); |
248 | } |
249 | |
250 | // Not public, but needs to be visible to am.LogicalConnection |
251 | public void recycleConnection() { |
252 | if (physicalConnection_.agent_.loggingEnabled()) { |
253 | physicalConnection_.agent_.logWriter_.traceEntry(this, "recycleConnection"); |
254 | } |
255 | |
256 | for (java.util.Enumeration e = listeners_.elements(); e.hasMoreElements();) { |
257 | javax.sql.ConnectionEventListener listener = (javax.sql.ConnectionEventListener) e.nextElement(); |
258 | javax.sql.ConnectionEvent event = new javax.sql.ConnectionEvent(this); |
259 | listener.connectionClosed(event); |
260 | } |
261 | } |
262 | |
263 | // Not public, but needs to be visible to am.LogicalConnection |
264 | public void trashConnection(SqlException exception) { |
265 | for (java.util.Enumeration e = listeners_.elements(); e.hasMoreElements();) { |
266 | javax.sql.ConnectionEventListener listener = (javax.sql.ConnectionEventListener) e.nextElement(); |
267 | java.sql.SQLException sqle = exception.getSQLException(); |
268 | javax.sql.ConnectionEvent event = new javax.sql.ConnectionEvent(this, sqle); |
269 | listener.connectionErrorOccurred(event); |
270 | } |
271 | } |
272 | |
273 | // Used by LogicalConnection close when it disassociates itself from the ClientPooledConnection |
274 | public synchronized void nullLogicalConnection() { |
275 | logicalConnection_ = null; |
276 | } |
277 | |
278 | /*-----------------------------------------------------------------*/ |
279 | /* |
280 | * These methods are needed to provide StatementEvent support for |
281 | * derby. |
282 | * They are actually implemented in EmbedPooledConnection40 but have |
283 | * a dummy implementation here |
284 | */ |
285 | |
286 | /** |
287 | * |
288 | * The onStatementClose contains the logic for raising the Statement Closed |
289 | * events. This method has a dummy implementation here to avoid error when |
290 | * this class is compiled with jdk1.4. The class the actual implementation |
291 | * in ClientPooledConnection40. |
292 | * |
293 | * @param statement The PreparedStatement that was closed |
294 | * |
295 | */ |
296 | public void onStatementClose(PreparedStatement statement) { |
297 | |
298 | } |
299 | |
300 | /** |
301 | * The method contains the logic for raising the Statement error occurred |
302 | * events. This method has a dummy implementation here to avoid error when |
303 | * this class is compiled with jdk1.4. The class the actual implementation |
304 | * in ClientPooledConnection40. |
305 | * |
306 | * @param statement The PreparedStatement that was closed |
307 | * @param sqle The SQLException associated with the error that caused |
308 | * the invalidation of this PreparedStatement |
309 | */ |
310 | public void onStatementErrorOccurred(PreparedStatement statement, |
311 | SQLException sqle) { |
312 | |
313 | } |
314 | |
315 | /** |
316 | * creates and returns NetXAConnection. |
317 | * Overwrite this method to create different version of NetXAConnection |
318 | * @param ds |
319 | * @param logWriter |
320 | * @param user |
321 | * @param password |
322 | * @param rmId |
323 | * @return NetXAConnection |
324 | */ |
325 | protected NetXAConnection getNetXAConnection (ClientBaseDataSource ds, |
326 | NetLogWriter logWriter, |
327 | String user, |
328 | String password, |
329 | int rmId) throws SqlException { |
330 | return new NetXAConnection(logWriter, |
331 | user, |
332 | password, |
333 | ds, |
334 | rmId, |
335 | true, |
336 | this); |
337 | |
338 | } |
339 | } |