1 | /* |
2 | |
3 | Derby - Class org.apache.derby.jdbc.EmbedXAConnection |
4 | |
5 | Copyright 2003, 2005 The Apache Software Foundation or its licensors, as 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 | |
21 | package org.apache.derby.jdbc; |
22 | |
23 | import org.apache.derby.impl.jdbc.Util; |
24 | import org.apache.derby.iapi.jdbc.EngineConnection; |
25 | import org.apache.derby.iapi.jdbc.ResourceAdapter; |
26 | |
27 | import org.apache.derby.iapi.reference.SQLState; |
28 | import org.apache.derby.iapi.reference.JDBC30Translation; |
29 | |
30 | import java.sql.Connection; |
31 | import java.sql.SQLException; |
32 | import java.sql.Statement; |
33 | import java.sql.PreparedStatement; |
34 | import java.sql.CallableStatement; |
35 | import javax.transaction.xa.XAResource; |
36 | |
37 | /** -- jdbc 2.0. extension -- */ |
38 | import javax.sql.XAConnection; |
39 | |
40 | /** |
41 | */ |
42 | class EmbedXAConnection extends EmbedPooledConnection |
43 | implements XAConnection |
44 | |
45 | { |
46 | |
47 | private EmbedXAResource xaRes; |
48 | |
49 | EmbedXAConnection(EmbeddedDataSource ds, ResourceAdapter ra, String u, String p, boolean requestPassword) throws SQLException |
50 | { |
51 | super(ds, u, p, requestPassword); |
52 | xaRes = new EmbedXAResource (this, ra); |
53 | } |
54 | |
55 | /* |
56 | ** XAConnection methods |
57 | */ |
58 | |
59 | public final synchronized XAResource getXAResource() throws SQLException { |
60 | checkActive(); |
61 | return xaRes; |
62 | } |
63 | |
64 | /* |
65 | ** BrokeredConnectionControl api |
66 | */ |
67 | /** |
68 | Allow control over setting auto commit mode. |
69 | */ |
70 | public void checkAutoCommit(boolean autoCommit) throws SQLException { |
71 | if (autoCommit && (xaRes.getCurrentXid () != null)) |
72 | throw Util.generateCsSQLException(SQLState.CANNOT_AUTOCOMMIT_XA); |
73 | |
74 | super.checkAutoCommit(autoCommit); |
75 | } |
76 | /** |
77 | Are held cursors allowed. If the connection is attached to |
78 | a global transaction then downgrade the result set holdabilty |
79 | to CLOSE_CURSORS_AT_COMMIT if downgrade is true, otherwise |
80 | throw an exception. |
81 | If the connection is in a local transaction then the |
82 | passed in holdabilty is returned. |
83 | */ |
84 | public int checkHoldCursors(int holdability, boolean downgrade) |
85 | throws SQLException |
86 | { |
87 | if (holdability == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) { |
88 | if (xaRes.getCurrentXid () != null) { |
89 | if (!downgrade) |
90 | throw Util.generateCsSQLException(SQLState.CANNOT_HOLD_CURSOR_XA); |
91 | |
92 | holdability = JDBC30Translation.CLOSE_CURSORS_AT_COMMIT; |
93 | } |
94 | } |
95 | |
96 | return super.checkHoldCursors(holdability, downgrade); |
97 | } |
98 | |
99 | /** |
100 | Allow control over creating a Savepoint (JDBC 3.0) |
101 | */ |
102 | public void checkSavepoint() throws SQLException { |
103 | |
104 | if (xaRes.getCurrentXid () != null) |
105 | throw Util.generateCsSQLException(SQLState.CANNOT_ROLLBACK_XA); |
106 | |
107 | super.checkSavepoint(); |
108 | } |
109 | |
110 | /** |
111 | Allow control over calling rollback. |
112 | */ |
113 | public void checkRollback() throws SQLException { |
114 | |
115 | if (xaRes.getCurrentXid () != null) |
116 | throw Util.generateCsSQLException(SQLState.CANNOT_ROLLBACK_XA); |
117 | |
118 | super.checkRollback(); |
119 | } |
120 | /** |
121 | Allow control over calling commit. |
122 | */ |
123 | public void checkCommit() throws SQLException { |
124 | |
125 | if (xaRes.getCurrentXid () != null) |
126 | throw Util.generateCsSQLException(SQLState.CANNOT_COMMIT_XA); |
127 | |
128 | super.checkCommit(); |
129 | } |
130 | |
131 | public Connection getConnection() throws SQLException |
132 | { |
133 | Connection handle; |
134 | |
135 | // Is this just a local transaction? |
136 | if (xaRes.getCurrentXid () == null) { |
137 | handle = super.getConnection(); |
138 | } else { |
139 | |
140 | if (currentConnectionHandle != null) { |
141 | // this can only happen if someone called start(Xid), |
142 | // getConnection, getConnection (and we are now the 2nd |
143 | // getConnection call). |
144 | // Cannot yank a global connection away like, I don't think... |
145 | throw Util.generateCsSQLException( |
146 | SQLState.CANNOT_CLOSE_ACTIVE_XA_CONNECTION); |
147 | } |
148 | |
149 | handle = getNewCurrentConnectionHandle(); |
150 | } |
151 | |
152 | currentConnectionHandle.syncState(); |
153 | |
154 | return handle; |
155 | } |
156 | |
157 | /** |
158 | Wrap and control a Statement |
159 | */ |
160 | public Statement wrapStatement(Statement s) throws SQLException { |
161 | XAStatementControl sc = new XAStatementControl(this, s); |
162 | return sc.applicationStatement; |
163 | } |
164 | /** |
165 | Wrap and control a PreparedStatement |
166 | */ |
167 | public PreparedStatement wrapStatement(PreparedStatement ps, String sql, Object generatedKeys) throws SQLException { |
168 | ps = super.wrapStatement(ps,sql,generatedKeys); |
169 | XAStatementControl sc = new XAStatementControl(this, ps, sql, generatedKeys); |
170 | return (PreparedStatement) sc.applicationStatement; |
171 | } |
172 | /** |
173 | Wrap and control a PreparedStatement |
174 | */ |
175 | public CallableStatement wrapStatement(CallableStatement cs, String sql) throws SQLException { |
176 | cs = super.wrapStatement(cs,sql); |
177 | XAStatementControl sc = new XAStatementControl(this, cs, sql); |
178 | return (CallableStatement) sc.applicationStatement; |
179 | } |
180 | |
181 | /** |
182 | Override getRealConnection to create a a local connection |
183 | when we are not associated with an XA transaction. |
184 | |
185 | This can occur if the application has a Connection object (conn) |
186 | and the following sequence occurs. |
187 | |
188 | conn = xac.getConnection(); |
189 | xac.start(xid, ...) |
190 | |
191 | // do work with conn |
192 | |
193 | xac.end(xid, ...); |
194 | |
195 | // do local work with conn |
196 | // need to create new connection here. |
197 | */ |
198 | public EngineConnection getRealConnection() throws SQLException |
199 | { |
200 | EngineConnection rc = super.getRealConnection(); |
201 | if (rc != null) |
202 | return rc; |
203 | |
204 | openRealConnection(); |
205 | |
206 | // a new Connection, set its state according to the application's Connection handle |
207 | currentConnectionHandle.setState(true); |
208 | |
209 | return realConnection; |
210 | } |
211 | } |