Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
FutureMessageResult |
|
| 1.7142857142857142;1.714 |
1 | /* | |
2 | * $Id: FutureMessageResult.java 10489 2008-01-23 17:53:38Z dfeist $ | |
3 | * -------------------------------------------------------------------------------------- | |
4 | * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.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 | 2 | 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 | public FutureMessageResult(Callable callable) | |
66 | { | |
67 | 10 | super(callable); |
68 | 8 | this.executor = DefaultExecutor; |
69 | 8 | } |
70 | ||
71 | /** | |
72 | * Set an ExecutorService to run this invocation. | |
73 | * | |
74 | * @param e the executor to be used. | |
75 | * @throws IllegalArgumentException when the executor is null or shutdown. | |
76 | */ | |
77 | public void setExecutor(Executor e) | |
78 | { | |
79 | 4 | if (e == null) |
80 | { | |
81 | 2 | throw new IllegalArgumentException("Executor must not be null."); |
82 | } | |
83 | ||
84 | 2 | synchronized (this) |
85 | { | |
86 | 2 | this.executor = e; |
87 | 2 | } |
88 | 2 | } |
89 | ||
90 | /** | |
91 | * Set a post-invocation transformer. | |
92 | * | |
93 | * @param t UMOTransformers to be applied to the result of this invocation. May be | |
94 | * null. | |
95 | */ | |
96 | public void setTransformers(List t) | |
97 | { | |
98 | 0 | synchronized (this) |
99 | { | |
100 | 0 | this.transformers = t; |
101 | 0 | } |
102 | 0 | } |
103 | ||
104 | public MuleMessage getMessage() throws InterruptedException, ExecutionException, TransformerException | |
105 | { | |
106 | 2 | return this.getMessage(this.get()); |
107 | } | |
108 | ||
109 | public MuleMessage getMessage(long timeout) | |
110 | throws InterruptedException, ExecutionException, TimeoutException, TransformerException | |
111 | { | |
112 | 2 | return this.getMessage(this.get(timeout, TimeUnit.MILLISECONDS)); |
113 | } | |
114 | ||
115 | private MuleMessage getMessage(Object obj) throws TransformerException | |
116 | { | |
117 | 2 | MuleMessage result = null; |
118 | 2 | if (obj != null) |
119 | { | |
120 | 0 | if (obj instanceof MuleMessage) |
121 | { | |
122 | 0 | result = (MuleMessage)obj; |
123 | } | |
124 | else | |
125 | { | |
126 | 0 | result = new DefaultMuleMessage(obj); |
127 | } | |
128 | ||
129 | 0 | synchronized (this) |
130 | { | |
131 | 0 | if (transformers != null) |
132 | { | |
133 | 0 | result.applyTransformers(transformers); |
134 | } | |
135 | 0 | } |
136 | ||
137 | } | |
138 | 2 | return result; |
139 | } | |
140 | ||
141 | /** | |
142 | * Start asynchronous execution of this task | |
143 | */ | |
144 | public void execute() | |
145 | { | |
146 | 6 | synchronized (this) |
147 | { | |
148 | 6 | executor.execute(this); |
149 | 4 | } |
150 | 4 | } |
151 | ||
152 | } |