1 | /* |
2 | |
3 | Derby - Class org.apache.derby.impl.tools.ij.xaHelper |
4 | |
5 | Copyright 1999, 2004 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.impl.tools.ij; |
22 | |
23 | import org.apache.derby.iapi.tools.i18n.LocalizedResource; |
24 | import java.sql.Connection; |
25 | import java.sql.SQLException; |
26 | import java.util.Locale; |
27 | import java.util.Vector; |
28 | |
29 | import javax.transaction.xa.Xid; |
30 | import javax.transaction.xa.XAResource; |
31 | import javax.transaction.xa.XAException; |
32 | import javax.sql.PooledConnection; |
33 | import javax.sql.XAConnection; |
34 | import javax.sql.XADataSource; |
35 | import javax.sql.DataSource; |
36 | import javax.sql.ConnectionPoolDataSource; |
37 | import org.apache.derby.iapi.services.info.JVMInfo; |
38 | |
39 | /* |
40 | * The real xa helper class. Load this class only if we know the javax classes |
41 | * are in the class path. |
42 | */ |
43 | class xaHelper implements xaAbstractHelper |
44 | { |
45 | |
46 | private XADataSource currentXADataSource; |
47 | private XAConnection currentXAConnection; |
48 | |
49 | private String databaseName; |
50 | |
51 | // non xa stuff |
52 | private DataSource currentDataSource; |
53 | private ConnectionPoolDataSource currentCPDataSource; |
54 | private PooledConnection currentPooledConnection; |
55 | |
56 | private boolean isJCC; |
57 | private boolean isNetClient; |
58 | private String framework; |
59 | |
60 | xaHelper() |
61 | { |
62 | } |
63 | |
64 | |
65 | public void setFramework(String fm) |
66 | { |
67 | framework = fm.toUpperCase(Locale.ENGLISH); |
68 | if (framework.endsWith("NET") || |
69 | framework.equals("DB2JCC")) |
70 | isJCC = true; |
71 | else if (framework.equals("DERBYNETCLIENT")) |
72 | isNetClient = true; |
73 | |
74 | } |
75 | |
76 | private Xid makeXid(int xid) |
77 | { |
78 | return new ijXid(xid, databaseName.getBytes()); |
79 | } |
80 | |
81 | public void XADataSourceStatement(ij parser, Token dbname, Token shutdown, |
82 | String create) |
83 | throws SQLException |
84 | { |
85 | try |
86 | { |
87 | currentXADataSource = (XADataSource) getXADataSource(); |
88 | |
89 | databaseName = parser.stringValue(dbname.image); |
90 | |
91 | if (isJCC || isNetClient) |
92 | { |
93 | String hostName = System.getProperty("hostName"); |
94 | if ((hostName != null ) && (!hostName.equals("localhost"))) |
95 | { |
96 | xaHelper.setDataSourceProperty(currentXADataSource, |
97 | "ServerName", hostName); |
98 | } |
99 | else |
100 | { |
101 | xaHelper.setDataSourceProperty(currentXADataSource, |
102 | "ServerName", "localhost"); |
103 | } |
104 | xaHelper.setDataSourceProperty(currentXADataSource, |
105 | "portNumber", 1527); |
106 | |
107 | String user; |
108 | String password; |
109 | user = "APP"; |
110 | password = "APP"; |
111 | xaHelper.setDataSourceProperty(currentXADataSource, |
112 | "user", user); |
113 | xaHelper.setDataSourceProperty(currentXADataSource, |
114 | "password", password); |
115 | //xaHelper.setDataSourceProperty(currentXADataSource, |
116 | //"traceFile", "trace.out." + framework); |
117 | } |
118 | if (isJCC) |
119 | { |
120 | xaHelper.setDataSourceProperty(currentXADataSource, |
121 | "driverType", 4); |
122 | |
123 | xaHelper.setDataSourceProperty(currentXADataSource, |
124 | "retrieveMessagesFromServerOnGetMessage", true); |
125 | } |
126 | xaHelper.setDataSourceProperty(currentXADataSource, "databaseName", databaseName); |
127 | |
128 | if (shutdown != null && shutdown.toString().toLowerCase(Locale.ENGLISH).equals("shutdown")) |
129 | { |
130 | if (isJCC || isNetClient) |
131 | xaHelper.setDataSourceProperty(currentXADataSource,"databaseName", databaseName + ";shutdown=true"); |
132 | else |
133 | xaHelper.setDataSourceProperty(currentXADataSource, "shutdownDatabase", "shutdown"); |
134 | |
135 | // do a getXAConnection to shut it down */ |
136 | currentXADataSource.getXAConnection().getConnection(); |
137 | currentXADataSource = null; |
138 | currentXAConnection = null; |
139 | } |
140 | else if (create != null && create.toLowerCase(java.util.Locale.ENGLISH).equals("create")) |
141 | { |
142 | if (isJCC || isNetClient) |
143 | xaHelper.setDataSourceProperty(currentXADataSource,"databaseName", databaseName + ";create=true"); |
144 | else |
145 | xaHelper.setDataSourceProperty(currentXADataSource, |
146 | "createDatabase", "create"); |
147 | |
148 | /* do a getXAConnection to create it */ |
149 | XAConnection conn = currentXADataSource.getXAConnection(); |
150 | conn.close(); |
151 | |
152 | xaHelper.setDataSourceProperty(currentXADataSource, "createDatabase", null); |
153 | } |
154 | } |
155 | catch (Throwable t) |
156 | { |
157 | handleException(t); |
158 | } |
159 | } |
160 | |
161 | |
162 | public void XAConnectStatement(ij parser, Token user, Token pass, String id) |
163 | throws SQLException |
164 | { |
165 | try |
166 | { |
167 | if (currentXAConnection != null) |
168 | { |
169 | try { |
170 | currentXAConnection.close(); |
171 | } catch (SQLException sqle) { |
172 | } |
173 | |
174 | currentXAConnection = null; |
175 | } |
176 | |
177 | String username = null; |
178 | String password = ""; |
179 | |
180 | if (pass != null) |
181 | password = parser.stringValue(pass.image); |
182 | |
183 | if (user != null) |
184 | { |
185 | username = parser.stringValue(user.image); |
186 | |
187 | currentXAConnection = |
188 | currentXADataSource.getXAConnection(username, password); |
189 | } |
190 | else |
191 | { |
192 | |
193 | currentXAConnection = currentXADataSource.getXAConnection(); |
194 | } |
195 | |
196 | } |
197 | catch (Throwable t) |
198 | { |
199 | handleException(t); |
200 | } |
201 | } |
202 | |
203 | public void XADisconnectStatement(ij parser, String n) throws SQLException |
204 | { |
205 | if (currentXAConnection == null) |
206 | throw ijException.noSuchConnection("XAConnection"); |
207 | currentXAConnection.close(); |
208 | currentXAConnection = null; |
209 | } |
210 | |
211 | public Connection XAGetConnectionStatement(ij parser, String n) throws SQLException |
212 | { |
213 | try |
214 | { |
215 | return currentXAConnection.getConnection(); |
216 | } |
217 | catch(Throwable t) |
218 | { |
219 | handleException(t); |
220 | } |
221 | return null; |
222 | } |
223 | |
224 | public void CommitStatement(ij parser, Token onePhase, Token twoPhase, |
225 | int xid) |
226 | throws SQLException |
227 | { |
228 | try |
229 | { |
230 | currentXAConnection.getXAResource().commit(makeXid(xid), (onePhase != null)); |
231 | } |
232 | catch(Throwable t) |
233 | { |
234 | handleException(t); |
235 | } |
236 | } |
237 | |
238 | public void EndStatement(ij parser, int flag, int xid) throws SQLException |
239 | { |
240 | try |
241 | { |
242 | currentXAConnection.getXAResource().end(makeXid(xid), flag); |
243 | } |
244 | catch(Throwable t) |
245 | { |
246 | handleException(t); |
247 | } |
248 | } |
249 | |
250 | public void ForgetStatement(ij parser, int xid) throws SQLException |
251 | { |
252 | try |
253 | { |
254 | currentXAConnection.getXAResource().forget(makeXid(xid)); |
255 | } |
256 | catch(Throwable t) |
257 | { |
258 | handleException(t); |
259 | } |
260 | } |
261 | |
262 | public void PrepareStatement(ij parser, int xid) throws SQLException |
263 | { |
264 | try |
265 | { |
266 | currentXAConnection.getXAResource().prepare(makeXid(xid)); |
267 | } |
268 | catch(Throwable t) |
269 | { |
270 | handleException(t); |
271 | } |
272 | } |
273 | |
274 | public ijResult RecoverStatement(ij parser, int flag) throws SQLException |
275 | { |
276 | Object[] val = null; |
277 | |
278 | try |
279 | { |
280 | val = currentXAConnection.getXAResource().recover(flag); |
281 | } |
282 | catch(Throwable t) |
283 | { |
284 | handleException(t); |
285 | } |
286 | |
287 | Vector v = new Vector(); |
288 | v.addElement(""); |
289 | v.addElement(LocalizedResource.getMessage("IJ_Reco0InDoubT", LocalizedResource.getNumber(val.length))); |
290 | v.addElement(""); |
291 | for (int i = 0; i < val.length; i++) |
292 | v.addElement(LocalizedResource.getMessage("IJ_Tran01", LocalizedResource.getNumber(i+1), val[i].toString())); |
293 | |
294 | return new ijVectorResult(v,null); |
295 | |
296 | } |
297 | |
298 | public void RollbackStatement(ij parser, int xid) throws SQLException |
299 | { |
300 | try |
301 | { |
302 | currentXAConnection.getXAResource().rollback(makeXid(xid)); |
303 | } |
304 | catch(Throwable t) |
305 | { |
306 | handleException(t); |
307 | } |
308 | |
309 | } |
310 | |
311 | public void StartStatement(ij parser, int flag, int xid) throws SQLException |
312 | { |
313 | try |
314 | { |
315 | currentXAConnection.getXAResource().start(makeXid(xid), flag); |
316 | } |
317 | catch(Throwable t) |
318 | { |
319 | handleException(t); |
320 | } |
321 | } |
322 | |
323 | private void handleException(Throwable t) throws SQLException |
324 | { |
325 | if (t instanceof SQLException) |
326 | { |
327 | // let ij handle it |
328 | throw (SQLException)t; |
329 | } |
330 | if (t instanceof XAException) |
331 | { |
332 | int errorCode = ((XAException)t).errorCode; |
333 | String error = LocalizedResource.getMessage("IJ_IlleValu"); |
334 | |
335 | // XA_RBBASE 100 |
336 | // XA_RBROLLBACK 100 |
337 | // XA_RBCOMMFAIL 101 |
338 | // XA_RBDEADLOCK 102 |
339 | // XA_RBINTEGRITY 103 |
340 | // XA_RBOTHER 104 |
341 | // XA_RBPROTO 105 |
342 | // XA_RBTIMEOUT 106 |
343 | // XA_RBTRANSIENT 107 |
344 | // XA_RBEND 107 |
345 | // |
346 | // XA_RDONLY 3 |
347 | // XA_RETRY 4 |
348 | // XA_HEURMIX 5 |
349 | // XA_HEURRB 6 |
350 | // XA_HEURCOM 7 |
351 | // XA_HEURHAZ 8 |
352 | // XA_NOMIGRATE 9 |
353 | // |
354 | // XAER_ASYNC -2 |
355 | // XAER_RMERR -3 |
356 | // XAER_NOTA -4 |
357 | // XAER_INVAL -5 |
358 | // XAER_PROTO -6 |
359 | // XAER_RMFAIL -7 |
360 | // XAER_DUPID -8 |
361 | // XAER_OUTSIDE -9 |
362 | |
363 | switch(errorCode) |
364 | { |
365 | case XAException.XA_HEURCOM : error = "XA_HEURCOM "; break; |
366 | case XAException.XA_HEURHAZ : error = "XA_HEURHAZ"; break; |
367 | case XAException.XA_HEURMIX : error = "XA_HEURMIX"; break; |
368 | case XAException.XA_HEURRB : error = "XA_HEURRB "; break; |
369 | case XAException.XA_NOMIGRATE : error = "XA_NOMIGRATE "; break; |
370 | // case XAException.XA_RBBASE : error = "XA_RBBASE "; break; |
371 | case XAException.XA_RBCOMMFAIL : error = "XA_RBCOMMFAIL "; break; |
372 | case XAException.XA_RBDEADLOCK : error = "XA_RBDEADLOCK "; break; |
373 | // case XAException.XA_RBEND : error = "XA_RBEND "; break; |
374 | case XAException.XA_RBINTEGRITY : error = "XA_RBINTEGRITY "; break; |
375 | case XAException.XA_RBOTHER : error = "XA_RBOTHER "; break; |
376 | case XAException.XA_RBPROTO : error = "XA_RBPROTO "; break; |
377 | case XAException.XA_RBROLLBACK : error = "XA_RBROLLBACK "; break; |
378 | case XAException.XA_RBTIMEOUT : error = "XA_RBTIMEOUT "; break; |
379 | case XAException.XA_RBTRANSIENT : error = "XA_RBTRANSIENT "; break; |
380 | case XAException.XA_RDONLY : error = "XA_RDONLY "; break; |
381 | case XAException.XA_RETRY : error = "XA_RETRY "; break; |
382 | case XAException.XAER_ASYNC : error = "XAER_ASYNC "; break; |
383 | case XAException.XAER_DUPID : error = "XAER_DUPID "; break; |
384 | case XAException.XAER_INVAL : error = "XAER_INVAL "; break; |
385 | case XAException.XAER_NOTA : error = "XAER_NOTA "; break; |
386 | case XAException.XAER_OUTSIDE : error = "XAER_OUTSIDE "; break; |
387 | case XAException.XAER_PROTO : error = "XAER_PROTO "; break; |
388 | case XAException.XAER_RMERR : error = "XAER_RMERR "; break; |
389 | case XAException.XAER_RMFAIL : error = "XAER_RMFAIL "; break; |
390 | } |
391 | //t.printStackTrace(System.out); |
392 | throw new ijException(error); |
393 | |
394 | } |
395 | else // StandardException or run time exception, log it first |
396 | { |
397 | String info = LocalizedResource.getMessage("IJ_01SeeLog", t.toString(), t.getMessage()); |
398 | // t.printStackTrace(System.out); |
399 | throw new ijException(info); |
400 | } |
401 | } |
402 | |
403 | |
404 | // non-xa stuff. DataSource and ConnectionPoolDataSource |
405 | public Connection DataSourceStatement(ij parser, Token dbname, Token protocol, |
406 | Token userT, Token passT, String id) |
407 | throws SQLException |
408 | { |
409 | |
410 | try { |
411 | currentDataSource = (DataSource) (Class.forName("org.apache.derby.jdbc.EmbeddedDataSource").newInstance()); |
412 | } catch (Exception e) { |
413 | throw new SQLException(e.toString()); |
414 | } |
415 | databaseName = parser.stringValue(dbname.image); |
416 | xaHelper.setDataSourceProperty(currentDataSource, "databaseName", databaseName); |
417 | xaHelper.setDataSourceProperty(currentXADataSource, "dataSourceName", databaseName); |
418 | // make a connection |
419 | Connection c = null; |
420 | String username = null; |
421 | String password = ""; |
422 | |
423 | if (passT != null) |
424 | password = parser.stringValue(passT.image); |
425 | |
426 | if (userT != null) |
427 | { |
428 | username = parser.stringValue(userT.image); |
429 | c = currentDataSource.getConnection(username, password); |
430 | } |
431 | else |
432 | { |
433 | c = currentDataSource.getConnection(); |
434 | } |
435 | |
436 | return c; |
437 | |
438 | } |
439 | |
440 | public void CPDataSourceStatement(ij parser, Token dbname, Token protocol) |
441 | throws SQLException |
442 | { |
443 | try { |
444 | currentCPDataSource = (ConnectionPoolDataSource) (Class.forName("org.apache.derby.jdbc.EmbeddedConnectionPoolDataSource").newInstance()); |
445 | } catch (Exception e) { |
446 | throw new SQLException(e.toString()); |
447 | } |
448 | databaseName = parser.stringValue(dbname.image); |
449 | xaHelper.setDataSourceProperty(currentCPDataSource, "databaseName", databaseName); |
450 | } |
451 | |
452 | public void CPConnectStatement(ij parser, Token userT, Token passT, String n) |
453 | throws SQLException |
454 | { |
455 | String username = null; |
456 | String password = ""; |
457 | |
458 | if (passT != null) |
459 | password = parser.stringValue(passT.image); |
460 | |
461 | if (userT != null) |
462 | { |
463 | username = parser.stringValue(userT.image); |
464 | currentPooledConnection = |
465 | currentCPDataSource.getPooledConnection(username, password); |
466 | } |
467 | else |
468 | { |
469 | currentPooledConnection = |
470 | currentCPDataSource.getPooledConnection(); |
471 | } |
472 | } |
473 | |
474 | public Connection CPGetConnectionStatement(ij parser, String n) |
475 | throws SQLException |
476 | { |
477 | return currentPooledConnection.getConnection(); |
478 | } |
479 | |
480 | public void CPDisconnectStatement(ij parser, String n) throws SQLException |
481 | { |
482 | if (currentPooledConnection == null) |
483 | throw ijException.noSuchConnection(LocalizedResource.getMessage("IJ_Pool")); |
484 | currentPooledConnection.close(); |
485 | currentPooledConnection = null; |
486 | } |
487 | |
488 | /** |
489 | * Get a DataSource that supports distributed transactions. |
490 | * |
491 | * @return XADataSource object |
492 | * |
493 | * @exception Exception if XaDataSource is not in class path. |
494 | */ |
495 | private XADataSource getXADataSource() throws Exception |
496 | { |
497 | // We need to construct this object in this round about fashion because |
498 | // if we new it directly, then it will the tools.jar file to bloat. |
499 | try |
500 | { |
501 | if (isJCC) |
502 | return (XADataSource) |
503 | (Class.forName("com.ibm.db2.jcc.DB2XADataSource").newInstance()); |
504 | else if (isNetClient){ |
505 | if (JVMInfo.JDK_ID >= JVMInfo.J2SE_16) { |
506 | //running under jdk1.6 or higher |
507 | // try instantiating EmbeddedXADataSource40 |
508 | try { |
509 | return (XADataSource)(Class.forName( |
510 | "org.apache.derby.jdbc." + |
511 | "ClientXADataSource40").newInstance()); |
512 | } |
513 | catch (ClassNotFoundException e) { |
514 | //probably it was not compiled with jdbc4.0 |
515 | //support go ahead with EmbeddedXADataSource |
516 | } |
517 | } |
518 | return (XADataSource) (Class.forName( |
519 | "org.apache.derby.jdbc.ClientXADataSource" |
520 | ).newInstance()); |
521 | } |
522 | else { |
523 | if (JVMInfo.JDK_ID >= JVMInfo.J2SE_16) { |
524 | //running under jdk1.6 or higher |
525 | // try instantiating EmbeddedXADataSource40 |
526 | try { |
527 | return (XADataSource)(Class.forName( |
528 | "org.apache.derby.jdbc." + |
529 | "EmbeddedXADataSource40").newInstance()); |
530 | } |
531 | catch (ClassNotFoundException e) { |
532 | //probably it was not compiled with jdbc4.0 |
533 | //support go ahead with EmbeddedXADataSource |
534 | } |
535 | } |
536 | return (XADataSource)(Class.forName("org.apache.derby.jdbc.EmbeddedXADataSource").newInstance()); |
537 | } |
538 | } |
539 | catch(ClassNotFoundException cnfe) { |
540 | throw new ijException(LocalizedResource.getMessage("IJ_XAClass")); |
541 | } |
542 | catch (InstantiationException e) { } |
543 | catch (IllegalAccessException e) { } |
544 | |
545 | throw new ijException(LocalizedResource.getMessage("IJ_XANoI")); |
546 | } |
547 | private static final Class[] STRING_P = { "".getClass() }; |
548 | private static final Class[] INT_P = { Integer.TYPE }; |
549 | private static final Class[] BOOLEAN_P = {Boolean.TYPE }; |
550 | |
551 | private static void setDataSourceProperty(Object ds, String property, int |
552 | value) throws SQLException |
553 | { |
554 | String methodName = |
555 | "set" + Character.toUpperCase(property.charAt(0)) + property.substring(1); |
556 | try { |
557 | java.lang.reflect.Method m = ds.getClass().getMethod(methodName, INT_P); |
558 | m.invoke(ds, new Object[] {new Integer(value)}); |
559 | } |
560 | catch (Exception e) |
561 | { |
562 | throw new SQLException(property + " ???" + e.getMessage()); |
563 | } |
564 | |
565 | } |
566 | |
567 | private static void setDataSourceProperty(Object ds, String property, String value) throws SQLException { |
568 | |
569 | String methodName = |
570 | "set" + Character.toUpperCase(property.charAt(0)) + property.substring(1); |
571 | |
572 | try { |
573 | java.lang.reflect.Method m = ds.getClass().getMethod(methodName, STRING_P); |
574 | m.invoke(ds, new Object[] {value}); |
575 | return; |
576 | } catch (/*NoSuchMethod*/Exception nsme) { |
577 | throw new SQLException(property + " ???"); |
578 | //java.lang.reflect.Method m = ds.getClass().getMethod("set" + property, INT_P); |
579 | //m.invoke(ds, new Object[] {Integer.valueOf(value)}); |
580 | } |
581 | } |
582 | |
583 | private static void setDataSourceProperty(Object ds, String property, boolean value) throws SQLException { |
584 | |
585 | String methodName = |
586 | "set" + Character.toUpperCase(property.charAt(0)) + property.substring(1); |
587 | |
588 | try { |
589 | java.lang.reflect.Method m = ds.getClass().getMethod(methodName, BOOLEAN_P); |
590 | m.invoke(ds, new Object[] {new Boolean(value)}); |
591 | return; |
592 | } catch (Exception nsme) { |
593 | throw new SQLException(property + " ???"); |
594 | } |
595 | } |
596 | } |
597 | |
598 | |
599 | |
600 | class ijXid implements Xid, java.io.Serializable |
601 | { |
602 | private static final long serialVersionUID = 64467452100036L; |
603 | |
604 | private final int format_id; |
605 | private final byte[] global_id; |
606 | private final byte[] branch_id; |
607 | |
608 | |
609 | ijXid(int xid, byte[] id) |
610 | { |
611 | format_id = xid; |
612 | global_id = id; |
613 | branch_id = id; |
614 | |
615 | } |
616 | /** |
617 | * Obtain the format id part of the Xid. |
618 | * <p> |
619 | * |
620 | * @return Format identifier. O means the OSI CCR format. |
621 | **/ |
622 | public int getFormatId() |
623 | { |
624 | return(format_id); |
625 | } |
626 | |
627 | /** |
628 | * Obtain the global transaction identifier part of XID as an array of |
629 | * bytes. |
630 | * <p> |
631 | * |
632 | * @return A byte array containing the global transaction identifier. |
633 | **/ |
634 | public byte[] getGlobalTransactionId() |
635 | { |
636 | return(global_id); |
637 | } |
638 | |
639 | /** |
640 | * Obtain the transaction branch qualifier part of the Xid in a byte array. |
641 | * <p> |
642 | * |
643 | * @return A byte array containing the branch qualifier of the transaction. |
644 | **/ |
645 | public byte[] getBranchQualifier() |
646 | { |
647 | return(branch_id); |
648 | } |
649 | } |
650 | |
651 | |