KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > jca > work > SimpleTaskWorkManager


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.jca.work;
18
19 import javax.resource.spi.work.ExecutionContext JavaDoc;
20 import javax.resource.spi.work.Work JavaDoc;
21 import javax.resource.spi.work.WorkAdapter JavaDoc;
22 import javax.resource.spi.work.WorkCompletedException JavaDoc;
23 import javax.resource.spi.work.WorkEvent JavaDoc;
24 import javax.resource.spi.work.WorkException JavaDoc;
25 import javax.resource.spi.work.WorkListener JavaDoc;
26 import javax.resource.spi.work.WorkManager JavaDoc;
27 import javax.resource.spi.work.WorkRejectedException JavaDoc;
28
29 import org.springframework.core.task.AsyncTaskExecutor;
30 import org.springframework.core.task.SimpleAsyncTaskExecutor;
31 import org.springframework.core.task.SyncTaskExecutor;
32 import org.springframework.core.task.TaskExecutor;
33 import org.springframework.core.task.TaskRejectedException;
34 import org.springframework.core.task.TaskTimeoutException;
35 import org.springframework.util.Assert;
36
37 /**
38  * Simple JCA 1.5 {@link javax.resource.spi.work.WorkManager} implementation that
39  * delegates to a Spring {@link org.springframework.core.task.TaskExecutor}.
40  * Provides simple task execution including start timeouts, but without support
41  * for a JCA ExecutionContext (i.e. without support for imported transactions).
42  *
43  * <p>Uses a {@link org.springframework.core.task.SyncTaskExecutor} for {@link #doWork}
44  * calls and a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}
45  * for {@link #startWork} and {@link #scheduleWork} calls, by default.
46  * These default task executors can be overridden through configuration.
47  *
48  * <p><b>NOTE: This WorkManager does not provide thread pooling by default!</b>
49  * Specify a {@link org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor}
50  * (or any other thread-pooling TaskExecutor) as "asyncTaskExecutor" in order to
51  * achieve actual thread pooling.
52  *
53  * <p>This WorkManager automatically detects a specified
54  * {@link org.springframework.core.task.AsyncTaskExecutor} implementation
55  * and uses its extended timeout functionality where appropriate.
56  * JCA WorkListeners are fully supported in any case.
57  *
58  * @author Juergen Hoeller
59  * @since 2.0.3
60  * @see #setSyncTaskExecutor
61  * @see #setAsyncTaskExecutor
62  */

