001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy 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,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.jca.work;
018:
019: import javax.resource.spi.BootstrapContext;
020: import javax.resource.spi.work.ExecutionContext;
021: import javax.resource.spi.work.Work;
022: import javax.resource.spi.work.WorkException;
023: import javax.resource.spi.work.WorkListener;
024: import javax.resource.spi.work.WorkManager;
025: import javax.resource.spi.work.WorkRejectedException;
026:
027: import org.springframework.core.task.AsyncTaskExecutor;
028: import org.springframework.core.task.TaskRejectedException;
029: import org.springframework.core.task.TaskTimeoutException;
030: import org.springframework.jca.context.BootstrapContextAware;
031: import org.springframework.scheduling.SchedulingException;
032: import org.springframework.scheduling.SchedulingTaskExecutor;
033: import org.springframework.util.Assert;
034:
035: /**
036: * {@link org.springframework.core.task.TaskExecutor} implementation
037: * that delegates to a JCA 1.5 WorkManager, implementing the
038: * {@link javax.resource.spi.work.WorkManager} interface.
039: *
040: * <p>This is mainly intended for use within a JCA ResourceAdapter implementation,
041: * but may also be used in a standalone environment, delegating to a locally
042: * embedded WorkManager implementation (such as Geronimo's).
043: *
044: * <p>Also implements the JCA 1.5 WorkManager interface itself, delegating all
045: * calls to the target WorkManager. Hence, a caller can choose whether it wants
046: * to talk to this executor through the Spring TaskExecutor interface or the
047: * JCA 1.5 WorkManager interface.
048: *
049: * @author Juergen Hoeller
050: * @since 2.0.3
051: * @see #setWorkManager
052: * @see javax.resource.spi.work.WorkManager#scheduleWork
053: */
054: public class WorkManagerTaskExecutor implements SchedulingTaskExecutor,
055: AsyncTaskExecutor, WorkManager, BootstrapContextAware {
056:
057: private WorkManager workManager = new SimpleTaskWorkManager();
058:
059: private boolean blockUntilStarted = false;
060:
061: private boolean blockUntilCompleted = false;
062:
063: private WorkListener workListener;
064:
065: /**
066: * Create a new WorkManagerTaskExecutor, expecting bean-style configuration.
067: * @see #setWorkManager
068: */
069: public WorkManagerTaskExecutor() {
070: }
071:
072: /**
073: * Create a new WorkManagerTaskExecutor for the given WorkManager.
074: * @param workManager the JCA WorkManager to delegate to
075: */
076: public WorkManagerTaskExecutor(WorkManager workManager) {
077: setWorkManager(workManager);
078: }
079:
080: /**
081: * Specify the JCA WorkManager to delegate to.
082: */
083: public void setWorkManager(WorkManager workManager) {
084: Assert.notNull(workManager, "WorkManager must not be null");
085: this .workManager = workManager;
086: }
087:
088: /**
089: * Specify the JCA BootstrapContext that contains the
090: * WorkManager to delegate to.
091: */
092: public void setBootstrapContext(BootstrapContext bootstrapContext) {
093: Assert.notNull(bootstrapContext,
094: "BootstrapContext must not be null");
095: this .workManager = bootstrapContext.getWorkManager();
096: }
097:
098: /**
099: * Set whether to let {@link #execute} block until the work
100: * has been actually started.
101: * <p>Uses the JCA <code>startWork</code> operation underneath,
102: * instead of the default <code>scheduleWork</code>.
103: * @see javax.resource.spi.work.WorkManager#startWork
104: * @see javax.resource.spi.work.WorkManager#scheduleWork
105: */
106: public void setBlockUntilStarted(boolean blockUntilStarted) {
107: this .blockUntilStarted = blockUntilStarted;
108: }
109:
110: /**
111: * Set whether to let {@link #execute} block until the work
112: * has been completed.
113: * <p>Uses the JCA <code>doWork</code> operation underneath,
114: * instead of the default <code>scheduleWork</code>.
115: * @see javax.resource.spi.work.WorkManager#doWork
116: * @see javax.resource.spi.work.WorkManager#scheduleWork
117: */
118: public void setBlockUntilCompleted(boolean blockUntilCompleted) {
119: this .blockUntilCompleted = blockUntilCompleted;
120: }
121:
122: /**
123: * Specify a JCA 1.5 WorkListener to apply, if any.
124: * <p>This shared WorkListener instance will be passed on to the
125: * WorkManager by all {@link #execute} calls on this TaskExecutor.
126: */
127: public void setWorkListener(WorkListener workListener) {
128: this .workListener = workListener;
129: }
130:
131: //-------------------------------------------------------------------------
132: // Implementation of the Spring SchedulingTaskExecutor interface
133: //-------------------------------------------------------------------------
134:
135: public void execute(Runnable task) {
136: execute(task, TIMEOUT_INDEFINITE);
137: }
138:
139: public void execute(Runnable task, long startTimeout) {
140: Assert.state(this .workManager != null,
141: "No WorkManager specified");
142: Work work = new DelegatingWork(task);
143: try {
144: if (this .blockUntilCompleted) {
145: if (startTimeout != TIMEOUT_INDEFINITE
146: || this .workListener != null) {
147: this .workManager.doWork(work, startTimeout, null,
148: this .workListener);
149: } else {
150: this .workManager.doWork(work);
151: }
152: } else if (this .blockUntilStarted) {
153: if (startTimeout != TIMEOUT_INDEFINITE
154: || this .workListener != null) {
155: this .workManager.startWork(work, startTimeout,
156: null, this .workListener);
157: } else {
158: this .workManager.startWork(work);
159: }
160: } else {
161: if (startTimeout != TIMEOUT_INDEFINITE
162: || this .workListener != null) {
163: this .workManager.scheduleWork(work, startTimeout,
164: null, this .workListener);
165: } else {
166: this .workManager.scheduleWork(work);
167: }
168: }
169: } catch (WorkRejectedException ex) {
170: if (WorkException.START_TIMED_OUT.equals(ex.getErrorCode())) {
171: throw new TaskTimeoutException(
172: "JCA WorkManager rejected task because of timeout: "
173: + task, ex);
174: } else {
175: throw new TaskRejectedException(
176: "JCA WorkManager rejected task: " + task, ex);
177: }
178: } catch (WorkException ex) {
179: throw new SchedulingException(
180: "Could not schedule task on JCA WorkManager", ex);
181: }
182: }
183:
184: /**
185: * This task executor prefers short-lived work units.
186: */
187: public boolean prefersShortLivedTasks() {
188: return true;
189: }
190:
191: //-------------------------------------------------------------------------
192: // Implementation of the JCA WorkManager interface
193: //-------------------------------------------------------------------------
194:
195: public void doWork(Work work) throws WorkException {
196: this .workManager.doWork(work);
197: }
198:
199: public void doWork(Work work, long delay,
200: ExecutionContext executionContext, WorkListener workListener)
201: throws WorkException {
202:
203: this .workManager.doWork(work, delay, executionContext,
204: workListener);
205: }
206:
207: public long startWork(Work work) throws WorkException {
208: return this .workManager.startWork(work);
209: }
210:
211: public long startWork(Work work, long delay,
212: ExecutionContext executionContext, WorkListener workListener)
213: throws WorkException {
214:
215: return this .workManager.startWork(work, delay,
216: executionContext, workListener);
217: }
218:
219: public void scheduleWork(Work work) throws WorkException {
220: this .workManager.scheduleWork(work);
221: }
222:
223: public void scheduleWork(Work work, long delay,
224: ExecutionContext executionContext, WorkListener workListener)
225: throws WorkException {
226:
227: this.workManager.scheduleWork(work, delay, executionContext,
228: workListener);
229: }
230:
231: }
|