1 5 package org.h2.jdbcx; 6 7 import java.sql.Connection ; 9 import java.sql.ResultSet ; 10 import java.sql.SQLException ; 11 import java.sql.Statement ; 12 import java.util.ArrayList ; 13 import java.util.Properties ; 14 import javax.sql.ConnectionEvent ; 15 import javax.sql.ConnectionEventListener ; 16 import javax.sql.XAConnection ; 17 import javax.transaction.xa.XAException ; 18 import javax.transaction.xa.XAResource ; 19 import javax.transaction.xa.Xid ; 20 import org.h2.util.ByteUtils; 21 import org.h2.util.JdbcUtils; 22 import org.h2.jdbc.JdbcConnection; 23 25 import org.h2.message.TraceObject; 26 27 31 33 public class JdbcXAConnection extends TraceObject 34 implements XAConnection , XAResource , JdbcConnectionListener 36 { 38 39 private JdbcDataSourceFactory factory; 41 private String url, user, password; 42 private JdbcConnection conn; 43 private ArrayList listeners = new ArrayList (); 44 private Xid currentTransaction; 45 46 JdbcXAConnection(JdbcDataSourceFactory factory, int id, String url, String user, String password) { 47 this.factory = factory; 48 setTrace(factory.getTrace(), TraceObject.XA_DATASOURCE, id); 49 this.url = url; 50 this.user = user; 51 this.password = password; 52 } 53 54 public XAResource getXAResource() throws SQLException { 55 debugCodeCall("getXAResource"); 56 return this; 57 } 58 59 public void close() throws SQLException { 60 debugCodeCall("close"); 61 if(conn != null) { 62 conn.closeConnection(); 63 conn = null; 64 } 65 } 66 67 public Connection getConnection() throws SQLException { 68 debugCodeCall("getConnection"); 69 close(); 70 Properties info = new Properties (); 71 info.setProperty("user", user); 72 info.setProperty("password", password); 73 conn = new JdbcConnection(url, info); 74 return conn; 75 } 76 77 public void addConnectionEventListener(ConnectionEventListener listener) { 78 debugCode("addConnectionEventListener(listener)"); 79 listeners.add(listener); 80 conn.setJdbcConnectionListener(this); 81 } 82 83 public void removeConnectionEventListener(ConnectionEventListener listener) { 84 debugCode("removeConnectionEventListener(listener)"); 85 listeners.remove(listener); 86 } 87 88 public void fatalErrorOccured(JdbcConnection conn, SQLException e) throws SQLException { 89 debugCode("fatalErrorOccured(conn, e)"); 90 for(int i=0; i<listeners.size(); i++) { 91 ConnectionEventListener listener = (ConnectionEventListener )listeners.get(i); 92 ConnectionEvent event = new ConnectionEvent (this, e); 93 listener.connectionErrorOccurred(event); 94 } 95 close(); 96 } 97 98 public void closed(JdbcConnection conn) { 99 debugCode("closed(conn)"); 100 for(int i=0; i<listeners.size(); i++) { 101 ConnectionEventListener listener = (ConnectionEventListener )listeners.get(i); 102 ConnectionEvent event = new ConnectionEvent (this); 103 listener.connectionClosed(event); 104 } 105 } 106 107 public int getTransactionTimeout() throws XAException { 108 debugCodeCall("getTransactionTimeout"); 109 return 0; 110 } 111 112 public boolean setTransactionTimeout(int seconds) throws XAException { 113 debugCodeCall("setTransactionTimeout", seconds); 114 return false; 115 } 116 117 public boolean isSameRM(XAResource xares) throws XAException { 118 debugCode("isSameRM(xares)"); 119 return xares == this; 120 } 121 122 public Xid [] recover(int flag) throws XAException { 123 debugCodeCall("recover", quoteFlags(flag)); 124 checkOpen(); 125 Statement stat = null; 126 try { 127 stat = conn.createStatement(); 128 ResultSet rs = stat.executeQuery("SELECT * FROM INFORMATION_SCHEMA.IN_DOUBT ORDER BY ID"); 129 ArrayList list = new ArrayList (); 130 while(rs.next()) { 131 String tid = rs.getString("TRANSACTION"); 132 int id = getNextId(XID); 133 Xid xid = new JdbcXid(factory, id, tid); 134 list.add(xid); 135 } 136 rs.close(); 137 Xid [] result = new Xid [list.size()]; 138 list.toArray(result); 139 return result; 140 } catch(SQLException e) { 141 getTrace().debug("throw XAException.XAER_OUTSIDE", e); 142 throw new XAException (XAException.XAER_OUTSIDE); 143 } finally { 144 JdbcUtils.closeSilently(stat); 145 } 146 } 147 148 private void checkOpen() throws XAException { 149 if(conn == null) { 150 getTrace().debug("conn==null"); 151 throw new XAException (XAException.XAER_OUTSIDE); 152 } 153 } 154 155 public int prepare(Xid xid) throws XAException { 156 debugCode("prepare("+quoteXid(xid)+")"); 157 checkOpen(); 158 if(currentTransaction != xid) { 159 getTrace().debug("throw XAException.XAER_INVAL"); 160 throw new XAException (XAException.XAER_INVAL); 161 } 162 Statement stat = null; 163 try { 164 stat = conn.createStatement(); 165 stat.execute("PREPARE COMMIT"); 166 } catch(SQLException e) { 167 throw convertException(e); 168 } finally { 169 JdbcUtils.closeSilently(stat); 170 } 171 getTrace().debug("return TMSUCCESS"); 172 return TMSUCCESS; 173 } 174 175 public void forget(Xid xid) throws XAException { 176 debugCode("forget("+quoteXid(xid)+")"); 177 } 179 180 public void rollback(Xid xid) throws XAException { 181 debugCode("rollback("+quoteXid(xid)+")"); 182 try { 183 conn.rollback(); 184 } catch(SQLException e) { 185 throw convertException(e); 186 } 187 getTrace().debug("rolled back"); 188 } 189 190 public void end(Xid xid, int flags) throws XAException { 191 debugCode("end("+quoteXid(xid)+", "+quoteFlags(flags)+")"); 192 if(flags == TMSUSPEND) { 193 return; 194 } 195 if(currentTransaction != xid) { 196 getTrace().debug("throw XAException.XAER_OUTSIDE"); 197 throw new XAException (XAException.XAER_OUTSIDE); 198 } 199 getTrace().debug("currentTransaction=null"); 200 currentTransaction = null; 201 } 202 203 private String quoteFlags(int flags) { 204 StringBuffer buff = new StringBuffer (); 205 if((flags & XAResource.TMENDRSCAN) != 0) { 206 buff.append("|XAResource.TMENDRSCAN"); 207 } 208 if((flags & XAResource.TMFAIL) != 0) { 209 buff.append("|XAResource.TMFAIL"); 210 } 211 if((flags & XAResource.TMJOIN) != 0) { 212 buff.append("|XAResource.TMJOIN"); 213 } 214 if((flags & XAResource.TMONEPHASE) != 0) { 215 buff.append("|XAResource.TMONEPHASE"); 216 } 217 if((flags & XAResource.TMRESUME) != 0) { 218 buff.append("|XAResource.TMRESUME"); 219 } 220 if((flags & XAResource.TMSTARTRSCAN) != 0) { 221 buff.append("|XAResource.TMSTARTRSCAN"); 222 } 223 if((flags & XAResource.TMSUCCESS) != 0) { 224 buff.append("|XAResource.TMSUCCESS"); 225 } 226 if((flags & XAResource.TMSUSPEND) != 0) { 227 buff.append("|XAResource.TMSUSPEND"); 228 } 229 if(buff.length() == 0) { 230 buff.append("|XAResource.TMNOFLAGS"); 231 } 232 return buff.toString().substring(1); 233 } 234 235 private String quoteXid(Xid xid) { 236 StringBuffer buff = new StringBuffer (); 237 buff.append("\"f:"); 238 buff.append(xid.getFormatId()); 239 buff.append(",bq:"); 240 buff.append(ByteUtils.convertBytesToString(xid.getBranchQualifier())); 241 buff.append(",gxid:"); 242 buff.append(ByteUtils.convertBytesToString(xid.getGlobalTransactionId())); 243 buff.append(",c:"); 244 buff.append(xid.getClass().getName()); 245 buff.append("\""); 246 return buff.toString(); 247 } 248 249 public void start(Xid xid, int flags) throws XAException { 250 debugCode("start("+quoteXid(xid)+", "+quoteFlags(flags)+")"); 251 if(flags == TMRESUME) { 252 return; 253 } 254 if(currentTransaction != null) { 255 getTrace().debug("throw XAException.XAER_NOTA"); 256 throw new XAException (XAException.XAER_NOTA); 257 } 258 try { 259 conn.setAutoCommit(false); 260 } catch(SQLException e) { 261 throw convertException(e); 262 } 263 getTrace().debug("currentTransaction=xid"); 264 currentTransaction = xid; 265 } 266 267 private XAException convertException(SQLException e) { 268 getTrace().debug("throw XAException("+e.getMessage()+")"); 269 return new XAException (e.getMessage()); 270 } 271 272 public void commit(Xid xid, boolean onePhase) throws XAException { 273 debugCode("commit("+quoteXid(xid)+", "+onePhase+")"); 274 try { 275 conn.commit(); 276 } catch(SQLException e) { 277 throw convertException(e); 278 } 279 getTrace().debug("committed"); 280 } 281 283 289 291 297 299 } 300 | Popular Tags |