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