View Javadoc

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