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