View Javadoc

1   /*
2    * $Id: FutureMessageResult.java 7963 2007-08-21 08:53:15Z 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  package org.mule.umo;
12  
13  import org.mule.impl.MuleMessage;
14  import org.mule.umo.transformer.TransformerException;
15  import org.mule.umo.transformer.UMOTransformer;
16  import org.mule.util.concurrent.DaemonThreadFactory;
17  
18  import edu.emory.mathcs.backport.java.util.concurrent.Callable;
19  import edu.emory.mathcs.backport.java.util.concurrent.ExecutionException;
20  import edu.emory.mathcs.backport.java.util.concurrent.Executor;
21  import edu.emory.mathcs.backport.java.util.concurrent.Executors;
22  import edu.emory.mathcs.backport.java.util.concurrent.FutureTask;
23  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
24  import edu.emory.mathcs.backport.java.util.concurrent.TimeoutException;
25  
26  /**
27   * <code>FutureMessageResult</code> is an UMOMessage result of a remote invocation
28   * on a Mule Server. This object makes the result available to the client code once
29   * the request has been processed. This execution happens asynchronously.
30   */
31  // @ThreadSafe
32  public class FutureMessageResult extends FutureTask
33  {
34      /**
35       * This is a simple default Executor for FutureMessageResults. Instead of
36       * spawning a Thread for each invocation it uses a single daemon Thread with an
37       * unbounded queue, so "truly" concurrent operation of multiple Futures or
38       * otherwise customized execution behaviour requires calling the
39       * {@link #setExecutor(Executor)} method and passing in a custom {@link Executor}.
40       * This is strongly recommended in order to provide better control over
41       * concurrency, resource consumption and possible overruns.
42       * <p>
43       * Reasons for these defaults:
44       * <ul>
45       * <li> a daemon thread does not block the VM on shutdown; lifecycle control
46       * should be done elsewhere (e.g. the provider of the custom ExecutorService),
47       * otherwise this class would become too overloaded
48       * <li> a single thread provides for conservative & predictable yet async
49       * behaviour from a client's point of view
50       * <li> the unbounded queue is not optimal but probably harmless since e.g. a
51       * MuleClient would have to create a LOT of Futures for an OOM. Cancelled/timed
52       * out invocations are GC'ed so the problem is rather unlikely to occur.
53       * </ul>
54       */
55      private static final Executor DefaultExecutor = Executors.newSingleThreadExecutor(
56          new DaemonThreadFactory("MuleDefaultFutureMessageExecutor"));
57  
58      // @GuardedBy(this)
59      private Executor executor;
60  
61      // @GuardedBy(this)
62      private UMOTransformer transformer;
63  
64      public FutureMessageResult(Callable callable)
65      {
66          super(callable);
67          this.executor = DefaultExecutor;
68      }
69  
70      /**
71       * Set an ExecutorService to run this invocation.
72       * 
73       * @param e the executor to be used.
74       * @throws IllegalArgumentException when the executor is null or shutdown.
75       */
76      public void setExecutor(Executor e)
77      {
78          if (e == null)
79          {
80              throw new IllegalArgumentException("Executor must not be null.");
81          }
82  
83          synchronized (this)
84          {
85              this.executor = e;
86          }
87      }
88  
89      /**
90       * Set a post-invocation transformer.
91       * 
92       * @param t UMOTransformer to be applied to the result of this invocation. May be
93       *            null.
94       */
95      public void setTransformer(UMOTransformer t)
96      {
97          synchronized (this)
98          {
99              this.transformer = t;
100         }
101     }
102 
103     public UMOMessage getMessage() throws InterruptedException, ExecutionException, TransformerException
104     {
105         return this.getMessage(this.get());
106     }
107 
108     public UMOMessage getMessage(long timeout)
109         throws InterruptedException, ExecutionException, TimeoutException, TransformerException
110     {
111         return this.getMessage(this.get(timeout, TimeUnit.MILLISECONDS));
112     }
113 
114     private UMOMessage getMessage(Object obj) throws TransformerException
115     {
116         if (obj != null)
117         {
118             if (obj instanceof UMOMessage)
119             {
120                 return (UMOMessage)obj;
121             }
122 
123             synchronized (this)
124             {
125                 if (transformer != null)
126                 {
127                     obj = transformer.transform(obj);
128                 }
129             }
130 
131             return new MuleMessage(obj);
132         }
133         else
134         {
135             return null;
136         }
137     }
138 
139     /**
140      * Start asynchronous execution of this task
141      */
142     public void execute()
143     {
144         synchronized (this)
145         {
146             executor.execute(this);
147         }
148     }
149 
150 }