001: /*
002: * Copyright 2004-2006 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: package org.quartz.plugins;
017:
018: import javax.transaction.Status;
019: import javax.transaction.UserTransaction;
020:
021: import org.apache.commons.logging.Log;
022: import org.apache.commons.logging.LogFactory;
023: import org.quartz.Scheduler;
024: import org.quartz.SchedulerException;
025: import org.quartz.ee.jta.UserTransactionHelper;
026: import org.quartz.spi.SchedulerPlugin;
027:
028: /**
029: * Base class for plugins that wish to support having their start and
030: * shutdown methods run within a <code>UserTransaction</code>. This is
031: * often necessary if using the JobStoreCMT and the plugin interacts with
032: * jobs/triggers.
033: *
034: * <p>
035: * The subclass should implement start(UserTransaction) and
036: * shutdown(UserTransaction). The <code>UserTransaction</code> will be
037: * non-null if property <em>wrapInUserTransaction</em> is set to true.
038: * </p>
039: * <p>
040: * For convenience, this base class also provides an initialize() implementation
041: * which saves the scheduler and plugin name, as well as getLog() for logging.
042: * </p>
043: */
044: public abstract class SchedulerPluginWithUserTransactionSupport
045: implements SchedulerPlugin {
046:
047: private String name;
048: private Scheduler scheduler;
049: private final Log log = LogFactory.getLog(getClass());
050:
051: // Properties
052:
053: private boolean wrapInUserTransaction = false;
054:
055: /**
056: * <p>
057: * Called when the associated <code>Scheduler</code> is started, in order
058: * to let the plug-in know it can now make calls into the scheduler if it
059: * needs to.
060: * </p>
061: *
062: * <p>
063: * If UserTransaction is not null, the plugin can call setRollbackOnly()
064: * on it to signal that the wrapped transaction should rollback.
065: * </p>
066: *
067: * @param userTransaction The UserTranaction object used to provide a
068: * transaction around the start() operation. It will be null if
069: * <em>wrapInUserTransaction</em> is false or if the transaction failed
070: * to be started.
071: */
072: protected void start(UserTransaction userTransaction) {
073: }
074:
075: /**
076: * <p>
077: * Called in order to inform the <code>SchedulerPlugin</code> that it
078: * should free up all of it's resources because the scheduler is shutting
079: * down.
080: * </p>
081: *
082: * <p>
083: * If UserTransaction is not null, the plugin can call setRollbackOnly()
084: * on it to signal that the wrapped transaction should rollback.
085: * </p>
086: *
087: * @param userTransaction The UserTranaction object used to provide a
088: * transaction around the shutdown() operation. It will be null if
089: * <em>wrapInUserTransaction</em> is false or if the transaction failed
090: * to be started.
091: */
092: protected void shutdown(UserTransaction userTransaction) {
093: }
094:
095: /**
096: * Get the commons Log for this class.
097: */
098: protected Log getLog() {
099: return log;
100: }
101:
102: /**
103: * Get the name of this plugin. Set as part of initialize().
104: */
105: protected String getName() {
106: return name;
107: }
108:
109: /**
110: * Get this plugin's <code>Scheduler</code>. Set as part of initialize().
111: */
112: protected Scheduler getScheduler() {
113: return scheduler;
114: }
115:
116: public void initialize(String name, Scheduler scheduler)
117: throws SchedulerException {
118: this .name = name;
119: this .scheduler = scheduler;
120: }
121:
122: /**
123: * Wrap the start() and shutdown() methods in a UserTransaction. This is necessary
124: * for some plugins if using the JobStoreCMT.
125: */
126: public boolean getWrapInUserTransaction() {
127: return wrapInUserTransaction;
128: }
129:
130: /**
131: * Wrap the start() and shutdown() methods in a UserTransaction. This is necessary
132: * for some plugins if using the JobStoreCMT.
133: */
134: public void setWrapInUserTransaction(boolean wrapInUserTransaction) {
135: this .wrapInUserTransaction = wrapInUserTransaction;
136: }
137:
138: /**
139: * Based on the value of <em>wrapInUserTransaction</em>, wraps the
140: * call to start(UserTransaction) in a UserTransaction.
141: */
142: public void start() {
143: UserTransaction userTransaction = startUserTransaction();
144: try {
145: start(userTransaction);
146: } finally {
147: resolveUserTransaction(userTransaction);
148: }
149: }
150:
151: /**
152: * Based on the value of <em>wrapInUserTransaction</em>, wraps the
153: * call to shutdown(UserTransaction) in a UserTransaction.
154: */
155: public void shutdown() {
156: UserTransaction userTransaction = startUserTransaction();
157: try {
158: shutdown(userTransaction);
159: } finally {
160: resolveUserTransaction(userTransaction);
161: }
162: }
163:
164: /**
165: * If <em>wrapInUserTransaction</em> is true, starts a new UserTransaction
166: * and returns it. Otherwise, or if establishing the transaction fail, it
167: * will return null.
168: */
169: private UserTransaction startUserTransaction() {
170: if (wrapInUserTransaction == false) {
171: return null;
172: }
173:
174: UserTransaction userTransaction = null;
175: try {
176: userTransaction = UserTransactionHelper
177: .lookupUserTransaction();
178: userTransaction.begin();
179: } catch (Throwable t) {
180: UserTransactionHelper
181: .returnUserTransaction(userTransaction);
182: userTransaction = null;
183: getLog().error(
184: "Failed to start UserTransaction for plugin: "
185: + getName(), t);
186: }
187:
188: return userTransaction;
189: }
190:
191: /**
192: * If the given UserTransaction is not null, it is committed/rolledback,
193: * and then returned to the UserTransactionHelper.
194: */
195: private void resolveUserTransaction(UserTransaction userTransaction) {
196: if (userTransaction != null) {
197: try {
198: if (userTransaction.getStatus() == Status.STATUS_MARKED_ROLLBACK) {
199: userTransaction.rollback();
200: } else {
201: userTransaction.commit();
202: }
203: } catch (Throwable t) {
204: getLog().error(
205: "Failed to resolve UserTransaction for plugin: "
206: + getName(), t);
207: } finally {
208: UserTransactionHelper
209: .returnUserTransaction(userTransaction);
210: }
211: }
212: }
213: }
|