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