001: /*
002: * Copyright 2004-2005 OpenSymphony
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy
006: * of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations
014: * under the License.
015: *
016: */
017:
018: /*
019: * Previously Copyright (c) 2001-2004 James House
020: */
021: package org.quartz.ee.jta;
022:
023: import javax.naming.InitialContext;
024: import javax.transaction.HeuristicMixedException;
025: import javax.transaction.HeuristicRollbackException;
026: import javax.transaction.NotSupportedException;
027: import javax.transaction.RollbackException;
028: import javax.transaction.SystemException;
029: import javax.transaction.UserTransaction;
030:
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033: import org.quartz.SchedulerException;
034:
035: /**
036: * <p>
037: * A helper for obtaining a handle to a UserTransaction...
038: * </p>
039: * <p>
040: * To ensure proper cleanup of the InitalContext used to create/lookup
041: * the UserTransaction, be sure to always call returnUserTransaction() when
042: * you are done with the UserTransaction.
043: * </p>
044: *
045: * @author James House
046: */
047: public class UserTransactionHelper {
048:
049: /*
050: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
051: *
052: * Constants.
053: *
054: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
055: */
056:
057: public static final String DEFAULT_USER_TX_LOCATION = "java:comp/UserTransaction";
058:
059: /*
060: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
061: *
062: * Data members.
063: *
064: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
065: */
066:
067: private static String userTxURL = DEFAULT_USER_TX_LOCATION;
068:
069: /*
070: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
071: *
072: * Constructors.
073: *
074: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
075: */
076:
077: /**
078: * Do not allow the creation of an all static utility class.
079: */
080: private UserTransactionHelper() {
081: }
082:
083: /*
084: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
085: *
086: * Interface.
087: *
088: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
089: */
090:
091: public static String getUserTxLocation() {
092: return userTxURL;
093: }
094:
095: /**
096: * Set the JNDI URL at which the Application Server's UserTransaction can
097: * be found. If not set, the default value is "java:comp/UserTransaction" -
098: * which works for nearly all application servers.
099: */
100: public static void setUserTxLocation(String userTxURL) {
101: if (userTxURL != null) {
102: UserTransactionHelper.userTxURL = userTxURL;
103: }
104: }
105:
106: /**
107: * Create/Lookup a UserTransaction in the InitialContext via the
108: * name set in setUserTxLocation().
109: */
110: public static UserTransaction lookupUserTransaction()
111: throws SchedulerException {
112: return new UserTransactionWithContext();
113: }
114:
115: /**
116: * Return a UserTransaction that was retrieved via getUserTransaction().
117: * This will make sure that the InitalContext used to lookup/create the
118: * UserTransaction is properly cleaned up.
119: */
120: public static void returnUserTransaction(
121: UserTransaction userTransaction) {
122: if ((userTransaction != null)
123: && (userTransaction instanceof UserTransactionWithContext)) {
124: UserTransactionWithContext userTransactionWithContext = (UserTransactionWithContext) userTransaction;
125:
126: userTransactionWithContext.closeContext();
127: }
128: }
129:
130: /**
131: * This class wraps a UserTransaction with the InitialContext that was used
132: * to look it up, so that when the UserTransaction is returned to the
133: * UserTransactionHelper the InitialContext can be closed.
134: */
135: private static class UserTransactionWithContext implements
136: UserTransaction {
137: InitialContext context;
138: UserTransaction userTransaction;
139:
140: public UserTransactionWithContext() throws SchedulerException {
141: try {
142: context = new InitialContext();
143: } catch (Throwable t) {
144: throw new SchedulerException(
145: "UserTransactionHelper failed to create InitialContext to lookup/create UserTransaction.",
146: t);
147: }
148:
149: try {
150: userTransaction = (UserTransaction) context
151: .lookup(userTxURL);
152: } catch (Throwable t) {
153: closeContext();
154: throw new SchedulerException(
155: "UserTransactionHelper could not lookup/create UserTransaction.",
156: t);
157: }
158:
159: if (userTransaction == null) {
160: closeContext();
161: throw new SchedulerException(
162: "UserTransactionHelper could not lookup/create UserTransaction from the InitialContext.");
163: }
164: }
165:
166: /**
167: * Close the InitialContext that was used to lookup/create the
168: * underlying UserTransaction.
169: */
170: public void closeContext() {
171: try {
172: if (context != null) {
173: context.close();
174: }
175: } catch (Throwable t) {
176: getLog()
177: .warn(
178: "Failed to close InitialContext used to get a UserTransaction.",
179: t);
180: }
181: context = null;
182: }
183:
184: /**
185: * When we are being garbage collected, make sure we were properly
186: * returned to the UserTransactionHelper.
187: */
188: protected void finalize() throws Throwable {
189: try {
190: if (context != null) {
191: getLog()
192: .warn(
193: "UserTransaction was never returned to the UserTransactionHelper.");
194: closeContext();
195: }
196: } finally {
197: super .finalize();
198: }
199: }
200:
201: private static Log getLog() {
202: return LogFactory.getLog(UserTransactionWithContext.class);
203: }
204:
205: // Wrapper methods that just delegate to the underlying UserTransaction
206:
207: public void begin() throws NotSupportedException,
208: SystemException {
209: userTransaction.begin();
210: }
211:
212: public void commit() throws RollbackException,
213: HeuristicMixedException, HeuristicRollbackException,
214: SecurityException, IllegalStateException,
215: SystemException {
216: userTransaction.commit();
217: }
218:
219: public void rollback() throws IllegalStateException,
220: SecurityException, SystemException {
221: userTransaction.rollback();
222: }
223:
224: public void setRollbackOnly() throws IllegalStateException,
225: SystemException {
226: userTransaction.setRollbackOnly();
227: }
228:
229: public int getStatus() throws SystemException {
230: return userTransaction.getStatus();
231: }
232:
233: public void setTransactionTimeout(int seconds)
234: throws SystemException {
235: userTransaction.setTransactionTimeout(seconds);
236: }
237: }
238: }
|