View Javadoc

1   /*
2    * $Id: FutureMessageResult.java 20297 2010-11-22 18:49:18Z aperepel $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.api;
12  
13  import org.mule.DefaultMuleMessage;
14  import org.mule.util.concurrent.DaemonThreadFactory;
15  
16  import java.util.List;
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 MuleMessage 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 List transformers;
63  
64      protected MuleContext muleContext;
65  
66      public FutureMessageResult(Callable callable, MuleContext muleContext)
67      {
68          super(callable);
69          this.executor = DefaultExecutor;
70          this.muleContext = muleContext;
71      }
72  
73      /**
74       * Set an ExecutorService to run this invocation.
75       * 
76       * @param e the executor to be used.
77       * @throws IllegalArgumentException when the executor is null or shutdown.
78       */
79      public void setExecutor(Executor e)
80      {
81          if (e == null)
82          {
83              throw new IllegalArgumentException("Executor must not be null.");
84          }
85  
86          synchronized (this)
87          {
88              this.executor = e;
89          }
90      }
91  
92      /**
93       * Set a post-invocation transformer.
94       * 
95       * @param t Transformers to be applied to the result of this invocation. May be
96       *            null.
97       */
98      public void setTransformers(List t)
99      {
100         synchronized (this)
101         {
102             this.transformers = t;
103         }
104     }
105 
106     public MuleMessage getMessage() throws InterruptedException, ExecutionException, MuleException
107     {
108         return this.getMessage(this.get());
109     }
110 
111     public MuleMessage getMessage(long timeout)
112         throws InterruptedException, ExecutionException, TimeoutException, MuleException
113     {
114         return this.getMessage(this.get(timeout, TimeUnit.MILLISECONDS));
115     }
116 
117     private MuleMessage getMessage(Object obj) throws MuleException
118     {
119         MuleMessage result = null;
120         if (obj != null)
121         {
122             if (obj instanceof MuleMessage)
123             {
124                 result = (MuleMessage)obj;
125             }
126             else
127             {
128                 result = new DefaultMuleMessage(obj, muleContext);
129             }
130 
131             synchronized (this)
132             {
133                 if (transformers != null)
134                 {
135                     result.applyTransformers(null, transformers, null);
136                 }
137             }
138 
139         }
140         return result;
141     }
142 
143     /**
144      * Start asynchronous execution of this task
145      */
146     public void execute()
147     {
148         synchronized (this)
149         {
150             executor.execute(this);
151         }
152     }
153 
154 }