View Javadoc

1   /*
2    * $Id: MuleWorkManager.java 11517 2008-03-31 21:34:19Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  /**
12   *
13   * Copyright 2004 The Apache Software Foundation
14   *
15   *  Licensed under the Apache License, Version 2.0 (the "License");
16   *  you may not use this file except in compliance with the License.
17   *  You may obtain a copy of the License at
18   *
19   *     http://www.apache.org/licenses/LICENSE-2.0
20   *
21   *  Unless required by applicable law or agreed to in writing, software
22   *  distributed under the License is distributed on an "AS IS" BASIS,
23   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24   *  See the License for the specific language governing permissions and
25   *  limitations under the License.
26   */
27  
28  package org.mule.work;
29  
30  import org.mule.api.MuleException;
31  import org.mule.api.config.ThreadingProfile;
32  import org.mule.api.context.WorkManager;
33  import org.mule.api.work.WorkExecutor;
34  
35  import java.text.MessageFormat;
36  import java.util.List;
37  
38  import javax.resource.spi.XATerminator;
39  import javax.resource.spi.work.ExecutionContext;
40  import javax.resource.spi.work.Work;
41  import javax.resource.spi.work.WorkCompletedException;
42  import javax.resource.spi.work.WorkException;
43  import javax.resource.spi.work.WorkListener;
44  
45  import edu.emory.mathcs.backport.java.util.concurrent.Executor;
46  import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService;
47  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
48  
49  import org.apache.commons.logging.Log;
50  import org.apache.commons.logging.LogFactory;
51  
52  /**
53   * <code>MuleWorkManager</code> is a JCA Work manager implementation used to manage
54   * thread allocation for Mule components and connectors. This code has been adapted
55   * from the Geronimo implementation.
56   */
57  public class MuleWorkManager implements WorkManager
58  {
59      /**
60       * logger used by this class
61       */
62      protected static final Log logger = LogFactory.getLog(MuleWorkManager.class);
63  
64      /**
65       * Graceful shutdown delay
66       */
67      private static final long SHUTDOWN_TIMEOUT = 5000L;
68  
69      /**
70       * The ThreadingProfile used for creation of the underlying ExecutorService
71       */
72      private final ThreadingProfile threadingProfile;
73  
74      /**
75       * The actual pool of threads used by this MuleWorkManager to process the Work
76       * instances submitted via the (do,start,schedule)Work methods.
77       */
78      private volatile ExecutorService workExecutorService;
79      private final String name;
80  
81      /**
82       * Various policies used for work execution
83       */
84      private final WorkExecutor scheduleWorkExecutor = new ScheduleWorkExecutor();
85      private final WorkExecutor startWorkExecutor = new StartWorkExecutor();
86      private final WorkExecutor syncWorkExecutor = new SyncWorkExecutor();
87  
88      public MuleWorkManager(ThreadingProfile profile, String name)
89      {
90          super();
91  
92          if (name == null)
93          {
94              name = "WorkManager#" + hashCode();
95          }
96  
97          this.threadingProfile = profile;
98          this.name = name;
99      }
100 
101     public synchronized void start() throws MuleException
102     {
103         if (workExecutorService == null)
104         {
105             workExecutorService = threadingProfile.createPool(name);
106         }
107     }
108 
109     public synchronized void dispose()
110     {
111         if (workExecutorService != null)
112         {
113             try
114             {
115                 // Cancel currently executing tasks
116                 List outstanding = workExecutorService.shutdownNow();
117 
118                 // Wait a while for existing tasks to terminate
119                 if (!workExecutorService.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS))
120                 {
121                     if (logger.isWarnEnabled())
122                     {
123                         logger.warn(MessageFormat.format(
124                                 "Pool {0} did not terminate in time; {1} work items were cancelled.",
125                                 new Object[] {name, outstanding.isEmpty() ? "No" : Integer.toString(outstanding.size())}));
126                     }
127                 }
128             }
129             catch (InterruptedException ie)
130             {
131                 // (Re-)Cancel if current thread also interrupted
132                 workExecutorService.shutdownNow();
133                 // Preserve interrupt status
134                 Thread.currentThread().interrupt();
135             }
136             finally
137             {
138                 workExecutorService = null;
139             }
140         }
141     }
142 
143 
144     // TODO
145     public XATerminator getXATerminator()
146     {
147         return null;
148     }
149 
150     /*
151      * (non-Javadoc)
152      *
153      * @see javax.resource.spi.work.MuleWorkManager#doWork(javax.resource.spi.work.Work)
154      */
155     public void doWork(Work work) throws WorkException
156     {
157         executeWork(new WorkerContext(work), syncWorkExecutor);
158     }
159 
160     /*
161      * (non-Javadoc)
162      *
163      * @see javax.resource.spi.work.MuleWorkManager#doWork(javax.resource.spi.work.Work,
164      *      long, javax.resource.spi.work.ExecutionContext,
165      *      javax.resource.spi.work.WorkListener)
166      */
167     public void doWork(Work work, long startTimeout, ExecutionContext execContext, WorkListener workListener)
168         throws WorkException
169     {
170         WorkerContext workWrapper = new WorkerContext(work, startTimeout, execContext, workListener);
171         workWrapper.setThreadPriority(Thread.currentThread().getPriority());
172         executeWork(workWrapper, syncWorkExecutor);
173     }
174 
175     /*
176      * (non-Javadoc)
177      *
178      * @see javax.resource.spi.work.MuleWorkManager#startWork(javax.resource.spi.work.Work)
179      */
180     public long startWork(Work work) throws WorkException
181     {
182         WorkerContext workWrapper = new WorkerContext(work);
183         workWrapper.setThreadPriority(Thread.currentThread().getPriority());
184         executeWork(workWrapper, startWorkExecutor);
185         return System.currentTimeMillis() - workWrapper.getAcceptedTime();
186     }
187 
188     /*
189      * (non-Javadoc)
190      *
191      * @see javax.resource.spi.work.MuleWorkManager#startWork(javax.resource.spi.work.Work,
192      *      long, javax.resource.spi.work.ExecutionContext,
193      *      javax.resource.spi.work.WorkListener)
194      */
195     public long startWork(Work work,
196                           long startTimeout,
197                           ExecutionContext execContext,
198                           WorkListener workListener) throws WorkException
199     {
200         WorkerContext workWrapper = new WorkerContext(work, startTimeout, execContext, workListener);
201         workWrapper.setThreadPriority(Thread.currentThread().getPriority());
202         executeWork(workWrapper, startWorkExecutor);
203         return System.currentTimeMillis() - workWrapper.getAcceptedTime();
204     }
205 
206     /*
207      * (non-Javadoc)
208      *
209      * @see javax.resource.spi.work.MuleWorkManager#scheduleWork(javax.resource.spi.work.Work)
210      */
211     public void scheduleWork(Work work) throws WorkException
212     {
213         WorkerContext workWrapper = new WorkerContext(work);
214         workWrapper.setThreadPriority(Thread.currentThread().getPriority());
215         executeWork(workWrapper, scheduleWorkExecutor);
216     }
217 
218     /*
219      * (non-Javadoc)
220      *
221      * @see javax.resource.spi.work.MuleWorkManager#scheduleWork(javax.resource.spi.work.Work,
222      *      long, javax.resource.spi.work.ExecutionContext,
223      *      javax.resource.spi.work.WorkListener)
224      */
225     public void scheduleWork(Work work,
226                              long startTimeout,
227                              ExecutionContext execContext,
228                              WorkListener workListener) throws WorkException
229     {
230         WorkerContext workWrapper = new WorkerContext(work, startTimeout, execContext, workListener);
231         workWrapper.setThreadPriority(Thread.currentThread().getPriority());
232         executeWork(workWrapper, scheduleWorkExecutor);
233     }
234 
235     /**
236      * @see Executor#execute(Runnable)
237      */
238     public void execute(Runnable work)
239     {
240         if (workExecutorService == null)
241         {
242             throw new IllegalStateException("This MuleWorkManager '" + name + "' was never started");
243         }
244         else if (workExecutorService.isShutdown())
245         {
246             throw new IllegalStateException("This MuleWorkManager '" + name + "' is stopped");
247         }
248 
249         workExecutorService.execute(work);
250     }
251 
252     /**
253      * Execute the specified Work.
254      *
255      * @param work Work to be executed.
256      * @exception WorkException Indicates that the Work execution has been
257      *                unsuccessful.
258      */
259     private void executeWork(WorkerContext work, WorkExecutor workExecutor) throws WorkException
260     {
261         if (workExecutorService == null || workExecutorService.isShutdown())
262         {
263             throw new IllegalStateException("This MuleWorkManager '" + name + "' is stopped");
264         }
265 
266         try
267         {
268             work.workAccepted(this);
269             workExecutor.doExecute(work, workExecutorService);
270             WorkException exception = work.getWorkException();
271             if (null != exception)
272             {
273                 throw exception;
274             }
275         }
276         catch (InterruptedException e)
277         {
278             WorkCompletedException wcj = new WorkCompletedException("The execution has been interrupted for WorkManager: " + name, e);
279             wcj.setErrorCode(WorkException.INTERNAL);
280             throw wcj;
281         }
282     }
283 
284 }