Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
FutureMessageResult |
|
| 1.7142857142857142;1.714 |
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 | 0 | 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 | 0 | super(callable); |
70 | 0 | this.executor = DefaultExecutor; |
71 | 0 | this.muleContext = muleContext; |
72 | 0 | } |
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 | 0 | if (e == null) |
83 | { | |
84 | 0 | throw new IllegalArgumentException("Executor must not be null."); |
85 | } | |
86 | ||
87 | 0 | synchronized (this) |
88 | { | |
89 | 0 | this.executor = e; |
90 | 0 | } |
91 | 0 | } |
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 | 0 | synchronized (this) |
102 | { | |
103 | 0 | this.transformers = t; |
104 | 0 | } |
105 | 0 | } |
106 | ||
107 | public MuleMessage getMessage() throws InterruptedException, ExecutionException, MuleException | |
108 | { | |
109 | 0 | return this.getMessage(this.get()); |
110 | } | |
111 | ||
112 | public MuleMessage getMessage(long timeout) | |
113 | throws InterruptedException, ExecutionException, TimeoutException, MuleException | |
114 | { | |
115 | 0 | return this.getMessage(this.get(timeout, TimeUnit.MILLISECONDS)); |
116 | } | |
117 | ||
118 | private MuleMessage getMessage(Object obj) throws MuleException | |
119 | { | |
120 | 0 | MuleMessage result = null; |
121 | 0 | if (obj != null) |
122 | { | |
123 | 0 | if (obj instanceof MuleMessage) |
124 | { | |
125 | 0 | result = (MuleMessage)obj; |
126 | } | |
127 | else | |
128 | { | |
129 | 0 | result = new DefaultMuleMessage(obj, muleContext); |
130 | } | |
131 | ||
132 | 0 | synchronized (this) |
133 | { | |
134 | 0 | if (transformers != null) |
135 | { | |
136 | 0 | result.applyTransformers(null, transformers, null); |
137 | } | |
138 | 0 | } |
139 | ||
140 | } | |
141 | 0 | return result; |
142 | } | |
143 | ||
144 | /** | |
145 | * Start asynchronous execution of this task | |
146 | */ | |
147 | public void execute() | |
148 | { | |
149 | 0 | synchronized (this) |
150 | { | |
151 | 0 | executor.execute(this); |
152 | 0 | } |
153 | 0 | } |
154 | ||
155 | } |