View Javadoc

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