View Javadoc

1   /*
2    * $Id: MuleWorkManager.java 7976 2007-08-21 14:26:13Z 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.impl.work;
29  
30  import org.mule.MuleManager;
31  import org.mule.config.ThreadingProfile;
32  import org.mule.umo.UMOException;
33  import org.mule.umo.manager.UMOWorkManager;
34  
35  import java.util.List;
36  
37  import javax.resource.spi.XATerminator;
38  import javax.resource.spi.work.ExecutionContext;
39  import javax.resource.spi.work.Work;
40  import javax.resource.spi.work.WorkCompletedException;
41  import javax.resource.spi.work.WorkException;
42  import javax.resource.spi.work.WorkListener;
43  
44  import edu.emory.mathcs.backport.java.util.concurrent.Executor;
45  import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService;
46  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
47  import org.apache.commons.logging.Log;
48  import org.apache.commons.logging.LogFactory;
49  
50  /**
51   * <code>MuleWorkManager</code> is a JCA Work manager implementation used to manage
52   * thread allocation for Mule components and connectors. This code has been adapted
53   * from the Geronimo implementation.
54   */
55  public class MuleWorkManager implements UMOWorkManager
56  {
57      /**
58       * logger used by this class
59       */
60      protected static final Log logger = LogFactory.getLog(MuleWorkManager.class);
61  
62      /**
63       * Graceful shutdown delay
64       */
65      private static final long SHUTDOWN_TIMEOUT = 5000L;
66  
67      /**
68       * The ThreadingProfile used for creation of the underlying ExecutorService
69       */
70      private final ThreadingProfile threadingProfile;
71  
72      /**
73       * The actual pool of threads used by this MuleWorkManager to process the Work
74       * instances submitted via the (do,start,schedule)Work methods.
75       */
76      private volatile ExecutorService workExecutorService;
77      private final String name;
78  
79      /**
80       * Various policies used for work execution
81       */
82      private final WorkExecutor scheduleWorkExecutor = new ScheduleWorkExecutor();
83      private final WorkExecutor startWorkExecutor = new StartWorkExecutor();
84      private final WorkExecutor syncWorkExecutor = new SyncWorkExecutor();
85  
86      public MuleWorkManager()
87      {
88          this(MuleManager.getConfiguration().getDefaultThreadingProfile(), null);
89      }
90  
91      public MuleWorkManager(ThreadingProfile profile, String name)
92      {
93          super();
94  
95          if (name == null)
96          {
97              name = "WorkManager#" + hashCode();
98          }
99  
100         this.threadingProfile = profile;
101         this.name = name;
102     }
103 
104     public synchronized void start() throws UMOException
105     {
106         if (workExecutorService == null)
107         {
108             workExecutorService = threadingProfile.createPool(name);
109         }
110     }
111 
112     public synchronized void stop() throws UMOException
113     {
114         if (workExecutorService != null)
115         {
116             try
117             {
118                 // Cancel currently executing tasks
119                 List outstanding = workExecutorService.shutdownNow();
120 
121                 // Wait a while for existing tasks to terminate
122                 if (!workExecutorService.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS))
123                 {
124                     logger.warn("Pool " + name + " did not terminate in time; " + outstanding.size()
125                                     + " work items were cancelled.");
126                 }
127             }
128             catch (InterruptedException ie)
129             {
130                 // (Re-)Cancel if current thread also interrupted
131                 workExecutorService.shutdownNow();
132                 // Preserve interrupt status
133                 Thread.currentThread().interrupt();
134             }
135             finally
136             {
137                 workExecutorService = null;
138             }
139         }
140     }
141 
142     public void dispose()
143     {
144         try
145         {
146             stop();
147         }
148         catch (UMOException e)
149         {
150             // TODO MULE-863: Is this serious?
151             logger.warn("Error while disposing Work Manager: " + e.getMessage(), e);
152         }
153     }
154 
155     // TODO
156     public XATerminator getXATerminator()
157     {
158         return null;
159     }
160 
161     /*
162      * (non-Javadoc)
163      * 
164      * @see javax.resource.spi.work.MuleWorkManager#doWork(javax.resource.spi.work.Work)
165      */
166     public void doWork(Work work) throws WorkException
167     {
168         executeWork(new WorkerContext(work), syncWorkExecutor);
169     }
170 
171     /*
172      * (non-Javadoc)
173      * 
174      * @see javax.resource.spi.work.MuleWorkManager#doWork(javax.resource.spi.work.Work,
175      *      long, javax.resource.spi.work.ExecutionContext,
176      *      javax.resource.spi.work.WorkListener)
177      */
178     public void doWork(Work work, long startTimeout, ExecutionContext execContext, WorkListener workListener)
179         throws WorkException
180     {
181         WorkerContext workWrapper = new WorkerContext(work, startTimeout, execContext, workListener);
182         workWrapper.setThreadPriority(Thread.currentThread().getPriority());
183         executeWork(workWrapper, syncWorkExecutor);
184     }
185 
186     /*
187      * (non-Javadoc)
188      * 
189      * @see javax.resource.spi.work.MuleWorkManager#startWork(javax.resource.spi.work.Work)
190      */
191     public long startWork(Work work) throws WorkException
192     {
193         WorkerContext workWrapper = new WorkerContext(work);
194         workWrapper.setThreadPriority(Thread.currentThread().getPriority());
195         executeWork(workWrapper, startWorkExecutor);
196         return System.currentTimeMillis() - workWrapper.getAcceptedTime();
197     }
198 
199     /*
200      * (non-Javadoc)
201      * 
202      * @see javax.resource.spi.work.MuleWorkManager#startWork(javax.resource.spi.work.Work,
203      *      long, javax.resource.spi.work.ExecutionContext,
204      *      javax.resource.spi.work.WorkListener)
205      */
206     public long startWork(Work work,
207                           long startTimeout,
208                           ExecutionContext execContext,
209                           WorkListener workListener) throws WorkException
210     {
211         WorkerContext workWrapper = new WorkerContext(work, startTimeout, execContext, workListener);
212         workWrapper.setThreadPriority(Thread.currentThread().getPriority());
213         executeWork(workWrapper, startWorkExecutor);
214         return System.currentTimeMillis() - workWrapper.getAcceptedTime();
215     }
216 
217     /*
218      * (non-Javadoc)
219      * 
220      * @see javax.resource.spi.work.MuleWorkManager#scheduleWork(javax.resource.spi.work.Work)
221      */
222     public void scheduleWork(Work work) throws WorkException
223     {
224         WorkerContext workWrapper = new WorkerContext(work);
225         workWrapper.setThreadPriority(Thread.currentThread().getPriority());
226         executeWork(workWrapper, scheduleWorkExecutor);
227     }
228 
229     /*
230      * (non-Javadoc)
231      * 
232      * @see javax.resource.spi.work.MuleWorkManager#scheduleWork(javax.resource.spi.work.Work,
233      *      long, javax.resource.spi.work.ExecutionContext,
234      *      javax.resource.spi.work.WorkListener)
235      */
236     public void scheduleWork(Work work,
237                              long startTimeout,
238                              ExecutionContext execContext,
239                              WorkListener workListener) throws WorkException
240     {
241         WorkerContext workWrapper = new WorkerContext(work, startTimeout, execContext, workListener);
242         workWrapper.setThreadPriority(Thread.currentThread().getPriority());
243         executeWork(workWrapper, scheduleWorkExecutor);
244     }
245 
246     /**
247      * @see Executor#execute(Runnable)
248      */
249     public void execute(Runnable work)
250     {
251         if (workExecutorService == null || workExecutorService.isShutdown())
252         {
253             throw new IllegalStateException("This MuleWorkManager is stopped");
254         }
255 
256         workExecutorService.execute(work);
257     }
258 
259     /**
260      * Execute the specified Work.
261      * 
262      * @param work Work to be executed.
263      * @exception WorkException Indicates that the Work execution has been
264      *                unsuccessful.
265      */
266     private void executeWork(WorkerContext work, WorkExecutor workExecutor) throws WorkException
267     {
268         if (workExecutorService == null || workExecutorService.isShutdown())
269         {
270             throw new IllegalStateException("This MuleWorkManager is stopped");
271         }
272 
273         try
274         {
275             work.workAccepted(this);
276             workExecutor.doExecute(work, workExecutorService);
277             WorkException exception = work.getWorkException();
278             if (null != exception)
279             {
280                 throw exception;
281             }
282         }
283         catch (InterruptedException e)
284         {
285             WorkCompletedException wcj = new WorkCompletedException("The execution has been interrupted.", e);
286             wcj.setErrorCode(WorkException.INTERNAL);
287             throw wcj;
288         }
289     }
290 
291 }