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