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