View Javadoc

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