63 public class SimpleTaskWorkManager implements WorkManager JavaDoc {
64
65     private TaskExecutor syncTaskExecutor = new SyncTaskExecutor();
66
67     private TaskExecutor asyncTaskExecutor = new SimpleAsyncTaskExecutor();
68
69
70     /**
71      * Specify the TaskExecutor to use for <i>synchronous</i> work execution
72      * (i.e. {@link #doWork} calls).
73      * <p>Default is a {@link org.springframework.core.task.SyncTaskExecutor}.
74      */

75     public void setSyncTaskExecutor(TaskExecutor syncTaskExecutor) {
76         this.syncTaskExecutor = syncTaskExecutor;
77     }
78
79     /**
80      * Specify the TaskExecutor to use for <i>asynchronous</i> work execution
81      * (i.e. {@link #startWork} and {@link #scheduleWork} calls).
82      * <p>This will typically (but not necessarily) be an
83      * {@link org.springframework.core.task.AsyncTaskExecutor} implementation.
84      * Default is a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}.
85      */

86     public void setAsyncTaskExecutor(TaskExecutor asyncTaskExecutor) {
87         this.asyncTaskExecutor = asyncTaskExecutor;
88     }
89
90
91     public void doWork(Work JavaDoc work) throws WorkException JavaDoc {
92         doWork(work, WorkManager.INDEFINITE, null, null);
93     }
94
95     public void doWork(Work JavaDoc work, long startTimeout, ExecutionContext JavaDoc executionContext, WorkListener JavaDoc workListener)
96             throws WorkException JavaDoc {
97
98         Assert.state(this.syncTaskExecutor != null, "No 'syncTaskExecutor' set");
99         executeWork(this.syncTaskExecutor, work, startTimeout, false, executionContext, workListener);
100     }
101
102     public long startWork(Work JavaDoc work) throws WorkException JavaDoc {
103         return startWork(work, WorkManager.INDEFINITE, null, null);
104     }
105
106     public long startWork(Work JavaDoc work, long startTimeout, ExecutionContext JavaDoc executionContext, WorkListener JavaDoc workListener)
107             throws WorkException JavaDoc {
108
109         Assert.state(this.asyncTaskExecutor != null, "No 'asyncTaskExecutor' set");
110         return executeWork(this.asyncTaskExecutor, work, startTimeout, true, executionContext, workListener);
111     }
112
113     public void scheduleWork(Work JavaDoc work) throws WorkException JavaDoc {
114         scheduleWork(work, WorkManager.INDEFINITE, null, null);
115     }
116
117     public void scheduleWork(Work JavaDoc work, long startTimeout, ExecutionContext JavaDoc executionContext, WorkListener JavaDoc workListener)
118             throws WorkException JavaDoc {
119
120         Assert.state(this.asyncTaskExecutor != null, "No 'asyncTaskExecutor' set");
121         executeWork(this.asyncTaskExecutor, work, startTimeout, false, executionContext, workListener);
122     }
123
124
125     /**
126      * Execute the given Work on the specified TaskExecutor.
127      * @param taskExecutor the TaskExecutor to use
128      * @param work the Work to execute
129      * @param startTimeout the time duration within which the Work is supposed to start
130      * @param blockUntilStarted whether to block until the Work has started
131      * @param executionContext the JCA ExecutionContext for the given Work
132      * @param workListener the WorkListener to clal for the given Work
133      * @return the time elapsed from Work acceptance until start of execution
134      * (or -1 if not applicable or not known)
135      * @throws WorkException if the TaskExecutor did not accept the Work
136      */

137     protected long executeWork(TaskExecutor taskExecutor, Work JavaDoc work, long startTimeout,
138             boolean blockUntilStarted, ExecutionContext JavaDoc executionContext, WorkListener JavaDoc workListener)
139             throws WorkException JavaDoc {
140
141         if (executionContext != null && executionContext.getXid() != null) {
142             throw new WorkException JavaDoc("SimpleTaskWorkManager does not supported imported XIDs: " + executionContext.getXid());
143         }
144         WorkListener JavaDoc workListenerToUse = workListener;
145         if (workListenerToUse == null) {
146             workListenerToUse = new WorkAdapter JavaDoc();
147         }
148
149         boolean isAsync = (taskExecutor instanceof AsyncTaskExecutor);
150         DelegatingWorkAdapter workHandle = new DelegatingWorkAdapter(work, workListenerToUse, !isAsync);
151         try {
152             if (isAsync) {
153                 ((AsyncTaskExecutor) taskExecutor).execute(workHandle, startTimeout);
154             }
155             else {
156                 taskExecutor.execute(workHandle);
157             }
158         }
159         catch (TaskTimeoutException ex) {
160             WorkException JavaDoc wex = new WorkRejectedException JavaDoc("TaskExecutor rejected Work because of timeout: " + work, ex);
161             wex.setErrorCode(WorkException.START_TIMED_OUT);
162             workListenerToUse.workRejected(new WorkEvent JavaDoc(this, WorkEvent.WORK_REJECTED, work, wex));
163             throw wex;
164         }
165         catch (TaskRejectedException ex) {
166             WorkException JavaDoc wex = new WorkRejectedException JavaDoc("TaskExecutor rejected Work: " + work, ex);
167             wex.setErrorCode(WorkException.INTERNAL);
168             workListenerToUse.workRejected(new WorkEvent JavaDoc(this, WorkEvent.WORK_REJECTED, work, wex));
169             throw wex;
170         }
171         catch (Throwable JavaDoc ex) {
172             WorkException JavaDoc wex = new WorkException JavaDoc("TaskExecutor failed to execute Work: " + work, ex);
173             wex.setErrorCode(WorkException.INTERNAL);
174             throw wex;
175         }
176         if (isAsync) {
177             workListenerToUse.workAccepted(new WorkEvent JavaDoc(this, WorkEvent.WORK_ACCEPTED, work, null));
178         }
179
180         if (blockUntilStarted) {
181             long acceptanceTime = System.currentTimeMillis();
182             synchronized (workHandle.monitor) {
183                 try {
184                     while (!workHandle.started) {
185                         workHandle.monitor.wait();
186                     }
187                 }
188                 catch (InterruptedException JavaDoc ex) {
189                     Thread.currentThread().interrupt();
190                 }
191             }
192             return (System.currentTimeMillis() - acceptanceTime);
193         }
194         else {
195             return WorkManager.UNKNOWN;
196         }
197     }
198
199
200     /**
201      * Work adapter that supports start timeouts and WorkListener callbacks
202      * for a given Work that it delegates to.
203      */

204     private static class DelegatingWorkAdapter implements Work JavaDoc {
205
206         private final Work JavaDoc work;
207
208         private final WorkListener JavaDoc workListener;
209
210         private final boolean acceptOnExecution;
211
212         public final Object JavaDoc monitor = new Object JavaDoc();
213
214         public boolean started = false;
215
216         public DelegatingWorkAdapter(Work JavaDoc work, WorkListener JavaDoc workListener, boolean acceptOnExecution) {
217             this.work = work;
218             this.workListener = workListener;
219             this.acceptOnExecution = acceptOnExecution;
220         }
221
222         public void run() {
223             if (this.acceptOnExecution) {
224                 this.workListener.workAccepted(new WorkEvent JavaDoc(this, WorkEvent.WORK_ACCEPTED, work, null));
225             }
226             synchronized (this.monitor) {
227                 this.started = true;
228                 this.monitor.notify();
229             }
230             this.workListener.workStarted(new WorkEvent JavaDoc(this, WorkEvent.WORK_STARTED, this.work, null));
231             try {
232                 this.work.run();
233             }
234             catch (RuntimeException JavaDoc ex) {
235                 this.workListener.workCompleted(
236                         new WorkEvent JavaDoc(this, WorkEvent.WORK_COMPLETED, this.work, new WorkCompletedException JavaDoc(ex)));
237                 throw ex;
238             }
239             catch (Error JavaDoc err) {
240                 this.workListener.workCompleted(
241                         new WorkEvent JavaDoc(this, WorkEvent.WORK_COMPLETED, this.work, new WorkCompletedException JavaDoc(err)));
242                 throw err;
243             }
244             this.workListener.workCompleted(new WorkEvent JavaDoc(this, WorkEvent.WORK_COMPLETED, this.work, null));
245         }
246
247         public void release() {
248             this.work.release();
249         }
250     }
251
252 }
253
Popular Tags